Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Support environment API in `@tailwindcss/vite` ([#18970](https://github.com/tailwindlabs/tailwindcss/pull/18970))
- Preserve case of theme keys from JS configs and plugins ([#19337](https://github.com/tailwindlabs/tailwindcss/pull/19337))
- Write source maps correctly on the CLI when using `--watch` ([#19373](https://github.com/tailwindlabs/tailwindcss/pull/19373))
- Handle special defaults (like `ringColor.DEFAULT`) in JS configs ([#19348](https://github.com/tailwindlabs/tailwindcss/pull/19348))
- Upgrade: Handle `future` and `experimental` config keys ([#19344](https://github.com/tailwindlabs/tailwindcss/pull/19344))
- Try to canonicalize any arbitrary utility to a bare value ([#19379](https://github.com/tailwindlabs/tailwindcss/pull/19379))

Expand Down
3 changes: 1 addition & 2 deletions integrations/upgrade/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2347,8 +2347,7 @@ test(
--shadow-*: initial;
--shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);

--ring-width-*: initial;
--ring-width: 4px;
--default-ring-width: 4px;

--blur: var(--custom-default-blur);

Expand Down
5 changes: 5 additions & 0 deletions integrations/upgrade/js-config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ test(
steel: 'rgb(70 130 180 / <alpha-value>)',
smoke: 'rgba(245, 245, 245, var(--smoke-alpha, <alpha-value>))',
},
ringColor: {
DEFAULT: '#c0ffee',
},
opacity: {
superOpaque: '0.95',
},
Expand Down Expand Up @@ -191,6 +194,8 @@ test(
--color-steel: rgb(70 130 180);
--color-smoke: rgba(245, 245, 245, var(--smoke-alpha, 1));

--default-ring-color: #c0ffee;

--opacity-*: initial;
--opacity-superOpaque: 95%;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,16 +237,21 @@ async function migrateTheme(
prevSectionKey = sectionKey
}

if (resetNamespaces.has(key[0]) && resetNamespaces.get(key[0]) === false) {
resetNamespaces.set(key[0], true)
let property = keyPathToCssProperty([key[0]])
if (property !== null) {
themeSection.push(` ${escape(`--${property}`)}-*: initial;`)
}
}

let property = keyPathToCssProperty(key)

if (property !== null) {
if (
!property.startsWith('default-') &&
resetNamespaces.has(key[0]) &&
resetNamespaces.get(key[0]) === false
) {
resetNamespaces.set(key[0], true)
let ns = keyPathToCssProperty([key[0]])
if (ns !== null) {
themeSection.push(` ${escape(`--${ns}`)}-*: initial;`)
}
}

themeSection.push(` ${escape(`--${property}`)}: ${value};`)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const THEME_KEYS = new Map([
['backdrop-blur-sm', '--backdrop-blur-sm'],
['backdrop-blur-xs', '--backdrop-blur-xs'],

['ring', '--ring-width'],
['ring', '--default-ring-width'],
['ring-3', '--ring-width-3'],
])

Expand Down
35 changes: 35 additions & 0 deletions packages/tailwindcss/src/compat/apply-config-to-theme.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ test('config values can be merged into the theme', () => {
normal: '0 1px 3px black',
},

borderWidth: {
DEFAULT: '1.5px',
},
outlineWidth: {
DEFAULT: '2.5px',
},
ringWidth: {
DEFAULT: '3.5px',
},

borderRadius: {
sm: '0.33rem',
},
Expand All @@ -57,6 +67,10 @@ test('config values can be merged into the theme', () => {
'2xl': ['2rem'],
},

ringColor: {
DEFAULT: '#fff',
},

letterSpacing: {
superWide: '0.25em',
},
Expand All @@ -77,8 +91,12 @@ test('config values can be merged into the theme', () => {
},

transitionTimingFunction: {
DEFAULT: 'ease-in-out',
fast: 'cubic-bezier(0, 0.55, 0.45, 1)',
},
transitionDuration: {
DEFAULT: '1234ms',
},
},
},
base: '/root',
Expand Down Expand Up @@ -125,6 +143,23 @@ test('config values can be merged into the theme', () => {
expect(theme.resolve('100%', ['--width'])).toEqual('100%')
expect(theme.resolve('9xs', ['--container'])).toEqual('6rem')
expect(theme.resolve('fast', ['--ease'])).toEqual('cubic-bezier(0, 0.55, 0.45, 1)')

expect(theme.get(['--border'])).toEqual(null)
expect(theme.get(['--default-border-width'])).toEqual('1.5px')

expect(theme.get(['--outline'])).toEqual(null)
expect(theme.get(['--default-outline-width'])).toEqual('2.5px')

expect(theme.get(['--ring-color'])).toEqual(null)
expect(theme.get(['--default-ring-color'])).toEqual('#fff')

expect(theme.get(['--ring-width'])).toEqual(null)
expect(theme.get(['--default-ring-width'])).toEqual('3.5px')

expect(theme.get(['--default-transition-duration'])).toEqual('1234ms')

expect(theme.get(['--ease'])).toEqual(null)
expect(theme.get(['--default-transition-timing-function'])).toEqual('ease-in-out')
})

test('will reset default theme values with overwriting theme values', () => {
Expand Down
57 changes: 41 additions & 16 deletions packages/tailwindcss/src/compat/apply-config-to-theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,32 +147,57 @@ export function themeableValues(config: ResolvedConfig['theme']): [string[], unk
return toAdd
}

const SPECIAL_DEFAULT_KEYS: Record<string, string> = {
borderWidth: 'border-width',
outlineWidth: 'outline-width',
ringColor: 'ring-color',
ringWidth: 'ring-width',
transitionDuration: 'transition-duration',
transitionTimingFunction: 'transition-timing-function',
}

const OLD_TO_NEW_NAMESPACE: Record<string, string> = {
animation: 'animate',
aspectRatio: 'aspect',
borderRadius: 'radius',
boxShadow: 'shadow',
colors: 'color',
containers: 'container',
fontFamily: 'font',
fontSize: 'text',
letterSpacing: 'tracking',
lineHeight: 'leading',
maxWidth: 'container',
screens: 'breakpoint',
transitionTimingFunction: 'ease',
}

const IS_VALID_KEY = /^[a-zA-Z0-9-_%/\.]+$/

export function keyPathToCssProperty(path: string[]) {
// In some special cases the `DEFAULT` key did not map to a "default" utility
// e.g. `ringColor.DEFAULT` wasn't *just* used for `ring`. It was used for
// all ring utilities as the color when one wasn't specified.
//
// We place these specialty values under the `--default-*` namespace to signal
// that they are defaults used by (potentially) multiple utilities.
let specialDefault = SPECIAL_DEFAULT_KEYS[path[0]]
if (specialDefault && path[1] === 'DEFAULT') return `default-${specialDefault}`

// The legacy container component config should not be included in the Theme
if (path[0] === 'container') return null

path = path.slice()

if (path[0] === 'animation') path[0] = 'animate'
if (path[0] === 'aspectRatio') path[0] = 'aspect'
if (path[0] === 'borderRadius') path[0] = 'radius'
if (path[0] === 'boxShadow') path[0] = 'shadow'
if (path[0] === 'colors') path[0] = 'color'
if (path[0] === 'containers') path[0] = 'container'
if (path[0] === 'fontFamily') path[0] = 'font'
if (path[0] === 'fontSize') path[0] = 'text'
if (path[0] === 'letterSpacing') path[0] = 'tracking'
if (path[0] === 'lineHeight') path[0] = 'leading'
if (path[0] === 'maxWidth') path[0] = 'container'
if (path[0] === 'screens') path[0] = 'breakpoint'
if (path[0] === 'transitionTimingFunction') path[0] = 'ease'

for (let part of path) {
if (!IS_VALID_KEY.test(part)) return null
}

// Map old v3 namespaces to new theme namespaces
let ns = OLD_TO_NEW_NAMESPACE[path[0]]
if (ns) {
path = path.slice()
path[0] = ns
}

return (
path
// [1] should move into the nested object tuple. To create the CSS variable
Expand Down