8000 feat(preset-wind4): enhance color systax & support `color-interpolati… · unocss/unocss@ce4332c · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Commit ce4332c

Browse files
authored
feat(preset-wind4): enhance color systax & support color-interpolation-method parsed (#4729)
1 parent 7d61a0b commit ce4332c

File tree

7 files changed

+372
-162
lines changed

7 files changed

+372
-162
lines changed

packages-presets/preset-wind4/src/utils/utilities.ts

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { CSSEntries, CSSObject, CSSObjectInput, CSSValueInput, DynamicMatcher, RuleContext, StaticRule, VariantContext } from '@unocss/core'
22
import type { Theme } from '../theme'
33
import { symbols, toArray } from '@unocss/core'
4-
import { colorToString, getStringComponent, getStringComponents, parseCssColor } from '@unocss/rule-utils'
4+
import { colorToString, getStringComponent, getStringComponents, isInterpolatedMethod, parseCssColor } from '@unocss/rule-utils'
55
import { SpecialColorKey } from './constant'
66
import { h } from './handlers'
77
import { bracketTypeRe, numberWithUnitRE } from './handlers/regex'
@@ -127,17 +127,37 @@ export function splitShorthand(body: string, type: string) {
127127
* 'red-100' // From theme, plus scale
128128
* 'red-100/20' // From theme, plus scale/opacity
129129
* '[rgb(100 2 3)]/[var(--op)]' // Bracket with rgb color and bracket with opacity
130+
* '[rgb(100 2 3)]/[var(--op)]/[in_oklab]' // Bracket with rgb color, bracket with opacity and bracket with interpolation method
130131
*
131132
* @param body - Color string to be parsed.
132133
* @param theme - {@link Theme} object.
133134
* @return object if string is parseable.
134135
*/
135136
export function parseColor(body: string, theme: Theme) {
136-
const split = splitShorthand(body, 'color')
137+
let split
138+
const [front, ...rest] = getStringComponents(body, ['/', ':'], 3) ?? []
139+
140+
if (front != null) {
141+
const match = (front.match(bracketTypeRe) ?? [])[1]
142+
143+
if (match == null || match === 'color') {
144+
split = [front, ...rest]
145+
}
146+
}
147+
137148
if (!split)
138149
return
139150

140-
const [main, opacity] = split
151+
let opacity: string | undefined
152+
let [main, opacityOrModifier, modifier] = split as [string, string | undefined, string | undefined]
153+
154+
if (isInterpolatedMethod(opacityOrModifier) || isInterpolatedMethod(h.bracket(opacityOrModifier ?? ''))) {
155+
modifier = opacityOrModifier
156+
}
157+
else {
158+
opacity = opacityOrModifier
159+
}
160+
141161
const colors = main
142162
.replace(/([a-z])(\d)/g, '$1-$2')
143163
.split(/-/g)
@@ -167,6 +187,7 @@ export function parseColor(body: string, theme: Theme) {
167187

168188
return {
169189
opacity,
190+
modifier: (modifier && h.bracket.cssvar(modifier)) || modifier,
170191
name,
171192
no,
172193
color: color ?? SpecialColorKey[name as keyof typeof SpecialColorKey],
@@ -247,7 +268,7 @@ export function colorCSSGenerator(
247268
if (!data)
248269
return
249270

250-
const { color, keys, alpha } = data
271+
const { color, keys, alpha, modifier } = data
251272
const rawColorComment = ctx?.generator.config.envMode === 'dev' && color ? ` /* ${color} */` : ''
252273
const css: CSSObject = {}
253274

@@ -260,16 +281,24 @@ export function colorCSSGenerator(
260281
else {
261282
const alphaKey = `--un-${varName}-opacity`
262283
const value = keys ? generateThemeVariable('colors', keys) : color
263-
264-
if (!alpha) {
265-
css[alphaKey] = alpha
284+
let method = modifier ?? (keys ? 'in srgb' : 'in oklab')
285+
if (!method.startsWith('in ') && !method.startsWith('var(')) {
286+
method = `in ${method}`
266287
}
267-
css[property] = `color-mix(in oklch, ${value} ${alpha ?? `var(${alphaKey})`}, transparent)${rawColorComment}`
268288

289+
css[property] = `color-mix(${method}, ${value} ${alpha ?? `var(${alphaKey})`}, transparent)${rawColorComment}`
269290
result.push(defineProperty(alphaKey, { syntax: '<percentage>', initialValue: '100%' }))
270291

271292
if (keys) {
272293
themeTracking(`colors`, keys)
294+
if (!modifier) {
295+
result.push({
296+
[symbols.parent]: '@supports (color: color-mix(in lab, red, red))',
297+
[symbols.noMerge]: true,
298+
[symbols.shortcutsNoMerge]: true,
299+
[property]: `color-mix(in oklab, ${value} ${alpha ?? `var(${alphaKey})`}, transparent)${rawColorComment}`,
300+
})
301+
}
273302
}
274303
if (ctx?.theme) {
275304
detectThemeValue(color, ctx.theme)

packages-presets/rule-utils/src/colors.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,22 @@ export interface ParsedColorValue {
3636
alpha: string | number | undefined
3737
}
3838

39-
/* eslint-disable no-case-declarations */
4039
export const cssColorFunctions = ['hsl', 'hsla', 'hwb', 'lab', 'lch', 'oklab', 'oklch', 'rgb', 'rgba']
40+
export const rectangularColorSpace = ['srgb', 'srgb-linear', 'display-p3', 'a98-rgb', 'prophoto-rgb', 'rec2020', 'lab', 'oklab', 'xyz', 'xyz-d50', 'xyz-d65']
41+
export const polarColorSpace = ['hsl', 'hwb', 'lch', 'oklch']
42+
export const hueInterpolationMethods = ['shorter', 'longer', 'increasing', 'decreasing'] // hue interpolation methods for polar color spaces
4143
export const alphaPlaceholders = ['%alpha', '<alpha-value>']
4244
export const alphaPlaceholdersRE = new RegExp(alphaPlaceholders.map(v => escapeRegExp(v)).join('|'), 'g')
4345

46+
export function isInterpolatedMethod(type?: string): boolean {
47+
if (!type)
48+
return false
49+
50+
return rectangularColorSpace.some(space => type.includes(space))
51+
|| polarColorSpace.some(space => type.includes(space))
52+
|| hueInterpolationMethods.some(method => type.includes(method))
53+
}
54+
4455
export function hex2rgba(hex = ''): RGBAColorValue | undefined {
4556
const color = parseHexColor(hex)
4657
if (color != null) {
@@ -129,7 +140,7 @@ function parseHexColor(str: string): CSSColorValue | undefined {
129140

130141
switch (body.length) {
131142
case 3:
132-
case 4:
143+
case 4: {
133144
const digits = Array.from(body, s => Number.parseInt(s, 16)).map(n => (n << 4) | n)
134145
return {
135146
type: 'rgb',
@@ -138,9 +149,10 @@ function parseHexColor(str: string): CSSColorValue | undefined {
138149
? undefined
139150
: Math.round(digits[3] / 255 * 100) / 100,
140151
}
152+
}
141153

142154
case 6:
143-
case 8:
155+
case 8: {
144156
const value = Number.parseInt(body, 16)
145157
return {
146158
type: 'rgb',
@@ -151,6 +163,7 @@ function parseHexColor(str: string): CSSColorValue | undefined {
151163
? undefined
152164
: Math.round((value & 0xFF) / 255 * 100) / 100,
153165
}
166+
}
154167
}
155168
}
156169

packages-presets/rule-utils/src/utilities.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,14 @@ export function getStringComponent(str: string, open: string, close: string, sep
7878
]
7979
}
8080

81-
export function getStringComponents(str: string, separators: string | string[], limit?: number) {
81+
export function getStringComponents(str: string, separators: string | string[], limit?: number, open: string = '(', close: string = ')') {
8282
limit = limit ?? 10
8383
const components = []
8484
let i = 0
8585
while (str !== '') {
8686
if (++i > limit)
8787
return
88-
const componentPair = getStringComponent(str, '(', ')', separators)
88+
const componentPair = getStringComponent(str, open, close, separators)
8989
if (!componentPair)
9090
return
9191
const [component, rest] = componentPair

0 commit comments

Comments
 (0)
0