Skip to content

Commit

Permalink
Properly resolve theme('someKey.DEFAULT') when only --some-key-*
Browse files Browse the repository at this point in the history
…keys exist (#14354)

This PR fixes an issue where theme function calls like
`theme('transitionTimingFunction.DEFAULT')` would incorrectly resolve to
an object when the set of defined CSS theme values looked like this:

```css
@theme {
  --transition-timing-function-in: ease-in;
  --transition-timing-function-out: ease-out;
  --transition-timing-function-in-out: ease-out;
}
```

We were mistakenly retrieving the entire
`--transition-timing-function-*` namespace in this case and returning an
object, even though the user is explicitly asking for a single value by
including `.DEFAULT` in their call.

This ensures it resolves to null instead. Fixes an issue I ran into on
this live stream earlier today:

https://x.com/adamwathan/status/1831740214051799281

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
  • Loading branch information
adamwathan and adamwathan authored Sep 6, 2024
1 parent f028eae commit 7b59aac
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed

- Ensure there is always CLI feedback on save even when no new classes were found ([#14351](https://github.com/tailwindlabs/tailwindcss/pull/14351))
- Properly resolve `theme('someKey.DEFAULT')` when all `--some-key-*` keys have a suffix ([#14354](https://github.com/tailwindlabs/tailwindcss/pull/14354))

## [4.0.0-alpha.23] - 2024-09-05

Expand Down
27 changes: 13 additions & 14 deletions packages/tailwindcss/src/compat/plugin-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ function readFromCss(theme: Theme, path: string[]) {
}

// We have to turn the map into object-like structure for v3 compatibility
let obj = {}
let obj: Record<string, unknown> = {}
let useNestedObjects = false // paths.some((path) => nestedKeys.has(path))

for (let [key, value] of map) {
Expand All @@ -134,20 +134,19 @@ function readFromCss(theme: Theme, path: string[]) {
set(obj, path, value)
}

if ('DEFAULT' in obj) {
// The request looked like `theme('animation.DEFAULT')` and was turned into
// a lookup for `--animation-*` and we should extract the value for the
// `DEFAULT` key from the list of possible values
if (path[path.length - 1] === 'DEFAULT') {
return obj.DEFAULT
}
// If the request looked like `theme('animation.DEFAULT')` it would have been
// turned into a lookup for `--animation-*` so we should extract the value for
// the `DEFAULT` key from the list of possible values. If there is no
// `DEFAULT` in the list, there is no match so return `null`.
if (path[path.length - 1] === 'DEFAULT') {
return obj?.DEFAULT ?? null
}

// The request looked like `theme('animation.spin')` and was turned into a
// lookup for `--animation-spin-*` which had only one entry which means it
// should be returned directly
if (Object.keys(obj).length === 1) {
return obj.DEFAULT
}
// The request looked like `theme('animation.spin')` and was turned into a
// lookup for `--animation-spin-*` which had only one entry which means it
// should be returned directly.
if ('DEFAULT' in obj && Object.keys(obj).length === 1) {
return obj.DEFAULT
}

return obj
Expand Down
29 changes: 29 additions & 0 deletions packages/tailwindcss/src/plugin-api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,35 @@ describe('theme', async () => {
expect(fn).toHaveBeenCalledWith('blue')
})

test("`theme('*.DEFAULT')` resolves to `undefined` when all theme keys in that namespace have a suffix", async ({
expect,
}) => {
let input = css`
@tailwind utilities;
@plugin "my-plugin";
@theme {
--transition-timing-function-in: ease-in;
--transition-timing-function-out: ease-out;
}
`

let fn = vi.fn()

await compile(input, {
loadPlugin: async () => {
return plugin(({ theme }) => {
fn(theme('transitionTimingFunction.DEFAULT'))
fn(theme('transitionTimingFunction.in'))
fn(theme('transitionTimingFunction.out'))
})
},
})

expect(fn).toHaveBeenNthCalledWith(1, undefined)
expect(fn).toHaveBeenNthCalledWith(2, 'ease-in')
expect(fn).toHaveBeenNthCalledWith(3, 'ease-out')
})

test('nested theme key lookups work even for flattened keys', async ({ expect }) => {
let input = css`
@tailwind utilities;
Expand Down

0 comments on commit 7b59aac

Please sign in to comment.