Skip to content

Commit 229f17f

Browse files
committed
Add: Most CSS color space functions are supported
1 parent 3f9927c commit 229f17f

File tree

20 files changed

+80
-91
lines changed

20 files changed

+80
-91
lines changed

internal

packages/core/src/core.ts

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -353,15 +353,13 @@ export default class MasterCSS {
353353
variable.name = flatName
354354
if (groups.length)
355355
variable.group = groups.join('.')
356-
if (variable.type === 'color') {
357-
if (alpha) {
358-
const slashIndex = variable.value.indexOf('/')
359-
variable = {
360-
...variable,
361-
value: slashIndex === -1
362-
? variable.value + ' / ' + (alpha.startsWith('0.') ? alpha.slice(1) : alpha)
363-
: (variable.value.slice(0, slashIndex + 2) + String(+variable.value.slice(slashIndex + 2) * +alpha).slice(1))
364-
}
356+
if (variable.type === 'color' && variable.value && alpha) {
357+
const slashIndex = variable.value.indexOf('/')
358+
variable = {
359+
...variable,
360+
value: slashIndex === -1
361+
? variable.value + '/' + (alpha.startsWith('0.') ? alpha.slice(1) : alpha)
362+
: (variable.value.slice(0, slashIndex + 1) + String(+variable.value.slice(slashIndex + 1) * +alpha).slice(1))
365363
}
366364
}
367365
const currentMode = replacedMode ?? mode
@@ -472,23 +470,54 @@ export default class MasterCSS {
472470
}
473471
}
474472
} else {
475-
const hexColorResult = /^#([A-Fa-f0-9]{3,4}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})$/.exec(variableDefinition)
476-
if (hexColorResult) {
477-
const [r, g, b, a] = hexToRgb(hexColorResult[1])
478-
addVariable(name, { type: 'color', value: `${r} ${g} ${b}${a === 1 ? '' : ' / ' + a}`, space: 'rgb' })
479-
} else {
480-
const rgbFunctionResult = /^rgb\( *([0-9]{1,3})(?: *, *| +)([0-9]{1,3})(?: *, *| +)([0-9]{1,3}) *(?:(?:,|\/) *(.*?) *)?\)$/.exec(variableDefinition)
481-
if (rgbFunctionResult) {
482-
addVariable(name, { type: 'color', value: rgbFunctionResult[1] + ' ' + rgbFunctionResult[2] + ' ' + rgbFunctionResult[3] + (rgbFunctionResult[4] ? ' / ' + (rgbFunctionResult[4].startsWith('0.') ? rgbFunctionResult[4].slice(1) : rgbFunctionResult[4]) : ''), space: 'rgb' })
483-
} else {
484-
const hslFunctionResult = /^hsl\((.*?)\)$/.exec(variableDefinition)
485-
if (hslFunctionResult) {
486-
addVariable(name, { type: 'color', value: hslFunctionResult[1], space: 'hsl' })
487-
} else {
488-
addVariable(name, { type: 'string', value: variableDefinition })
473+
// 1. HEX
474+
const hexMatch = /^#([a-f0-9]{3,4}|[a-f0-9]{6}|[a-f0-9]{8})$/i.exec(variableDefinition)
475+
if (hexMatch) {
476+
const [r, g, b, a] = hexToRgb(hexMatch[1])
477+
addVariable(name, {
478+
type: 'color',
479+
value: `${r} ${g} ${b}${a === 1 ? '' : `/${a}`}`,
480+
space: 'rgb',
481+
})
482+
return
483+
}
484+
485+
// 2. COLOR FUNCTION
486+
const funcMatch = /^(color|color-contrast|color-mix|hwb|lab|lch|oklab|oklch|rgb|hsl|light-dark)\((.+)\)$/i.exec(variableDefinition)
487+
if (funcMatch) {
488+
let [, space, rawArgs] = funcMatch
489+
space = space.toLowerCase()
490+
const normalizedArgs = rawArgs
491+
.replace(/\s*\/\s*/g, '/')
492+
.replace(/\s*,\s*/g, ' ')
493+
.replace(/\s+/g, ' ')
494+
.trim()
495+
496+
let alpha: string | undefined
497+
const alphaMatch = /^(.+?)\/([^\s]+)$/.exec(normalizedArgs)
498+
const finalArgs = alphaMatch ? alphaMatch[1].trim() : normalizedArgs
499+
alpha = alphaMatch ? alphaMatch[2] : undefined
500+
if (space === 'color') {
501+
const nested = /^([a-z0-9-]+) (.+)$/i.exec(finalArgs)
502+
if (nested) {
503+
const [, nestedSpace, rest] = nested
504+
addVariable(name, {
505+
type: 'color',
506+
value: `${nestedSpace} ${rest}`,
507+
space: 'color',
508+
}, alpha)
509+
return
489510
}
490511
}
512+
addVariable(name, {
513+
type: 'color',
514+
value: finalArgs,
515+
space,
516+
}, undefined, alpha)
517+
return
491518
}
519+
// 3. Fallback
520+
addVariable(name, { type: 'string', value: variableDefinition })
492521
}
493522
}
494523
}

packages/core/src/utils/extend-config.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ export default function extendConfig(...configs: (Config | undefined)[]) {
99
Object.entries(obj).forEach(([key, value]) => {
1010
if (typeof value === 'object' && !Array.isArray(value)) {
1111
formatDeeply(value)
12-
} else if (key && !key.startsWith('@')) {
12+
} else if (key) {
1313
obj[key] = { '': value }
1414
}
1515
})
1616
}
17-
['components', 'variables'].forEach((key) => {
17+
['components', 'variables', 'modes'].forEach((key) => {
1818
if (clonedConfig[key as keyof Config]) {
1919
formatDeeply(clonedConfig[key as keyof Config] as Record<string, any>)
2020
}
@@ -44,7 +44,7 @@ export default function extendConfig(...configs: (Config | undefined)[]) {
4444
})
4545
return extendedConfig
4646
},
47-
{ animations: {}, components: {}, at: {}, variables: {} }
47+
{ animations: {}, components: {}, at: {}, variables: {}, modes: {} }
4848
)
4949

5050
for (const key in result) {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

3-
exports[`comp -> comp -> var > badge with common strong comp 1`] = `"@layer base,theme,preset,components,general;@layer theme{@media (prefers-color-scheme:light){:root{--primary:0 0 0}}@media (prefers-color-scheme:dark){:root{--primary:255 255 255}}@media (prefers-color-scheme:light){:root{--primary-text:255 255 255}}@media (prefers-color-scheme:dark){:root{--primary-text:0 0 0}}@media (prefers-color-scheme:light){:root{--primary-active:162 161 163}}@media (prefers-color-scheme:dark){:root{--primary-active:255 255 255}}}@layer components{.badge-primary{outline:0.0625rem rgb(var(--primary-active)) solid}.badge-primary{background-color:rgb(var(--primary))}.badge-primary{color:rgb(var(--primary-text))}}"`;
3+
exports[`comp -> comp -> var > badge with common strong comp 1`] = `"@layer base,theme,preset,components,general;@layer theme{@media (prefers-color-scheme:light){:root{--primary:0 0 0}}@media (prefers-color-scheme:dark){:root{--primary:255 255 255}}@media (prefers-color-scheme:light){:root{--primary-text:255 255 255}}@media (prefers-color-scheme:dark){:root{--primary-text:0 0 0}}@media (prefers-color-scheme:light){:root{--primary-active:71.04% 0.0048 308.4}}@media (prefers-color-scheme:dark){:root{--primary-active:255 255 255}}}@layer components{.badge-primary{outline:0.0625rem oklch(var(--primary-active)) solid}.badge-primary{background-color:rgb(var(--primary))}.badge-primary{color:rgb(var(--primary-text))}}"`;

packages/core/tests/config.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,7 @@ export default {
6060
rgb1: 'rgb(0, 0, 0)',
6161
rgb2: 'rgb(0 0 0)',
6262
rgb3: 'rgb(0 0 0/.5)',
63-
rgb4: 'rgb(0,0,0,.5)',
64-
'2': '$(primary-rgb4)/.7'
63+
'2': '$(primary-rgb3)/.7'
6564
},
6665
input: '#123456',
6766
code: '$(accent)',

packages/core/tests/config/colors/hex.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,15 @@ describe.concurrent('with themes', () => {
5050
modes: {
5151
'dark': { name: 'primary', key: 'primary', type: 'color', space: 'rgb', value: '255 255 255' },
5252
'light': { name: 'primary', key: 'primary', type: 'color', space: 'rgb', value: '150 150 150' },
53-
'chrisma': { name: 'primary', key: 'primary', type: 'color', space: 'rgb', value: '0 0 0 / .5' }
53+
'chrisma': { name: 'primary', key: 'primary', type: 'color', space: 'rgb', value: '0 0 0/.5' }
5454
}
5555
})
5656
})
5757

5858
it.concurrent('color', () => {
5959
expectLayers(
6060
{
61-
theme: ':root{--primary:0 0 0}.light{--primary:150 150 150}.dark{--primary:255 255 255}.chrisma{--primary:0 0 0 / .5}',
61+
theme: ':root{--primary:0 0 0}.light{--primary:150 150 150}.dark{--primary:255 255 255}.chrisma{--primary:0 0 0/.5}',
6262
general: '.fg\\:primary{color:rgb(var(--primary))}'
6363
},
6464
'fg:primary',
@@ -69,7 +69,7 @@ describe.concurrent('with themes', () => {
6969
it.concurrent('color/.5', () => {
7070
expectLayers(
7171
{
72-
theme: ':root{--primary:0 0 0}.light{--primary:150 150 150}.dark{--primary:255 255 255}.chrisma{--primary:0 0 0 / .5}',
72+
theme: ':root{--primary:0 0 0}.light{--primary:150 150 150}.dark{--primary:255 255 255}.chrisma{--primary:0 0 0/.5}',
7373
general: '.fg\\:primary\\/\\.5{color:rgb(var(--primary)/.5)}'
7474
},
7575
'fg:primary/.5',

packages/core/tests/config/colors/test.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ test.concurrent('colors', () => {
5252

5353
expectLayers(
5454
{
55-
general: '.bg\\:primary-alpha{background-color:rgb(255 255 255 / .1)}'
55+
general: '.bg\\:primary-alpha{background-color:rgb(255 255 255/.1)}'
5656
},
5757
'bg:primary-alpha',
5858
config
@@ -76,23 +76,15 @@ test.concurrent('colors', () => {
7676

7777
expectLayers(
7878
{
79-
general: '.bg\\:primary-rgb3{background-color:rgb(0 0 0 / .5)}'
79+
general: '.bg\\:primary-rgb3{background-color:rgb(0 0 0/.5)}'
8080
},
8181
'bg:primary-rgb3',
8282
config
8383
)
8484

8585
expectLayers(
8686
{
87-
general: '.bg\\:primary-rgb4{background-color:rgb(0 0 0 / .5)}'
88-
},
89-
'bg:primary-rgb4',
90-
config
91-
)
92-
93-
expectLayers(
94-
{
95-
general: '.bg\\:primary-2{background-color:rgb(0 0 0 / .35)}'
87+
general: '.bg\\:primary-2{background-color:rgb(0 0 0/.35)}'
9688
},
9789
'bg:primary-2',
9890
config

packages/core/tests/config/extends/master-1.css.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ const config = {
1818
dark: {
1919
first: '#222222',
2020
second: '#999999',
21-
third: '$blue-50',
22-
'third-2': '$blue-60'
21+
third: '$white',
22+
'third-2': '$white'
2323
}
2424
},
2525
components: {

packages/core/tests/config/extends/test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ it.concurrent('config extends', () => {
5555
light: {
5656
space: 'rgb',
5757
type: 'color',
58-
value: '0 0 0 / .5'
58+
value: '0 0 0/.5'
5959
}
6060
}
6161
})
@@ -67,7 +67,7 @@ it.concurrent('config extends', () => {
6767
dark: {
6868
space: 'rgb',
6969
type: 'color',
70-
value: '58 124 255'
70+
value: '255 255 255'
7171
}
7272
}
7373
})
@@ -78,7 +78,7 @@ it.concurrent('config extends', () => {
7878
dark: {
7979
space: 'rgb',
8080
type: 'color',
81-
value: '37 99 253'
81+
value: '255 255 255'
8282
}
8383
}
8484
})

packages/core/tests/config/variables/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ describe.concurrent('sigil', () => {
2020
})
2121
it.concurrent('sigil in config', () => {
2222
expect(createCSS({ variables: { a: '$white' } }).create('fg:a')?.text).toContain('rgb(255 255 255)')
23-
expect(createCSS({ variables: { a: '$white/.5' } }).create('fg:a')?.text).toContain('rgb(255 255 255 / .5)')
23+
expect(createCSS({ variables: { a: '$white/.5' } }).create('fg:a')?.text).toContain('rgb(255 255 255/.5)')
2424
})
2525
})
2626

0 commit comments

Comments
 (0)