Skip to content

Commit

Permalink
feat(preset-mini): support new color notation using css variables for…
Browse files Browse the repository at this point in the history
… compatibility (#3437)

Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
  • Loading branch information
LeekJay and antfu committed Dec 27, 2023
1 parent 4ec30a4 commit e9dccbd
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 33 deletions.
65 changes: 38 additions & 27 deletions packages/preset-mini/src/_rules/border.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { CSSEntries, CSSObject, Rule, RuleContext } from '@unocss/core'
import type { CSSColorValue, CSSEntries, CSSObject, Rule, RuleContext } from '@unocss/core'
import { colorOpacityToString, colorToString } from '@unocss/rule-utils'
import type { Theme } from '../theme'
import { cornerMap, directionMap, globalKeywords, h, hasParseableColor, isCSSMathFn, parseColor } from '../utils'
Expand Down Expand Up @@ -49,6 +49,38 @@ export const borders: Rule[] = [
[/^(?:border|b)-([bi][se])-(?:style-)?(.+)$/, handlerBorderStyle],
]

function transformBorderColor(color: string | CSSColorValue, alpha: string | number | undefined, direction: string | undefined): CSSObject {
if (alpha != null) {
return {
[`border${direction}-color`]: colorToString(color, alpha),
}
}
if (direction === '') {
const object: CSSObject = {}
const opacityVar = `--un-border-opacity`
const result = colorToString(color, `var(${opacityVar})`)

if (result.includes(opacityVar))
object[opacityVar] = typeof color === 'string' ? 1 : colorOpacityToString(color)
object['border-color'] = result

return object
}
else {
const object: CSSObject = {}
const opacityVar = '--un-border-opacity'
const opacityDirectionVar = `--un-border${direction}-opacity`
const result = colorToString(color, `var(${opacityDirectionVar})`)
if (result.includes(opacityDirectionVar)) {
object[opacityVar] = typeof color === 'string' ? 1 : colorOpacityToString(color)
object[opacityDirectionVar] = `var(${opacityVar})`
}
object[`border${direction}-color`] = result

return object
}
}

function borderColorResolver(direction: string) {
return ([, body]: string[], theme: Theme): CSSObject | undefined => {
const data = parseColor(body, theme, 'borderColor')
Expand All @@ -58,32 +90,11 @@ function borderColorResolver(direction: string) {

const { alpha, color, cssColor } = data

if (cssColor) {
if (alpha != null) {
return {
[`border${direction}-color`]: colorToString(cssColor, alpha),
}
}
if (direction === '') {
return {
'--un-border-opacity': colorOpacityToString(cssColor),
'border-color': colorToString(cssColor, 'var(--un-border-opacity)'),
}
}
else {
return {
// Separate this return since if `direction` is an empty string, the first key will be overwritten by the second.
'--un-border-opacity': colorOpacityToString(cssColor),
[`--un-border${direction}-opacity`]: 'var(--un-border-opacity)',
[`border${direction}-color`]: colorToString(cssColor, `var(--un-border${direction}-opacity)`),
}
}
}
else if (color) {
return {
[`border${direction}-color`]: colorToString(color, alpha),
}
}
if (cssColor)
return transformBorderColor(cssColor, alpha, direction)

else if (color)
return transformBorderColor(color, alpha, direction)
}
}

Expand Down
18 changes: 15 additions & 3 deletions packages/preset-mini/src/_utils/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,12 +194,24 @@ export function colorResolver(property: string, varName: string, key?: ThemeColo
css[property] = colorToString(cssColor, alpha)
}
else {
css[`--un-${varName}-opacity`] = colorOpacityToString(cssColor)
css[property] = colorToString(cssColor, `var(--un-${varName}-opacity)`)
const opacityVar = `--un-${varName}-opacity`
const result = colorToString(cssColor, `var(${opacityVar})`)
if (result.includes(opacityVar))
css[opacityVar] = colorOpacityToString(cssColor)
css[property] = result
}
}
else if (color) {
css[property] = colorToString(color, alpha)
if (alpha != null) {
css[property] = colorToString(color, alpha)
}
else {
const opacityVar = `--un-${varName}-opacity`
const result = colorToString(color, `var(${opacityVar})`)
if (result.includes(opacityVar))
css[opacityVar] = 1
css[property] = result
}
}

if (shouldPass?.(css) !== false)
Expand Down
6 changes: 3 additions & 3 deletions test/assets/output/preset-uno-targets.css
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/* layer: default */
.border-custom-b{border-color:rgba(var(--custom), 1);}
.border-custom-b{--un-border-opacity:1;border-color:rgba(var(--custom), var(--un-border-opacity));}
.border-custom-b\/0{border-color:rgba(var(--custom), 0);}
.border-custom-b\/10{border-color:rgba(var(--custom), 0.1);}
.bg-custom-b{background-color:rgba(var(--custom), 1);}
.bg-custom-b{--un-bg-opacity:1;background-color:rgba(var(--custom), var(--un-bg-opacity));}
.bg-custom-c{--un-bg-opacity:1;background-color:rgba(var(--custom-c), var(--un-bg-opacity));}
.bg-custom-c\/10{background-color:rgba(var(--custom-c), 0.1);}
.bg-custom-d{background-color:hsl(var(--custom-d), 1);}
.bg-custom-d{--un-bg-opacity:1;background-color:hsl(var(--custom-d), var(--un-bg-opacity));}
.bg-custom-d\/20{background-color:hsl(var(--custom-d), 0.2);}
.bg-custom-e{--un-bg-opacity:1;background-color:hsl(var(--custom-e) / var(--un-bg-opacity));}
.bg-custom-e\/30{background-color:hsl(var(--custom-e) / 0.3);}
Expand Down
39 changes: 39 additions & 0 deletions test/preset-mini.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,4 +381,43 @@ describe('preset-mini', () => {
.shadow-blackA7{--un-shadow-opacity:0.169;--un-shadow-color:hsla(0, 0%, 0%, var(--un-shadow-opacity));}"
`)
})

it('support new color notation using css variables for compatibility', async () => {
const uno = createGenerator({
presets: [
presetMini(),
],
theme: {
colors: {
primary: 'var(--base-primary, oklch(var(--primary) / <alpha-value>))',
},
},
})

expect((await uno.generate('bg-primary bg-opacity-50 text-primary text-opacity-50', { preflights: false })).css)
.toMatchInlineSnapshot(`
"/* layer: default */
.bg-primary{--un-bg-opacity:1;background-color:var(--base-primary, oklch(var(--primary) / var(--un-bg-opacity)));}
.bg-opacity-50{--un-bg-opacity:0.5;}
.text-primary{--un-text-opacity:1;color:var(--base-primary, oklch(var(--primary) / var(--un-text-opacity)));}
.text-opacity-50{--un-text-opacity:0.5;}"
`)

expect((await uno.generate('bg-primary/50 ring-5 ring-primary ring-opacity-50', { preflights: false })).css)
.toMatchInlineSnapshot(`
"/* layer: default */
.bg-primary\\/50{background-color:var(--base-primary, oklch(var(--primary) / 0.5));}
.ring-5{--un-ring-width:5px;--un-ring-offset-shadow:var(--un-ring-inset) 0 0 0 var(--un-ring-offset-width) var(--un-ring-offset-color);--un-ring-shadow:var(--un-ring-inset) 0 0 0 calc(var(--un-ring-width) + var(--un-ring-offset-width)) var(--un-ring-color);box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);}
.ring-primary{--un-ring-opacity:1;--un-ring-color:var(--base-primary, oklch(var(--primary) / var(--un-ring-opacity)));}
.ring-opacity-50{--un-ring-opacity:0.5;}"
`)

expect((await uno.generate('border-5 border-primary border-opacity-50', { preflights: false })).css)
.toMatchInlineSnapshot(`
"/* layer: default */
.border-5{border-width:5px;}
.border-primary{--un-border-opacity:1;border-color:var(--base-primary, oklch(var(--primary) / var(--un-border-opacity)));}
.border-opacity-50{--un-border-opacity:0.5;}"
`)
})
})

0 comments on commit e9dccbd

Please sign in to comment.