Skip to content

Commit

Permalink
feat(core): support factory with definePreset (#3098)
Browse files Browse the repository at this point in the history
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
  • Loading branch information
chizukicn and antfu committed Sep 19, 2023
1 parent de279bb commit 25fdc24
Show file tree
Hide file tree
Showing 14 changed files with 125 additions and 45 deletions.
6 changes: 3 additions & 3 deletions docs/config/presets.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ When authoring a preset, we usually export a constructor function that you could

```ts
// my-preset.ts
import { Preset } from 'unocss'
import { Preset, definePreset } from 'unocss'

export default function myPreset(options: MyPresetOptions): Preset {
export default definePreset((options?: MyPresetOptions) => {
return {
name: 'my-preset',
rules: [
Expand All @@ -19,7 +19,7 @@ export default function myPreset(options: MyPresetOptions): Preset {
],
// it supports most of the configuration you could have in the root config
}
}
})
```

Then the user can use it like this:
Expand Down
16 changes: 13 additions & 3 deletions packages/core/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Preset, ResolvedConfig, Rule, Shortcut, ToArray, UserConfig, UserConfigDefaults, UserShortcuts } from './types'
import type { Preset, PresetFactory, ResolvedConfig, Rule, Shortcut, ToArray, UserConfig, UserConfigDefaults, UserShortcuts } from './types'
import { clone, isStaticRule, mergeDeep, normalizeVariant, toArray, uniq, uniqueBy } from './utils'
import { extractorSplit } from './extractors'
import { DEFAULT_LAYERS } from './constants'
Expand All @@ -16,7 +16,11 @@ const __RESOLVED = '_uno_resolved'
/**
* Resolve a single preset, nested presets are ignored
*/
export function resolvePreset<Theme extends object = object>(preset: Preset<Theme>): Preset<Theme> {
export function resolvePreset<Theme extends object = object>(presetInput: Preset<Theme> | PresetFactory<Theme, any>): Preset<Theme> {
let preset = typeof presetInput === 'function'
? presetInput()
: presetInput

if (__RESOLVED in preset)
return preset

Expand Down Expand Up @@ -51,7 +55,7 @@ export function resolvePreset<Theme extends object = object>(preset: Preset<Them
/**
* Resolve presets with nested presets
*/
export function resolvePresets<Theme extends object = object>(preset: Preset<Theme>): Preset<Theme>[] {
export function resolvePresets<Theme extends object = object>(preset: Preset<Theme> | PresetFactory<Theme, any>): Preset<Theme>[] {
const root = resolvePreset(preset)
if (!root.presets)
return [root]
Expand Down Expand Up @@ -212,3 +216,9 @@ function mergeAutocompleteShorthands(shorthands: Record<string, string | string[
}
, {})
}

export function definePreset<Options extends object | undefined = undefined, Theme extends object = object>(preset: PresetFactory<Theme, Options>): PresetFactory<Theme, Options>
export function definePreset<Theme extends object = object>(preset: Preset<Theme>): Preset<Theme>
export function definePreset(preset: any) {
return preset
}
6 changes: 5 additions & 1 deletion packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ export interface ConfigBase<Theme extends object = object> {
/**
* Presets
*/
presets?: (Preset<Theme> | Preset<Theme>[])[]
presets?: (PresetOrFactory<Theme> | PresetOrFactory<Theme>[])[]

/**
* Additional options for auto complete
Expand Down Expand Up @@ -539,6 +539,10 @@ export interface Preset<Theme extends object = object> extends ConfigBase<Theme>
layer?: string
}

export type PresetFactory<Theme extends object = object, PresetOptions extends object | undefined = undefined> = (options?: PresetOptions) => Preset<Theme>

export type PresetOrFactory<Theme extends object = object> = Preset<Theme> | PresetFactory<Theme, any>

export interface GeneratorOptions {
/**
* Merge utilities with the exact same body to save the file size
Expand Down
7 changes: 3 additions & 4 deletions packages/preset-attributify/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Preset } from '@unocss/core'
import { definePreset } from '@unocss/core'
import { autocompleteExtractorAttributify } from './autocomplete'
import { defaultIgnoreAttributes, extractorAttributify } from './extractor'
import type { AttributifyOptions } from './types'
Expand All @@ -10,7 +10,7 @@ export * from './variant'
export * from './types'
export * from './jsx'

function presetAttributify(options: AttributifyOptions = {}): Preset {
export const presetAttributify = definePreset((options: AttributifyOptions = {}) => {
options.strict = options.strict ?? false
options.prefix = options.prefix ?? 'un-'
options.prefixedOnly = options.prefixedOnly ?? false
Expand Down Expand Up @@ -38,7 +38,6 @@ function presetAttributify(options: AttributifyOptions = {}): Preset {
},
extractorDefault: options.strict ? false : undefined,
}
}
})

export { presetAttributify }
export default presetAttributify
7 changes: 3 additions & 4 deletions packages/preset-icons/src/core.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { Preset } from '@unocss/core'
import { warnOnce } from '@unocss/core'
import { definePreset, warnOnce } from '@unocss/core'
import type {
IconifyLoaderOptions,
UniversalIconLoader,
Expand All @@ -12,7 +11,7 @@ const COLLECTION_NAME_PARTS_MAX = 3
export { IconsOptions }

export function createPresetIcons(lookupIconLoader: (options: IconsOptions) => Promise<UniversalIconLoader>) {
return function presetIcons(options: IconsOptions = {}): Preset {
return definePreset((options: IconsOptions = {}) => {
const {
scale = 1,
mode = 'auto',
Expand Down Expand Up @@ -118,7 +117,7 @@ export function createPresetIcons(lookupIconLoader: (options: IconsOptions) => P
{ layer, prefix },
]],
}
}
})
}

export function combineLoaders(loaders: UniversalIconLoader[]) {
Expand Down
7 changes: 4 additions & 3 deletions packages/preset-mini/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Postprocessor, Preflight, PreflightContext, Preset, PresetOptions } from '@unocss/core'
import type { Postprocessor, Preflight, PreflightContext, PresetOptions } from '@unocss/core'
import { definePreset } from '@unocss/core'
import { extractorArbitraryVariants } from '@unocss/extractor-arbitrary-variants'
import { preflights } from './preflights'
import { rules } from './rules'
Expand Down Expand Up @@ -71,7 +72,7 @@ export interface PresetMiniOptions extends PresetOptions {
arbitraryVariants?: boolean
}

export function presetMini(options: PresetMiniOptions = {}): Preset<Theme> {
export const presetMini = definePreset((options: PresetMiniOptions = {}) => {
options.dark = options.dark ?? 'class'
options.attributifyPseudo = options.attributifyPseudo ?? false
options.preflight = options.preflight ?? true
Expand All @@ -95,7 +96,7 @@ export function presetMini(options: PresetMiniOptions = {}): Preset<Theme> {
shorthands,
},
}
}
})

export default presetMini

Expand Down
8 changes: 5 additions & 3 deletions packages/preset-rem-to-px/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Preset } from '@unocss/core'
import { definePreset } from '@unocss/core'

const remRE = /(-?[\.\d]+)rem/g

Expand All @@ -10,7 +10,7 @@ export interface RemToPxOptions {
baseFontSize?: number
}

export default function remToPxPreset(options: RemToPxOptions = {}): Preset {
export const presetRemToPx = definePreset((options: RemToPxOptions = {}) => {
const {
baseFontSize = 16,
} = options
Expand All @@ -25,4 +25,6 @@ export default function remToPxPreset(options: RemToPxOptions = {}): Preset {
})
},
}
}
})

export default presetRemToPx
8 changes: 4 additions & 4 deletions packages/preset-tagify/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Preset } from '@unocss/core'
import { definePreset } from '@unocss/core'
import type { TagifyOptions } from './types'
import { extractorTagify } from './extractor'
import { variantTagify } from './variant'
Expand All @@ -7,7 +7,7 @@ export * from './extractor'
export * from './types'
export * from './variant'

function tagifyPreset(options: TagifyOptions = {}): Preset {
export const presetTagify = definePreset((options: TagifyOptions = {}) => {
const {
defaultExtractor = true,
} = options
Expand All @@ -27,6 +27,6 @@ function tagifyPreset(options: TagifyOptions = {}): Preset {
? undefined
: false,
}
}
})

export default tagifyPreset
export default presetTagify
6 changes: 3 additions & 3 deletions packages/preset-typography/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { CSSObject, Preset } from '@unocss/core'
import { toEscapedSelector } from '@unocss/core'
import { definePreset, toEscapedSelector } from '@unocss/core'
import type { Theme } from '@unocss/preset-mini'
import { getPreflights } from './preflights'
import type { TypographyCompatibilityOptions } from './types/compatibilityOptions'
Expand Down Expand Up @@ -60,7 +60,7 @@ export interface TypographyOptions {
* @returns typography preset
* @public
*/
export function presetTypography(options?: TypographyOptions): Preset<Theme> {
export const presetTypography = definePreset((options?: TypographyOptions): Preset<Theme> => {
if (options?.className) {
console.warn('[unocss:preset-typography] "className" is deprecated. '
+ 'Use "selectorName" instead.')
Expand Down Expand Up @@ -148,6 +148,6 @@ export function presetTypography(options?: TypographyOptions): Preset<Theme> {
},
],
}
}
})

export default presetTypography
6 changes: 3 additions & 3 deletions packages/preset-uno/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Preset } from '@unocss/core'
import { definePreset } from '@unocss/core'
import type { PresetMiniOptions, Theme } from '@unocss/preset-mini'
import { presetWind } from '@unocss/preset-wind'
import { variantColorMix } from './variants/mix'
Expand All @@ -7,7 +7,7 @@ export type { Theme }

export interface PresetUnoOptions extends PresetMiniOptions {}

export function presetUno(options: PresetUnoOptions = {}): Preset<Theme> {
export const presetUno = definePreset((options: PresetUnoOptions = {}) => {
const wind = presetWind(options)
return {
...wind,
Expand All @@ -17,6 +17,6 @@ export function presetUno(options: PresetUnoOptions = {}): Preset<Theme> {
variantColorMix(),
],
}
}
})

export default presetUno
9 changes: 4 additions & 5 deletions packages/preset-web-fonts/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Preset } from '@unocss/core'
import { toArray } from '@unocss/core'
import { definePreset, toArray } from '@unocss/core'
import { LAYER_IMPORTS } from '../../core/src/constants'
import { BunnyFontsProvider } from './providers/bunny'
import { GoogleFontsProvider } from './providers/google'
Expand Down Expand Up @@ -41,7 +41,7 @@ export function normalizedFontMeta(meta: WebFontMeta | string, defaultProvider:
}
}

function preset(options: WebFontsOptions = {}): Preset<any> {
export const presetWebFonts = definePreset((options: WebFontsOptions = {}) => {
const {
provider: defaultProvider = 'google',
extendTheme = true,
Expand Down Expand Up @@ -124,8 +124,7 @@ function preset(options: WebFontsOptions = {}): Preset<any> {
}
}
}

return preset
}
})

export default preset
export default presetWebFonts
8 changes: 4 additions & 4 deletions packages/preset-wind/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Preset } from '@unocss/core'
import type { PresetMiniOptions, Theme } from '@unocss/preset-mini'
import { definePreset } from '@unocss/core'
import type { PresetMiniOptions } from '@unocss/preset-mini'
import { presetMini } from '@unocss/preset-mini'

import { rules } from './rules'
Expand All @@ -14,7 +14,7 @@ export { rules, shortcuts, theme, variants }

export interface PresetWindOptions extends PresetMiniOptions { }

export function presetWind(options: PresetWindOptions = {}): Preset<Theme> {
export const presetWind = definePreset((options: PresetWindOptions = {}) => {
return {
...presetMini(options),
name: '@unocss/preset-wind',
Expand All @@ -23,6 +23,6 @@ export function presetWind(options: PresetWindOptions = {}): Preset<Theme> {
shortcuts,
variants: variants(options),
}
}
})

export default presetWind
6 changes: 1 addition & 5 deletions packages/unocss/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Preset, UserConfig } from '@unocss/core'
import type { UserConfig } from '@unocss/core'
import type { Theme } from '@unocss/preset-uno'

export * from '@unocss/core'
Expand All @@ -18,7 +18,3 @@ export { default as transformerAttributifyJsx } from '@unocss/transformer-attrib
export function defineConfig<T extends object = Theme>(config: UserConfig<T>) {
return config
}

export function definePreset<T extends object = object>(preset: Preset<T>) {
return preset
}
70 changes: 70 additions & 0 deletions test/define.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { createGenerator, definePreset } from '@unocss/core'
import { describe, expect, it } from 'vitest'

describe('definePreset', () => {
it('functional', async () => {
const presetFn1 = definePreset(() => {
return {
name: 'custom-preset-functional-1',
rules: [
['text-fn1', {
color: 'red',
}],
],
}
})

const presetFn2 = definePreset(() => {
return {
name: 'custom-preset-functional-2',
rules: [
['text-fn2', {
color: 'green',
}],
],
}
})

const presetStatic = definePreset({
name: 'custom-preset-static',
rules: [
['text-static', {
color: 'blue',
}],
],
})

const presetOptional = definePreset((option: { color?: string } = {}) => {
const color = option.color ?? 'red'
return {
name: 'custom-preset',
rules: [
['text-option', {
color,
}],
],
}
})

const uno = createGenerator({
presets: [
presetFn1(),
presetFn2, // presetFn2 is a factory that will be evaluated by uno
presetStatic,
presetOptional({
color: 'dark',
}),
],
})

const { css } = await uno.generate('text-fn1 text-fn2 text-static text-option')
expect(css)
.toMatchInlineSnapshot(`
"/* layer: default */
.text-fn1{color:red;}
.text-fn2{color:green;}
.text-static{color:blue;}
.text-option{color:dark;}"
`)
})
})

0 comments on commit 25fdc24

Please sign in to comment.