This commit is contained in:
Adam Wathan 2024-08-14 10:04:09 -04:00
parent 58cbbc5759
commit 22f72362bf
2 changed files with 83 additions and 40 deletions

View file

@ -101,10 +101,55 @@ describe('theme', async () => {
})
expect(compiler.build(['scrollbar-red-500', 'scrollbar-russet-700'])).toMatchInlineSnapshot(`
".scrollbar-russet-700 {
".scrollbar-red-500 {
scrollbar-color: var(--color-red-500, #ef4444);
}
.scrollbar-russet-700 {
scrollbar-color: #7a4724;
}
"
`)
})
test('plugin theme values can reference legacy theme keys that have been replaced with bare value support', async ({
expect,
}) => {
let input = css`
@tailwind utilities;
@plugin "my-plugin";
`
let compiler = await compile(input, {
loadPlugin: async () => {
return plugin(
function ({ matchUtilities, theme }) {
matchUtilities(
{
'animate-duration': (value) => ({ 'animation-duration': value }),
},
{
values: theme('animationDuration'),
},
)
},
{
theme: {
extend: {
animationDuration: ({ theme }: { theme: (path: string) => any }) => ({
...theme('transitionDuration'),
}),
},
},
},
)
},
})
expect(compiler.build(['animate-duration-316'])).toMatchInlineSnapshot(`
".animate-duration-316 {
animation-duration: 316ms;
}
"
`)
})
})

View file

@ -1,7 +1,6 @@
import { substituteAtApply } from './apply'
import { objectToAst, rule, type AstNode, type CssInJs } from './ast'
import type { DesignSystem } from './design-system'
import type { ThemeKey } from './theme'
import { withAlpha, withNegative } from './utilities'
import { inferDataType } from './utils/infer-data-type'
import { segment } from './utils/segment'
@ -26,7 +25,9 @@ export type PluginAPI = {
options?: Partial<{
type: string | string[]
supportsNegativeValues: boolean
values: Record<string, string>
values: Record<string, string> & {
[BARE_VALUE]?: (value: string) => string | null | undefined
}
modifiers: 'any' | Record<string, string>
}>,
): void
@ -132,7 +133,7 @@ export function buildPluginApi(
let isColor = types.includes('color')
// Resolve the candidate value
let value: string | null
let value: string | null = null
{
let values = options?.values ?? {}
@ -152,8 +153,10 @@ export function buildPluginApi(
value = values.DEFAULT ?? null
} else if (candidate.value.kind === 'arbitrary') {
value = candidate.value.value
} else {
value = values[candidate.value.value] ?? null
} else if (values[candidate.value.value]) {
value = values[candidate.value.value]
} else if (values[BARE_VALUE]) {
value = values[BARE_VALUE](candidate.value.value) ?? null
}
}
@ -199,51 +202,30 @@ export function buildPluginApi(
}
},
theme(path) {
let parts = segment(path, '.')
if (path === 'colors') {
let result: Record<string, string> = resolvedConfig.theme?.colors ?? {}
for (let [key] of designSystem.theme.namespace('--color')) {
result[key ?? 'DEFAULT'] = designSystem.theme.resolve(key, ['--color'])!
}
return result
}
let parts = segment(path, '.')
let result = resolvedConfig.theme ?? {}
for (let part of parts) {
result = result?.[part]
}
if (
[
'accentColor',
'backgroundColor',
'borderColor',
'boxShadowColor',
'caretColor',
'divideColor',
'fill',
'gradientColorStops',
'outlineColor',
'placeholderColor',
'ringColor',
'ringOffsetColor',
'stroke',
'textColor',
'textDecorationColor',
].includes(path)
) {
// Convert camelCase to kebab-case:
// https://github.com/postcss/postcss-js/blob/b3db658b932b42f6ac14ca0b1d50f50c4569805b/parser.js#L30-L35
let newPath = `--${path.replace(/([A-Z])/g, '-$1').toLowerCase()}` as ThemeKey
for (let [key] of designSystem.theme.namespace('--color')) {
result[key ?? 'DEFAULT'] = designSystem.theme.resolve(key, ['--color'])
}
for (let [key] of designSystem.theme.namespace(newPath)) {
result[key ?? 'DEFAULT'] = designSystem.theme.resolve(key, [newPath])
}
}
return result
},
}
}
const BARE_VALUE = Symbol('BARE_VALUE')
export function registerPlugins(plugins: Plugin[], designSystem: DesignSystem, ast: AstNode[]) {
let pluginObjects = []
@ -271,7 +253,23 @@ export function registerPlugins(plugins: Plugin[], designSystem: DesignSystem, a
for (let { config } of pluginObjects) {
for (let key in config?.theme?.extend) {
resolvedConfig.theme[key] ??= {}
Object.assign(resolvedConfig.theme[key], config?.theme.extend[key])
let value = config.theme.extend[key]
if (value instanceof Function) {
value = value({
theme(path: string) {
if (path === 'transitionDuration') {
return {
[BARE_VALUE]: (value: string) => {
if (!Number.isNaN(Number(value))) {
return `${value}ms`
}
},
}
}
},
})
}
Object.assign(resolvedConfig.theme[key], value)
}
}