Skip to content

Commit 3689021

Browse files
authored
feat(preset-wind4): support theme variable safelist (#4730)
1 parent 3758c4b commit 3689021

File tree

4 files changed

+77
-13
lines changed

4 files changed

+77
-13
lines changed

packages-presets/preset-wind4/src/index.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,6 @@ export interface PreflightsTheme {
4545

4646
/**
4747
* Process the theme keys.
48-
*
49-
* @default undefined
5048
*/
5149
process?: Arrayable<(entry: CSSEntry, ctx: PreflightContext<Theme>) => void>
5250
}

packages-presets/preset-wind4/src/preflights/theme.ts

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import type { CSSEntry, Preflight } from '@unocss/core'
22
import type { PreflightsTheme, PresetWind4Options } from '..'
33
import type { Theme } from '../theme/types'
4-
import { toArray } from '@unocss/core'
4+
import { toArray, uniq } from '@unocss/core'
55
import { alphaPlaceholdersRE } from '@unocss/rule-utils'
6-
import { compressCSS, getThemeByKey, trackedTheme } from '../utils'
6+
import { compressCSS, detectThemeValue, getThemeByKey, themeTracking, trackedTheme } from '../utils'
77

88
/** Exclude output for CSS Variables */
99
const ExcludeCssVarKeys = [
@@ -56,17 +56,33 @@ export function theme(options: PresetWind4Options): Preflight<Theme> {
5656
layer: 'theme',
5757
getCSS(ctx) {
5858
const { theme, generator } = ctx
59-
const preflightsTheme = options.preflights!.theme as PreflightsTheme
60-
if (preflightsTheme.mode === false) {
59+
const safelist = uniq(generator.config.safelist.flatMap(s => typeof s === 'function' ? s(ctx) : s))
60+
const { mode, process } = options.preflights!.theme as PreflightsTheme
61+
if (mode === false) {
6162
return undefined
6263
}
6364

64-
let deps
65+
if (safelist.length > 0) {
66+
for (const s of safelist) {
67+
const [key, ...prop] = s.trim().split(':')
68+
if (key in theme && prop.length <= 1) {
69+
const props = prop.length === 0 ? ['DEFAULT'] : prop[0].split('-')
70+
const v = getThemeByKey(theme, key as keyof Theme, props)
71+
72+
if (typeof v === 'string') {
73+
themeTracking(key, props)
74+
detectThemeValue(v, theme)
75+
}
76+
}
77+
}
78+
}
79+
80+
let deps: CSSEntry[]
6581
const generateCSS = (deps: CSSEntry[]) => {
66-
if (preflightsTheme.process) {
82+
if (process) {
6783
for (const utility of deps) {
68-
for (const process of toArray(preflightsTheme.process)) {
69-
process(utility, ctx)
84+
for (const p of toArray(process)) {
85+
p(utility, ctx)
7086
}
7187
}
7288
}
@@ -83,15 +99,15 @@ ${depCSS}
8399
}`, generator.config.envMode === 'dev')
84100
}
85101

86-
if (preflightsTheme.mode === 'on-demand') {
102+
if (mode === 'on-demand') {
87103
if (trackedTheme.size === 0)
88104
return undefined
89105

90106
deps = Array.from(trackedTheme).map((k) => {
91107
const [key, prop] = k.split(':') as [keyof Theme, string]
92108
const v = getThemeByKey(theme, key, prop.split('-'))
93109

94-
if (v) {
110+
if (typeof v === 'string') {
95111
return [`--${key}${`${key === 'spacing' && prop === 'DEFAULT' ? '' : `-${prop}`}`}`, v]
96112
}
97113

packages-presets/preset-wind4/src/utils/theme-track.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ export function detectThemeValue(value: string, theme: Theme) {
2929
if (variable) {
3030
const [key, ...path] = variable.split('-')
3131
const themeValue = getThemeByKey(theme, key as keyof Theme, path)
32-
if (themeValue != null) {
32+
33+
if (typeof themeValue === 'string') {
3334
themeTracking(key, path)
3435
detectThemeValue(themeValue, theme)
3536
}

test/preset-wind4.test.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,4 +322,53 @@ describe('preset-wind4', () => {
322322
}"
323323
`)
324324
})
325+
326+
it('theme safelist', async () => {
327+
const uno = await createGenerator<object>({
328+
envMode: 'dev',
329+
theme: {
330+
custom: {
331+
foo: 'var(--custom-bar)',
332+
bar: 'var(--custom-baz-DEFAULT, inherit)',
333+
baz: {
334+
DEFAULT: 'inherit',
335+
},
336+
},
337+
},
338+
presets: [
339+
presetWind4({
340+
preflights: {
341+
reset: false,
342+
},
343+
}),
344+
],
345+
safelist: [
346+
'spacing',
347+
'colors:red-100',
348+
'breakpoint:sm',
349+
({ theme }) => {
350+
if ('custom' in theme) {
351+
return [
352+
'custom:foo',
353+
]
354+
}
355+
return []
356+
},
357+
],
358+
})
359+
360+
const { getLayer } = await uno.generate('')
361+
const css = getLayer('theme')
362+
expect(css).toMatchInlineSnapshot(`
363+
"/* layer: theme */
364+
:root, :host {
365+
--spacing: 0.25rem;
366+
--colors-red-100: oklch(93.6% 0.032 17.717);
367+
--breakpoint-sm: 40rem;
368+
--custom-foo: var(--custom-bar);
369+
--custom-bar: var(--custom-baz-DEFAULT, inherit);
370+
--custom-baz-DEFAULT: inherit;
371+
}"
372+
`)
373+
})
325374
})

0 commit comments

Comments
 (0)