Skip to content

Commit

Permalink
feat: support nested presets
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Apr 9, 2023
1 parent 28ae639 commit 8e9dc95
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 7 deletions.
27 changes: 26 additions & 1 deletion packages/core/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,21 @@ export function resolveShortcuts<Theme extends {} = {}>(shortcuts: UserShortcuts
})
}

const __RESOLVED = '_uno_resolved'

/**
* Resolve a single preset, nested presets are ignored
*/
export function resolvePreset<Theme extends {} = {}>(preset: Preset<Theme>): Preset<Theme> {
if (__RESOLVED in preset)
return preset

preset = { ...preset }
Object.defineProperty(preset, __RESOLVED, {
value: true,
enumerable: false,
})

const shortcuts = preset.shortcuts
? resolveShortcuts(preset.shortcuts)
: undefined
Expand All @@ -34,12 +48,23 @@ export function resolvePreset<Theme extends {} = {}>(preset: Preset<Theme>): Pre
return preset
}

/**
* Resolve presets with nested presets
*/
export function resolvePresets<Theme extends {} = {}>(preset: Preset<Theme>): Preset<Theme>[] {
const root = resolvePreset(preset)
if (!root.presets)
return [root]
const nested = (root.presets || []).flatMap(toArray).flatMap(resolvePresets)
return [root, ...nested]
}

export function resolveConfig<Theme extends {} = {}>(
userConfig: UserConfig<Theme> = {},
defaults: UserConfigDefaults<Theme> = {},
): ResolvedConfig<Theme> {
const config = Object.assign({}, defaults, userConfig) as UserConfigDefaults<Theme>
const rawPresets = (config.presets || []).flatMap(toArray).map(resolvePreset)
const rawPresets = uniq((config.presets || []).flatMap(toArray).flatMap(resolvePresets))

const sortedPresets = [
...rawPresets.filter(p => p.enforce === 'pre'),
Expand Down
10 changes: 5 additions & 5 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,11 @@ export interface ConfigBase<Theme extends {} = {}> {
*/
extendTheme?: Arrayable<ThemeExtender<Theme>>

/**
* Presets
*/
presets?: (Preset<Theme> | Preset<Theme>[])[]

/**
* Additional options for auto complete
*/
Expand Down Expand Up @@ -547,11 +552,6 @@ export interface UserOnlyOptions<Theme extends {} = {}> {
*/
shortcutsLayer?: string

/**
* Presets
*/
presets?: (Preset<Theme> | Preset<Theme>[])[]

/**
* Environment mode
*
Expand Down
46 changes: 45 additions & 1 deletion test/config.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { UserConfig } from '@unocss/core'
import type { Preset, UserConfig } from '@unocss/core'
import { createGenerator } from '@unocss/core'
import type { Theme } from '@unocss/preset-mini'
import presetMini from '@unocss/preset-mini'
Expand Down Expand Up @@ -88,4 +88,48 @@ describe('config', () => {
.text-red-200{color:red;}"
`)
})

test('nested presets', async () => {
const presetA: Preset = {
name: 'presetA',
rules: [
['text-red-500', { color: 'red' }],
['bg-red-500', { backgroundColor: 'red' }],
],
shortcuts: {
'text-red': 'text-red-500',
},
}
const presetB: Preset = {
name: 'presetB',
rules: [
['text-yellow-500', { color: 'yellow' }],
['bg-yellow-500', { backgroundColor: 'yellow' }],
],
shortcuts: [{
btn: 'text-red bg-yellow-500',
}],
presets: [
presetA,
],
}

const uno = createGenerator({
presets: [
presetB,
],
})

expect(uno.config.presets.map(i => i.name))
.toEqual(['presetB', 'presetA'])

const { css } = await uno.generate('btn text-red text-yellow-500', { preflights: false })
expect(css).toMatchInlineSnapshot(`
"/* layer: shortcuts */
.btn{backgroundColor:yellow;color:red;}
.text-red{color:red;}
/* layer: default */
.text-yellow-500{color:yellow;}"
`)
})
})

0 comments on commit 8e9dc95

Please sign in to comment.