Skip to content

Commit

Permalink
feat: support extendTheme return to override (#2258)
Browse files Browse the repository at this point in the history
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
Co-authored-by: Chris <1633711653@qq.com>
  • Loading branch information
3 people committed Apr 9, 2023
1 parent 4fe0a96 commit aae131b
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 7 deletions.
8 changes: 5 additions & 3 deletions packages/core/src/config.ts
@@ -1,4 +1,4 @@
import type { Postprocessor, Preprocessor, Preset, ResolvedConfig, Rule, Shortcut, ThemeExtender, UserConfig, UserConfigDefaults, UserShortcuts } from './types'
import type { Postprocessor, Preprocessor, Preset, ResolvedConfig, Rule, Shortcut, UserConfig, UserConfigDefaults, UserShortcuts } from './types'
import { clone, isStaticRule, mergeDeep, normalizeVariant, toArray, uniq } from './utils'
import { extractorSplit } from './extractors'
import { DEFAULT_LAYERS } from './constants'
Expand Down Expand Up @@ -82,12 +82,14 @@ export function resolveConfig<Theme extends {} = {}>(
.filter(Boolean)
.reverse() as ResolvedConfig<Theme>['rulesDynamic']

const theme: Theme = clone([
let theme: Theme = clone([
...sortedPresets.map(p => p.theme || {}),
config.theme || {},
].reduce<Theme>((a, p) => mergeDeep(a, p), {} as Theme))

;(mergePresets('extendTheme') as ThemeExtender<any>[]).forEach(extendTheme => extendTheme(theme))
const extendThemes = toArray(mergePresets('extendTheme'))
for (const extendTheme of extendThemes)
theme = extendTheme(theme) || theme

const autocomplete = {
templates: uniq(sortedPresets.map(p => toArray(p.autocomplete?.templates)).flat()),
Expand Down
6 changes: 4 additions & 2 deletions packages/core/src/types.ts
Expand Up @@ -303,7 +303,7 @@ export type Variant<Theme extends {} = {}> = VariantFunction<Theme> | VariantObj

export type Preprocessor = (matcher: string) => string | undefined
export type Postprocessor = (util: UtilObject) => void
export type ThemeExtender<T> = (theme: T) => void
export type ThemeExtender<T> = (theme: T) => T | void

export interface ConfigBase<Theme extends {} = {}> {
/**
Expand Down Expand Up @@ -382,7 +382,9 @@ export interface ConfigBase<Theme extends {} = {}> {
postprocess?: Arrayable<Postprocessor>

/**
* Custom functions to extend the theme object
* Custom functions mutate the theme object.
*
* It's also possible to return a new theme object to completely replace the original one.
*/
extendTheme?: Arrayable<ThemeExtender<Theme>>

Expand Down
2 changes: 1 addition & 1 deletion packages/preset-web-fonts/src/types.ts
Expand Up @@ -24,7 +24,7 @@ export interface WebFontsOptions {
fonts?: Record<string, WebFontMeta | string | (WebFontMeta | string)[]>

/**
* Extend the theme object
* Extend fonts to the theme object
* @default true
*/
extendTheme?: boolean
Expand Down
2 changes: 1 addition & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

91 changes: 91 additions & 0 deletions test/config.test.ts
@@ -0,0 +1,91 @@
import type { UserConfig } from '@unocss/core'
import { createGenerator } from '@unocss/core'
import type { Theme } from '@unocss/preset-mini'
import presetMini from '@unocss/preset-mini'
import { describe, expect, test } from 'vitest'

describe('config', () => {
const createUno = (userConfig: UserConfig) => {
return createGenerator<Theme>({
...userConfig,
presets: [
presetMini(),
],
})
}
test('theme', async () => {
const uno = createUno({
theme: {
colors: {
red: {
500: '#0f0',
},
},
},
})
const { css } = await uno.generate('text-red-500 text-blue', { preflights: false })
expect(css).toMatchInlineSnapshot(`
"/* layer: default */
.text-blue{--un-text-opacity:1;color:rgba(96,165,250,var(--un-text-opacity));}
.text-red-500{--un-text-opacity:1;color:rgba(0,255,0,var(--un-text-opacity));}"
`)
})

test('extendTheme with return extend', async () => {
const uno = createUno({
extendTheme(mergedTheme) {
return {
...mergedTheme,
colors: {
red: {
500: 'red',
},
},
}
},
})
expect(uno.config.theme.colors).toEqual({ red: { 500: 'red' } })
})

test('extendTheme with return', async () => {
const unocss = createGenerator<Theme>({
extendTheme: () => {
return {
colors: {
red: {
200: 'red',
},
},
}
},
presets: [
presetMini(),
],
})
const { css } = await unocss.generate('text-red-100 text-red-200', { preflights: false })
expect(css).toMatchInlineSnapshot(`
"/* layer: default */
.text-red-200{color:red;}"
`)
})

test('extendTheme with mutation', async () => {
const unocss = createGenerator<Theme>({
extendTheme: (theme) => {
// @ts-expect-error test
theme.colors.red[100] = 'green'
// @ts-expect-error test
theme.colors.red[200] = 'red'
},
presets: [
presetMini(),
],
})
const { css } = await unocss.generate('text-red-100 text-red-200', { preflights: false })
expect(css).toMatchInlineSnapshot(`
"/* layer: default */
.text-red-100{color:green;}
.text-red-200{color:red;}"
`)
})
})

0 comments on commit aae131b

Please sign in to comment.