Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Reset default @theme values for non extend JS theme config
  • Loading branch information
philipp-spiess committed Oct 16, 2024
commit 67f9971ca53fae3b64cead8abf3837eda89d090e
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ export function migrateMediaScreen({
function migrate(root: Root) {
if (!designSystem || !userConfig) return

let resolvedUserConfig = resolveConfig(designSystem, [{ base: '', config: userConfig }])
let screens = resolvedUserConfig?.theme?.screens || {}
let { resolvedConfig } = resolveConfig(designSystem, [{ base: '', config: userConfig }])
let screens = resolvedConfig?.theme?.screens || {}

let mediaQueries = new DefaultMap<string, string | null>((name) => {
let value = designSystem?.resolveThemeValue(`--breakpoint-${name}`) ?? screens?.[name]
Expand Down
9 changes: 6 additions & 3 deletions packages/tailwindcss/src/compat/apply-compat-hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,12 +215,15 @@ function upgradeToFullPluginSupport({

let userConfig = [...pluginConfigs, ...configs]

let resolvedConfig = resolveConfig(designSystem, [
let { resolvedConfig } = resolveConfig(designSystem, [
{ config: createCompatConfig(designSystem.theme), base },
...userConfig,
{ config: { plugins: [darkModePlugin] }, base },
])
let resolvedUserConfig = resolveConfig(designSystem, userConfig)
let { resolvedConfig: resolvedUserConfig, resetThemeKeys } = resolveConfig(
designSystem,
userConfig,
)

let pluginApi = buildPluginApi(designSystem, ast, resolvedConfig)

Expand All @@ -231,7 +234,7 @@ function upgradeToFullPluginSupport({
// Merge the user-configured theme keys into the design system. The compat
// config would otherwise expand into namespaces like `background-color` which
// core utilities already read from.
applyConfigToTheme(designSystem, resolvedUserConfig)
applyConfigToTheme(designSystem, resolvedUserConfig, resetThemeKeys)
applyKeyframesToAst(ast, resolvedUserConfig)

registerThemeVariantOverrides(resolvedUserConfig, designSystem)
Expand Down
63 changes: 56 additions & 7 deletions packages/tailwindcss/src/compat/apply-config-to-theme.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { expect, test } from 'vitest'
import { buildDesignSystem } from '../design-system'
import { Theme } from '../theme'
import { Theme, ThemeOptions } from '../theme'
import { applyConfigToTheme } from './apply-config-to-theme'
import { resolveConfig } from './config/resolve-config'

test('Config values can be merged into the theme', () => {
test('config values can be merged into the theme', () => {
let theme = new Theme()
let design = buildDesignSystem(theme)

let resolvedUserConfig = resolveConfig(design, [
let { resolvedConfig, resetThemeKeys } = resolveConfig(design, [
{
config: {
theme: {
Expand Down Expand Up @@ -54,7 +54,7 @@ test('Config values can be merged into the theme', () => {
base: '/root',
},
])
applyConfigToTheme(design, resolvedUserConfig)
applyConfigToTheme(design, resolvedConfig, resetThemeKeys)

expect(theme.resolve('primary', ['--color'])).toEqual('#c0ffee')
expect(theme.resolve('sm', ['--breakpoint'])).toEqual('1234px')
Expand All @@ -75,11 +75,60 @@ test('Config values can be merged into the theme', () => {
])
})

test('Invalid keys are not merged into the theme', () => {
test('will reset default theme values with overwriting theme values', () => {
let theme = new Theme()
let design = buildDesignSystem(theme)

let resolvedUserConfig = resolveConfig(design, [
theme.add('--color-blue-400', 'lightblue', ThemeOptions.DEFAULT)
theme.add('--color-blue-500', 'blue', ThemeOptions.DEFAULT)
theme.add('--color-red-400', '#f87171')
theme.add('--color-red-500', '#ef4444')

let { resolvedConfig, resetThemeKeys } = resolveConfig(design, [
{
config: {
theme: {
colors: {
blue: {
500: '#3b82f6',
},
red: {
500: 'red',
},
},
extend: {
colors: {
blue: {
600: '#2563eb',
},
red: {
600: '#dc2626',
},
},
},
},
},
base: '/root',
},
])
applyConfigToTheme(design, resolvedConfig, resetThemeKeys)

expect(theme.namespace('--color')).toMatchInlineSnapshot(`
Map {
"red-400" => "#f87171",
"red-500" => "#ef4444",
"blue-500" => "#3b82f6",
"blue-600" => "#2563eb",
"red-600" => "#dc2626",
}
`)
})

test('invalid keys are not merged into the theme', () => {
let theme = new Theme()
let design = buildDesignSystem(theme)

let { resolvedConfig, resetThemeKeys } = resolveConfig(design, [
{
config: {
theme: {
Expand All @@ -92,7 +141,7 @@ test('Invalid keys are not merged into the theme', () => {
},
])

applyConfigToTheme(design, resolvedUserConfig)
applyConfigToTheme(design, resolvedConfig, resetThemeKeys)

let entries = Array.from(theme.entries())

Expand Down
13 changes: 12 additions & 1 deletion packages/tailwindcss/src/compat/apply-config-to-theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,18 @@ function resolveThemeValue(value: unknown, subValue: string | null = null): stri
return null
}

export function applyConfigToTheme(designSystem: DesignSystem, { theme }: ResolvedConfig) {
export function applyConfigToTheme(
designSystem: DesignSystem,
{ theme }: ResolvedConfig,
resetThemeKeys: Set<string>,
) {
for (let resetThemeKey of resetThemeKeys) {
let name = keyPathToCssProperty([resetThemeKey])
if (!name) continue

designSystem.theme.clearNamespace(`--${name}`, ThemeOptions.DEFAULT)
}

for (let [path, value] of themeableValues(theme)) {
if (typeof value !== 'string' && typeof value !== 'number') {
continue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import { Theme } from '../theme'
import { applyKeyframesToAst } from './apply-keyframes-to-ast'
import { resolveConfig } from './config/resolve-config'

test('Config values can be merged into the theme', () => {
test('keyframes can be merged into the theme', () => {
let theme = new Theme()
let design = buildDesignSystem(theme)

let ast: AstNode[] = []

let resolvedUserConfig = resolveConfig(design, [
let { resolvedConfig } = resolveConfig(design, [
{
config: {
theme: {
Expand All @@ -30,7 +30,7 @@ test('Config values can be merged into the theme', () => {
base: '/root',
},
])
applyKeyframesToAst(ast, resolvedUserConfig)
applyKeyframesToAst(ast, resolvedConfig)

expect(toCss(ast)).toMatchInlineSnapshot(`
"@keyframes fade-in {
Expand All @@ -52,3 +52,5 @@ test('Config values can be merged into the theme', () => {
"
`)
})

test.todo('will reset default keyframes with overwriting keyframes')
22 changes: 14 additions & 8 deletions packages/tailwindcss/src/compat/config/resolve-config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { resolveConfig } from './resolve-config'
test('top level theme keys are replaced', () => {
let design = buildDesignSystem(new Theme())

let config = resolveConfig(design, [
let { resolvedConfig, resetThemeKeys } = resolveConfig(design, [
{
config: {
theme: {
Expand Down Expand Up @@ -43,7 +43,7 @@ test('top level theme keys are replaced', () => {
},
])

expect(config).toMatchObject({
expect(resolvedConfig).toMatchObject({
theme: {
colors: {
blue: 'blue',
Expand All @@ -53,12 +53,13 @@ test('top level theme keys are replaced', () => {
},
},
})
expect(resetThemeKeys).toEqual(new Set(['colors', 'fontFamily']))
})

test('theme can be extended', () => {
let design = buildDesignSystem(new Theme())

let config = resolveConfig(design, [
let { resolvedConfig, resetThemeKeys } = resolveConfig(design, [
{
config: {
theme: {
Expand Down Expand Up @@ -87,7 +88,7 @@ test('theme can be extended', () => {
},
])

expect(config).toMatchObject({
expect(resolvedConfig).toMatchObject({
theme: {
colors: {
red: 'red',
Expand All @@ -98,14 +99,15 @@ test('theme can be extended', () => {
},
},
})
expect(resetThemeKeys).toEqual(new Set(['colors', 'fontFamily']))
})

test('theme keys can reference other theme keys using the theme function regardless of order', ({
expect,
}) => {
let design = buildDesignSystem(new Theme())

let config = resolveConfig(design, [
let { resolvedConfig, resetThemeKeys } = resolveConfig(design, [
{
config: {
theme: {
Expand Down Expand Up @@ -146,7 +148,7 @@ test('theme keys can reference other theme keys using the theme function regardl
},
])

expect(config).toMatchObject({
expect(resolvedConfig).toMatchObject({
theme: {
colors: {
red: 'red',
Expand All @@ -170,6 +172,7 @@ test('theme keys can reference other theme keys using the theme function regardl
},
},
})
expect(resetThemeKeys).toEqual(new Set(['colors', 'placeholderColor']))
})

test('theme keys can read from the CSS theme', () => {
Expand All @@ -178,7 +181,7 @@ test('theme keys can read from the CSS theme', () => {

let design = buildDesignSystem(theme)

let config = resolveConfig(design, [
let { resolvedConfig, resetThemeKeys } = resolveConfig(design, [
{
config: {
theme: {
Expand Down Expand Up @@ -212,7 +215,7 @@ test('theme keys can read from the CSS theme', () => {
},
])

expect(config).toMatchObject({
expect(resolvedConfig).toMatchObject({
theme: {
colors: {
red: 'red',
Expand Down Expand Up @@ -247,4 +250,7 @@ test('theme keys can read from the CSS theme', () => {
},
},
})
expect(resetThemeKeys).toEqual(
new Set(['colors', 'accentColor', 'placeholderColor', 'caretColor', 'transitionColor']),
)
})
34 changes: 27 additions & 7 deletions packages/tailwindcss/src/compat/config/resolve-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
type UserConfig,
} from './types'

type ResetThemeKeys = Set<string>

export interface ConfigFile {
path?: string
base: string
Expand Down Expand Up @@ -39,7 +41,10 @@ let minimal: ResolvedConfig = {
},
}

export function resolveConfig(design: DesignSystem, files: ConfigFile[]): ResolvedConfig {
export function resolveConfig(
design: DesignSystem,
files: ConfigFile[],
): { resolvedConfig: ResolvedConfig; resetThemeKeys: ResetThemeKeys } {
let ctx: ResolutionContext = {
design,
configs: [],
Expand Down Expand Up @@ -78,13 +83,16 @@ export function resolveConfig(design: DesignSystem, files: ConfigFile[]): Resolv
}

// Merge themes
mergeTheme(ctx)
let resetThemeKeys = mergeTheme(ctx)

return {
...ctx.result,
content: ctx.content,
theme: ctx.theme as ResolvedConfig['theme'],
plugins: ctx.plugins,
resolvedConfig: {
...ctx.result,
content: ctx.content,
theme: ctx.theme as ResolvedConfig['theme'],
plugins: ctx.plugins,
},
resetThemeKeys,
}
}

Expand Down Expand Up @@ -175,7 +183,9 @@ function extractConfigs(ctx: ResolutionContext, { config, base, path }: ConfigFi
ctx.configs.push(config)
}

function mergeTheme(ctx: ResolutionContext) {
function mergeTheme(ctx: ResolutionContext): ResetThemeKeys {
let resetThemeKeys: Set<string> = new Set()

let themeFn = createThemeFn(ctx.design, () => ctx.theme, resolveValue)
let theme = Object.assign(themeFn, {
theme: themeFn,
Expand All @@ -194,6 +204,14 @@ function mergeTheme(ctx: ResolutionContext) {
let theme = config.theme ?? {}
let extend = theme.extend ?? {}

// Keep track of all theme keys that were reset
for (let key in theme) {
if (key === 'extend') {
continue
}
resetThemeKeys.add(key)
}

// Shallow merge themes so latest "group" wins
Object.assign(ctx.theme, theme)

Expand Down Expand Up @@ -238,4 +256,6 @@ function mergeTheme(ctx: ResolutionContext) {
ctx.theme.screens[key] = screen.min
}
}

return resetThemeKeys
}
Loading