Skip to content

Commit 6f45428

Browse files
Consider earlier variants before sorting functions (#10288)
* Consider earlier variants before sorting functions Co-authored-by: Robin Malfait <[email protected]> * Update changelog Co-authored-by: Robin Malfait <[email protected]>
1 parent b05918a commit 6f45428

File tree

3 files changed

+215
-0
lines changed

3 files changed

+215
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3535
- Fix perf regression when checking for changed content ([#10234](https://github.com/tailwindlabs/tailwindcss/pull/10234))
3636
- Fix missing `blocklist` member in the `Config` type ([#10239](https://github.com/tailwindlabs/tailwindcss/pull/10239))
3737
- Escape group names in selectors ([#10276](https://github.com/tailwindlabs/tailwindcss/pull/10276))
38+
- Consider earlier variants before sorting functions ([#10288](https://github.com/tailwindlabs/tailwindcss/pull/10288))
3839

3940
### Changed
4041

src/lib/offsets.js

+16
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { remapBitfield } from './remap-bitfield.js'
1313
* @property {function | undefined} sort The sort function
1414
* @property {string|null} value The value we want to compare
1515
* @property {string|null} modifier The modifier that was used (if any)
16+
* @property {bigint} variant The variant bitmask
1617
*/
1718

1819
/**
@@ -127,6 +128,8 @@ export class Offsets {
127128
* @returns {RuleOffset}
128129
*/
129130
applyVariantOffset(rule, variant, options) {
131+
options.variant = variant.variants
132+
130133
return {
131134
...rule,
132135
layer: 'variants',
@@ -211,6 +214,19 @@ export class Offsets {
211214
for (let bOptions of b.options) {
212215
if (aOptions.id !== bOptions.id) continue
213216
if (!aOptions.sort || !bOptions.sort) continue
217+
218+
let maxFnVariant = max([aOptions.variant, bOptions.variant]) ?? 0n
219+
220+
// Create a mask of 0s from bits 1..N where N represents the mask of the Nth bit
221+
let mask = ~(maxFnVariant | (maxFnVariant - 1n))
222+
let aVariantsAfterFn = a.variants & mask
223+
let bVariantsAfterFn = b.variants & mask
224+
225+
// If the variants the same, we _can_ sort them
226+
if (aVariantsAfterFn !== bVariantsAfterFn) {
227+
continue
228+
}
229+
214230
let result = aOptions.sort(
215231
{
216232
value: aOptions.value,

tests/arbitrary-variants.test.js

+198
Original file line numberDiff line numberDiff line change
@@ -1158,3 +1158,201 @@ it('Invalid arbitrary variants selectors should produce nothing instead of faili
11581158
expect(result.css).toMatchFormattedCss(css``)
11591159
})
11601160
})
1161+
1162+
it('should output responsive variants + stacked variants in the right order', () => {
1163+
let config = {
1164+
content: [
1165+
{
1166+
raw: html`
1167+
<div class="xl:p-1"></div>
1168+
<div class="md:[&_ul]:flex-row"></div>
1169+
<div class="[&_ul]:flex"></div>
1170+
<div class="[&_ul]:flex-col"></div>
1171+
`,
1172+
},
1173+
],
1174+
corePlugins: { preflight: false },
1175+
}
1176+
1177+
let input = css`
1178+
@tailwind utilities;
1179+
`
1180+
1181+
return run(input, config).then((result) => {
1182+
expect(result.css).toMatchFormattedCss(css`
1183+
@media (min-width: 1280px) {
1184+
.xl\:p-1 {
1185+
padding: 0.25rem;
1186+
}
1187+
}
1188+
.\[\&_ul\]\:flex ul {
1189+
display: flex;
1190+
}
1191+
.\[\&_ul\]\:flex-col ul {
1192+
flex-direction: column;
1193+
}
1194+
@media (min-width: 768px) {
1195+
.md\:\[\&_ul\]\:flex-row ul {
1196+
flex-direction: row;
1197+
}
1198+
}
1199+
`)
1200+
})
1201+
})
1202+
1203+
it('should sort multiple variant fns with normal variants between them', () => {
1204+
/** @type {string[]} */
1205+
let lines = []
1206+
1207+
for (let a of [1, 2]) {
1208+
for (let b of [2, 1]) {
1209+
for (let c of [1, 2]) {
1210+
for (let d of [2, 1]) {
1211+
for (let e of [1, 2]) {
1212+
lines.push(`<div class="fred${a}:qux-[${b}]:baz${c}:bar-[${d}]:foo${e}:p-1"></div>`)
1213+
}
1214+
}
1215+
}
1216+
}
1217+
}
1218+
1219+
// Fisher-Yates shuffle
1220+
for (let i = lines.length - 1; i > 0; i--) {
1221+
let j = Math.floor(Math.random() * i)
1222+
;[lines[i], lines[j]] = [lines[j], lines[i]]
1223+
}
1224+
1225+
let config = {
1226+
content: [
1227+
{
1228+
raw: lines.join('\n'),
1229+
},
1230+
],
1231+
corePlugins: { preflight: false },
1232+
plugins: [
1233+
function ({ addVariant, matchVariant }) {
1234+
addVariant('foo1', '&[data-foo=1]')
1235+
addVariant('foo2', '&[data-foo=2]')
1236+
1237+
matchVariant('bar', (value) => `&[data-bar=${value}]`, {
1238+
sort: (a, b) => b.value - a.value,
1239+
})
1240+
1241+
addVariant('baz1', '&[data-baz=1]')
1242+
addVariant('baz2', '&[data-baz=2]')
1243+
1244+
matchVariant('qux', (value) => `&[data-qux=${value}]`, {
1245+
sort: (a, b) => b.value - a.value,
1246+
})
1247+
1248+
addVariant('fred1', '&[data-fred=1]')
1249+
addVariant('fred2', '&[data-fred=2]')
1250+
},
1251+
],
1252+
}
1253+
1254+
let input = css`
1255+
@tailwind utilities;
1256+
`
1257+
1258+
return run(input, config).then((result) => {
1259+
expect(result.css).toMatchFormattedCss(css`
1260+
.fred1\:qux-\[2\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='1'] {
1261+
padding: 0.25rem;
1262+
}
1263+
.fred1\:qux-\[2\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='1'] {
1264+
padding: 0.25rem;
1265+
}
1266+
.fred1\:qux-\[2\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='1'] {
1267+
padding: 0.25rem;
1268+
}
1269+
.fred1\:qux-\[2\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='1'] {
1270+
padding: 0.25rem;
1271+
}
1272+
.fred1\:qux-\[2\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='1'] {
1273+
padding: 0.25rem;
1274+
}
1275+
.fred1\:qux-\[2\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='1'] {
1276+
padding: 0.25rem;
1277+
}
1278+
.fred1\:qux-\[2\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='1'] {
1279+
padding: 0.25rem;
1280+
}
1281+
.fred1\:qux-\[2\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='1'] {
1282+
padding: 0.25rem;
1283+
}
1284+
.fred1\:qux-\[1\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='1'] {
1285+
padding: 0.25rem;
1286+
}
1287+
.fred1\:qux-\[1\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='1'] {
1288+
padding: 0.25rem;
1289+
}
1290+
.fred1\:qux-\[1\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='1'] {
1291+
padding: 0.25rem;
1292+
}
1293+
.fred1\:qux-\[1\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='1'] {
1294+
padding: 0.25rem;
1295+
}
1296+
.fred1\:qux-\[1\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='1'] {
1297+
padding: 0.25rem;
1298+
}
1299+
.fred1\:qux-\[1\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='1'] {
1300+
padding: 0.25rem;
1301+
}
1302+
.fred1\:qux-\[1\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='1'] {
1303+
padding: 0.25rem;
1304+
}
1305+
.fred1\:qux-\[1\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='1'] {
1306+
padding: 0.25rem;
1307+
}
1308+
.fred2\:qux-\[2\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='2'] {
1309+
padding: 0.25rem;
1310+
}
1311+
.fred2\:qux-\[2\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='2'] {
1312+
padding: 0.25rem;
1313+
}
1314+
.fred2\:qux-\[2\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='2'] {
1315+
padding: 0.25rem;
1316+
}
1317+
.fred2\:qux-\[2\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='2'] {
1318+
padding: 0.25rem;
1319+
}
1320+
.fred2\:qux-\[2\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='2'] {
1321+
padding: 0.25rem;
1322+
}
1323+
.fred2\:qux-\[2\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='2'] {
1324+
padding: 0.25rem;
1325+
}
1326+
.fred2\:qux-\[2\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='2'] {
1327+
padding: 0.25rem;
1328+
}
1329+
.fred2\:qux-\[2\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='2'] {
1330+
padding: 0.25rem;
1331+
}
1332+
.fred2\:qux-\[1\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='2'] {
1333+
padding: 0.25rem;
1334+
}
1335+
.fred2\:qux-\[1\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='2'] {
1336+
padding: 0.25rem;
1337+
}
1338+
.fred2\:qux-\[1\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='2'] {
1339+
padding: 0.25rem;
1340+
}
1341+
.fred2\:qux-\[1\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='2'] {
1342+
padding: 0.25rem;
1343+
}
1344+
.fred2\:qux-\[1\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='2'] {
1345+
padding: 0.25rem;
1346+
}
1347+
.fred2\:qux-\[1\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='2'] {
1348+
padding: 0.25rem;
1349+
}
1350+
.fred2\:qux-\[1\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='2'] {
1351+
padding: 0.25rem;
1352+
}
1353+
.fred2\:qux-\[1\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='2'] {
1354+
padding: 0.25rem;
1355+
}
1356+
`)
1357+
})
1358+
})

0 commit comments

Comments
 (0)