Sort classes using position of first matching rule (#11504)

* Refactor

* Sort based on first occurence of a candidate

This primarily affects components and utilities which contain multiple matched classes

* Simplify

* Update changelog

* Update
This commit is contained in:
Jordan Pittman 2023-06-29 09:49:53 -04:00
parent 243226887f
commit 80f3e85fa0
3 changed files with 44 additions and 1 deletions

View File

@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Ensure `repeating-conic-gradient` is detected as an image ([#11180](https://github.com/tailwindlabs/tailwindcss/pull/11180))
- Move unknown pseudo-elements outside of `:is` by default ([#11345](https://github.com/tailwindlabs/tailwindcss/pull/11345))
- Escape animation names when prefixes contain special characters ([#11470](https://github.com/tailwindlabs/tailwindcss/pull/11470))
- Sort classes using position of first matching rule ([#11504](https://github.com/tailwindlabs/tailwindcss/pull/11504))
### Added

View File

@ -949,7 +949,11 @@ function registerPlugins(plugins, context) {
let idx = BigInt(parasiteUtilities.length)
for (const [, rule] of rules) {
sortedClassNames.set(rule.raws.tailwind.candidate, idx++)
let candidate = rule.raws.tailwind.candidate
// When multiple rules match a candidate
// always take the position of the first one
sortedClassNames.set(candidate, sortedClassNames.get(candidate) ?? idx++)
}
return classes.map((className) => {

View File

@ -143,3 +143,41 @@ crosscheck(() => {
}
})
})
it('sorts based on first occurence of a candidate / rule', () => {
let classes = [
['foo-1 foo', 'foo foo-1'],
['bar', 'bar'],
['foo-1 foo', 'foo foo-1'],
]
let config = {
theme: {},
plugins: [
function ({ addComponents }) {
addComponents({
'.foo': { display: 'block' },
'.foo-1': { display: 'block' },
'.bar': { display: 'block' },
// This rule matches both the candidate `foo` and `bar`
// But when sorting `foo` — we've already got a
// position for `foo` so we should use it
'.bar .foo': { display: 'block' },
})
},
],
}
// Same context, different class lists
let context = createContext(resolveConfig(config))
for (const [input, output] of classes) {
expect(defaultSort(context.getClassOrder(input.split(' ')))).toEqual(output)
}
// Different context, different class lists
for (const [input, output] of classes) {
context = createContext(resolveConfig(config))
expect(defaultSort(context.getClassOrder(input.split(' ')))).toEqual(output)
}
})