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

Consider earlier variants before sorting functions #10288

Merged
merged 2 commits into from
Jan 10, 2023
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 @@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix perf regression when checking for changed content ([#10234](https://github.com/tailwindlabs/tailwindcss/pull/10234))
- Fix missing `blocklist` member in the `Config` type ([#10239](https://github.com/tailwindlabs/tailwindcss/pull/10239))
- Escape group names in selectors ([#10276](https://github.com/tailwindlabs/tailwindcss/pull/10276))
- Consider earlier variants before sorting functions ([#10288](https://github.com/tailwindlabs/tailwindcss/pull/10288))

### Changed

Expand Down
16 changes: 16 additions & 0 deletions src/lib/offsets.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { remapBitfield } from './remap-bitfield.js'
* @property {function | undefined} sort The sort function
* @property {string|null} value The value we want to compare
* @property {string|null} modifier The modifier that was used (if any)
* @property {bigint} variant The variant bitmask
*/

/**
Expand Down Expand Up @@ -127,6 +128,8 @@ export class Offsets {
* @returns {RuleOffset}
*/
applyVariantOffset(rule, variant, options) {
options.variant = variant.variants

return {
...rule,
layer: 'variants',
Expand Down Expand Up @@ -211,6 +214,19 @@ export class Offsets {
for (let bOptions of b.options) {
if (aOptions.id !== bOptions.id) continue
if (!aOptions.sort || !bOptions.sort) continue

let maxFnVariant = max([aOptions.variant, bOptions.variant]) ?? 0n

// Create a mask of 0s from bits 1..N where N represents the mask of the Nth bit
let mask = ~(maxFnVariant | (maxFnVariant - 1n))
let aVariantsAfterFn = a.variants & mask
let bVariantsAfterFn = b.variants & mask

// If the variants the same, we _can_ sort them
if (aVariantsAfterFn !== bVariantsAfterFn) {
continue
}

let result = aOptions.sort(
{
value: aOptions.value,
Expand Down
198 changes: 198 additions & 0 deletions tests/arbitrary-variants.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1158,3 +1158,201 @@ it('Invalid arbitrary variants selectors should produce nothing instead of faili
expect(result.css).toMatchFormattedCss(css``)
})
})

it('should output responsive variants + stacked variants in the right order', () => {
let config = {
content: [
{
raw: html`
<div class="xl:p-1"></div>
<div class="md:[&_ul]:flex-row"></div>
<div class="[&_ul]:flex"></div>
<div class="[&_ul]:flex-col"></div>
`,
},
],
corePlugins: { preflight: false },
}

let input = css`
@tailwind utilities;
`

return run(input, config).then((result) => {
expect(result.css).toMatchFormattedCss(css`
@media (min-width: 1280px) {
.xl\:p-1 {
padding: 0.25rem;
}
}
.\[\&_ul\]\:flex ul {
display: flex;
}
.\[\&_ul\]\:flex-col ul {
flex-direction: column;
}
@media (min-width: 768px) {
.md\:\[\&_ul\]\:flex-row ul {
flex-direction: row;
}
}
`)
})
})

it('should sort multiple variant fns with normal variants between them', () => {
/** @type {string[]} */
let lines = []

for (let a of [1, 2]) {
for (let b of [2, 1]) {
for (let c of [1, 2]) {
for (let d of [2, 1]) {
for (let e of [1, 2]) {
lines.push(`<div class="fred${a}:qux-[${b}]:baz${c}:bar-[${d}]:foo${e}:p-1"></div>`)
}
}
}
}
}

// Fisher-Yates shuffle
for (let i = lines.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * i)
;[lines[i], lines[j]] = [lines[j], lines[i]]
}

let config = {
content: [
{
raw: lines.join('\n'),
},
],
corePlugins: { preflight: false },
plugins: [
function ({ addVariant, matchVariant }) {
addVariant('foo1', '&[data-foo=1]')
addVariant('foo2', '&[data-foo=2]')

matchVariant('bar', (value) => `&[data-bar=${value}]`, {
sort: (a, b) => b.value - a.value,
})

addVariant('baz1', '&[data-baz=1]')
addVariant('baz2', '&[data-baz=2]')

matchVariant('qux', (value) => `&[data-qux=${value}]`, {
sort: (a, b) => b.value - a.value,
})

addVariant('fred1', '&[data-fred=1]')
addVariant('fred2', '&[data-fred=2]')
},
],
}

let input = css`
@tailwind utilities;
`

return run(input, config).then((result) => {
expect(result.css).toMatchFormattedCss(css`
.fred1\:qux-\[2\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='1'] {
padding: 0.25rem;
}
.fred1\:qux-\[2\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='1'] {
padding: 0.25rem;
}
.fred1\:qux-\[2\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='1'] {
padding: 0.25rem;
}
.fred1\:qux-\[2\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='1'] {
padding: 0.25rem;
}
.fred1\:qux-\[2\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='1'] {
padding: 0.25rem;
}
.fred1\:qux-\[2\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='1'] {
padding: 0.25rem;
}
.fred1\:qux-\[2\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='1'] {
padding: 0.25rem;
}
.fred1\:qux-\[2\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='1'] {
padding: 0.25rem;
}
.fred1\:qux-\[1\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='1'] {
padding: 0.25rem;
}
.fred1\:qux-\[1\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='1'] {
padding: 0.25rem;
}
.fred1\:qux-\[1\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='1'] {
padding: 0.25rem;
}
.fred1\:qux-\[1\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='1'] {
padding: 0.25rem;
}
.fred1\:qux-\[1\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='1'] {
padding: 0.25rem;
}
.fred1\:qux-\[1\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='1'] {
padding: 0.25rem;
}
.fred1\:qux-\[1\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='1'] {
padding: 0.25rem;
}
.fred1\:qux-\[1\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='1'] {
padding: 0.25rem;
}
.fred2\:qux-\[2\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='2'] {
padding: 0.25rem;
}
.fred2\:qux-\[2\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='2'] {
padding: 0.25rem;
}
.fred2\:qux-\[2\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='2'] {
padding: 0.25rem;
}
.fred2\:qux-\[2\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='2'] {
padding: 0.25rem;
}
.fred2\:qux-\[2\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='2'] {
padding: 0.25rem;
}
.fred2\:qux-\[2\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='2'] {
padding: 0.25rem;
}
.fred2\:qux-\[2\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='2'] {
padding: 0.25rem;
}
.fred2\:qux-\[2\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='2'] {
padding: 0.25rem;
}
.fred2\:qux-\[1\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='2'] {
padding: 0.25rem;
}
.fred2\:qux-\[1\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='2'] {
padding: 0.25rem;
}
.fred2\:qux-\[1\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='2'] {
padding: 0.25rem;
}
.fred2\:qux-\[1\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='2'] {
padding: 0.25rem;
}
.fred2\:qux-\[1\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='2'] {
padding: 0.25rem;
}
.fred2\:qux-\[1\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='2'] {
padding: 0.25rem;
}
.fred2\:qux-\[1\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='2'] {
padding: 0.25rem;
}
.fred2\:qux-\[1\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='2'] {
padding: 0.25rem;
}
`)
})
})