diff --git a/README.md b/README.md index 7121339..cac138d 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,12 @@ postcss([ ```ts type Options = { + /** color groups */ colors: Record + /** + * var flags + * @default ['--flag-light', '--flag-dark'] + */ + flags?: string[] } ``` diff --git a/package.json b/package.json index cb9b8c6..4550653 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ } }, "scripts": { + "prepack": "yarn build", "build": "rm -rf dist && pkgroll", "test": "vitest", "test:coverage": "vitest run --coverage", diff --git a/src/index.ts b/src/index.ts index b709a6e..83f95b9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,25 +1,28 @@ import {PluginCreator} from 'postcss' -type Options = { +export type Options = { + /** color groups */ colors: Record + /** + * var flags + * @default ['--flag-light', '--flag-dark'] + */ + flags?: string[] } -const defaults: Options = { +const defaults: Required = { colors: {}, + flags: ['--flag-light', '--flag-dark'], } const reRelativeColor = /\(\s*?from/i const reMixColor = /\bcolor-mix\(/i const themeColors: PluginCreator = (options) => { - const {colors} = {...defaults, ...options} - const reGroup = new RegExp( - `\\b${'var'}\\((${Object.keys(colors).join('|')})\\)`, - 'g' - ) - const resolveColor = ( - theme: 'dark' | 'light', - group: string, - fallback: string - ) => { + const { + colors, + flags: [lightFlag, darkFlag], + } = {...defaults, ...options} + const reGroup = new RegExp(`\\b${'var'}\\((${Object.keys(colors).join('|')})\\)`, 'g') + const resolveColor = (theme: 'dark' | 'light', group: string, fallback: string) => { const [lightKey, darkKey] = colors[group] || [] const colorKey = theme === 'light' ? lightKey : darkKey if (!colorKey) { @@ -37,21 +40,11 @@ const themeColors: PluginCreator = (options) => { if (!reGroup.test(value)) { return } - const lightValue = value.replace(reGroup, (match, group) => - resolveColor('light', group, match) - ) - const darkValue = value.replace(reGroup, (match, group) => - resolveColor('dark', group, match) - ) + const lightValue = value.replace(reGroup, (match, group) => resolveColor('light', group, match)) + const darkValue = value.replace(reGroup, (match, group) => resolveColor('dark', group, match)) const name = '--v' + hash(value) - decl.cloneBefore({ - prop: name, - value: `var(--flag-light, ${lightValue}) var(--flag-dark, ${darkValue})`, - }) - decl.cloneBefore({ - prop: decl.prop, - value: `var(${name})`, - }) + decl.cloneBefore({prop: name, value: `var(${lightFlag}, ${lightValue}) var(${darkFlag}, ${darkValue})`}) + decl.cloneBefore({prop: decl.prop, value: `var(${name})`}) }, } } diff --git a/test/index-with-vars.spec.ts b/test/index-with-vars.spec.ts index 5ff5715..779d224 100644 --- a/test/index-with-vars.spec.ts +++ b/test/index-with-vars.spec.ts @@ -1,10 +1,9 @@ import postcss from 'postcss' -import type {Plugin} from 'postcss' import {test, expect} from 'vitest' import dedent from 'dedent' import presetEnv from 'postcss-preset-env' import globalData from '@csstools/postcss-global-data' -import themeColors from '../src' +import themeColors, {type Options} from '../src' const colors = { '--G01': ['#eee', '#111'], @@ -14,15 +13,7 @@ const colors = { '--G03': ['red', 'blue'], } -type ExtraOpts = { - plugins?: (Plugin | any)[] -} - -const process = async ( - css: string, - options?: Omit[0], 'colors'> | null, - {plugins = []}: ExtraOpts = {} -) => { +const process = async (css: string, options?: Omit | null) => { return postcss([ globalData({ files: [ @@ -33,7 +24,6 @@ const process = async ( }), themeColors({colors, ...options}), presetEnv(), - ...plugins, ]).process(css, { from: undefined, }) @@ -45,7 +35,7 @@ test('use with relative color syntax', async () => { border: 1px solid oklch(from var(--G01) .8 c h); box-shadow: 0 0 0 2px var(--G01), 0 0 0 4px oklch(from var(--G01) l c h / .1); }` - const result = await process(input, null, {}) + const result = await process(input) expect(result.css).toMatchInlineSnapshot(` "a { --v1868641404: var(--flag-light, rgba(238, 238, 238, 0.1)) var(--flag-dark, rgba(17, 17, 17, 0.1)); @@ -80,7 +70,7 @@ test('use with color-mix()', async () => { a { color: color-mix(in srgb, var(--G01), transparent 20%); }` - const result = await process(input, null, {}) + const result = await process(input) expect(result.css).toMatchInlineSnapshot(` "a { --v546761730: var(--flag-light, rgba(238, 238, 238, 0.8)) var(--flag-dark, rgba(17, 17, 17, 0.8)); diff --git a/test/index.spec.ts b/test/index.spec.ts index b538fcb..e5d00d9 100644 --- a/test/index.spec.ts +++ b/test/index.spec.ts @@ -1,10 +1,9 @@ import postcss from 'postcss' -import type {Plugin} from 'postcss' import {test, expect} from 'vitest' import dedent from 'dedent' import presetEnv from 'postcss-preset-env' import globalData from '@csstools/postcss-global-data' -import themeColors from '../src' +import themeColors, {type Options} from '../src' const colors = { '--G01': ['#eee', '#111'], @@ -14,15 +13,7 @@ const colors = { '--G03': ['red', 'blue'], } -type ExtraOpts = { - plugins?: (Plugin | any)[] -} - -const process = async ( - css: string, - options?: Omit[0], 'colors'> | null, - {plugins = []}: ExtraOpts = {} -) => { +const process = async (css: string, options?: Omit | null) => { return postcss([ globalData({ files: [ @@ -32,7 +23,6 @@ const process = async ( }), themeColors({colors, ...options}), presetEnv(), - ...plugins, ]).process(css, { from: undefined, }) @@ -44,7 +34,7 @@ test('use with relative color syntax', async () => { border: 1px solid oklch(from var(--G01) .8 c h); box-shadow: 0 0 0 2px var(--G01), 0 0 0 4px oklch(from var(--G01) l c h / .1); }` - const result = await process(input, null, {}) + const result = await process(input) expect(result.css).toMatchInlineSnapshot(` "a { --v1868641404: var(--flag-light, rgba(238, 238, 238, 0.1)) var(--flag-dark, rgba(17, 17, 17, 0.1)); @@ -72,7 +62,7 @@ test('use with color-mix()', async () => { color: color-mix(in srgb, var(--G01), transparent 20%); } ` - const result = await process(input, null, {}) + const result = await process(input) expect(result.css).toMatchInlineSnapshot(` " a { @@ -125,3 +115,29 @@ test('process undefined group', async () => { const result = await process(input) expect(result.css).toBe(input) }) + +test('flags option', async () => { + const input = ` + a { + color: rgba(from var(--G03) r g b / .1); + } + ` + const result = await process(input, { + flags: ['--isLight', '--isDark'], + }) + expect(result.css).toMatchInlineSnapshot(` + " + a { + --v3204038125: var(--isLight, rgba(255, 0, 0, 0.1)) var(--isDark, rgba(0, 0, 255, 0.1)); + color: rgba(255, 0, 0, 0.1) rgba(0, 0, 255, 0.1); + color: var(--v3204038125); + } + + @supports (color: lab(from red l 1 1% / calc(alpha + 0.1))) { + a { + color: rgba(from var(--G03) r g b / .1); + } + } + " + `) +})