Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
5 changes: 2 additions & 3 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 Expand Up @@ -2381,7 +2380,7 @@ test(
<div class="blur blur-xs"></div>
<div class="backdrop-blur backdrop-blur-xs"></div>
<div class="rounded rounded-sm"></div>
<div class="ring"></div>
<div class="ring-3"></div>
Comment thread
thecrypticace marked this conversation as resolved.
Outdated
</div>
"
`)
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
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