Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix non-deterministic variant sorting #14835

Merged
merged 10 commits into from
Oct 31, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Detect classes in new files when using `@tailwindcss/postcss` ([#14829](https://github.com/tailwindlabs/tailwindcss/pull/14829))
- Fix crash when using `@source` containing `..` ([#14831](https://github.com/tailwindlabs/tailwindcss/pull/14831))
- Ensure instances of the same variant with different values are always sorted deterministically (e.g. `data-focus:flex` and `data-active:flex`) ([#14835](https://github.com/tailwindlabs/tailwindcss/pull/14835))
- _Upgrade (experimental)_: Install `@tailwindcss/postcss` next to `tailwindcss` ([#14830](https://github.com/tailwindlabs/tailwindcss/pull/14830))
- _Upgrade (experimental)_: Remove whitespace around `,` separator when print arbitrary values ([#14838](https://github.com/tailwindlabs/tailwindcss/pull/14838))

Expand Down
12 changes: 6 additions & 6 deletions packages/tailwindcss/src/compat/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1109,16 +1109,16 @@ test('creates variants for `data`, `supports`, and `aria` theme options at the s
'print:flex',
]),
).toMatchInlineSnapshot(`
".aria-polite\\:underline {
&[aria-live="polite"] {
text-decoration-line: underline;
}
}
.aria-hidden\\:flex {
".aria-hidden\\:flex {
&[aria-hidden="true"] {
display: flex;
}
}
.aria-polite\\:underline {
&[aria-live="polite"] {
text-decoration-line: underline;
}
}
.data-checked\\:underline {
&[data-ui~="checked"] {
text-decoration-line: underline;
Expand Down
26 changes: 17 additions & 9 deletions packages/tailwindcss/src/compat/plugin-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,12 +156,12 @@ export function buildPluginApi(
if (a.kind !== 'functional' || z.kind !== 'functional') {
return 0
}
if (!a.value || !z.value) {
return 0
}

let aValue = options?.values?.[a.value.value] ?? a.value.value
let zValue = options?.values?.[z.value.value] ?? z.value.value
let aValueKey = a.value ? a.value.value : 'DEFAULT'
let zValueKey = z.value ? z.value.value : 'DEFAULT'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RobinMalfait I'm not 100% sold that this is the "right" fix. Thoughts?


let aValue = options?.values?.[aValueKey] ?? aValueKey
let zValue = options?.values?.[zValueKey] ?? zValueKey

if (options && typeof options.sort === 'function') {
return options.sort(
Expand All @@ -170,11 +170,19 @@ export function buildPluginApi(
)
}

let aOrder = defaultOptionKeys.indexOf(a.value.value)
let zOrder = defaultOptionKeys.indexOf(z.value.value)
let aOrder = defaultOptionKeys.indexOf(aValueKey)
let zOrder = defaultOptionKeys.indexOf(zValueKey)

// Sort arbitrary values after configured values
aOrder = aOrder === -1 ? defaultOptionKeys.length : aOrder
zOrder = zOrder === -1 ? defaultOptionKeys.length : zOrder

if (aOrder !== zOrder) return aOrder - zOrder

if (aOrder - zOrder === 0) return aValue < zValue ? -1 : 1
return aOrder - zOrder
// SAFETY: The values don't need to be checked for equality as they
// are guaranteed to be unique since we sort a list of de-duped
// variants and different (valid) variants cannot produce the same AST.
return aValue < zValue ? -1 : 1
},
)
},
Expand Down
Loading