Skip to content

Commit 26cab53

Browse files
authored
Support sort function in matchVariant (#9423)
* support `sort` function in `matchVariant` This will ensure that we can sort arbitrary variant values (and hardcoded values) to ensure the order. * update changelog
1 parent 19b86e6 commit 26cab53

File tree

5 files changed

+471
-5
lines changed

5 files changed

+471
-5
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3939
- Don't emit generated utilities with invalid uses of theme functions ([#9319](https://github.com/tailwindlabs/tailwindcss/pull/9319))
4040
- Revert change that only listened for stdin close on TTYs ([#9331](https://github.com/tailwindlabs/tailwindcss/pull/9331))
4141
- Ignore unset values (like `null` or `undefined`) when resolving the classList for intellisense ([#9385](https://github.com/tailwindlabs/tailwindcss/pull/9385))
42+
- Support `sort` function in `matchVariant` ([#9423](https://github.com/tailwindlabs/tailwindcss/pull/9423))
4243

4344
## [3.1.8] - 2022-08-05
4445

src/lib/generateRules.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,11 @@ function applyVariant(variant, matches, context) {
294294
let withOffset = [
295295
{
296296
...meta,
297-
sort: context.offsets.applyVariantOffset(meta.sort, variantSort),
297+
sort: context.offsets.applyVariantOffset(
298+
meta.sort,
299+
variantSort,
300+
Object.assign({ value: args }, context.variantOptions.get(variant))
301+
),
298302
collectedFormats: (meta.collectedFormats ?? []).concat(collectedFormats),
299303
isArbitraryVariant: isArbitraryValue(variant),
300304
},

src/lib/offsets.js

+23-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ import bigSign from '../util/bigSign'
66
* @typedef {'base' | 'defaults' | 'components' | 'utilities' | 'variants' | 'user'} Layer
77
*/
88

9+
/**
10+
* @typedef {object} VariantOption
11+
* @property {number} id An unique identifier to identify `matchVariant`
12+
* @property {function | undefined} sort The sort function
13+
* @property {string} value The value we want to compare
14+
*/
15+
916
/**
1017
* @typedef {object} RuleOffset
1118
* @property {Layer} layer The layer that this rule belongs to
@@ -14,6 +21,7 @@ import bigSign from '../util/bigSign'
1421
* @property {bigint} variants Dynamic size. 1 bit per registered variant. 0n means no variants
1522
* @property {bigint} parallelIndex Rule index for the parallel variant. 0 if not applicable.
1623
* @property {bigint} index Index of the rule / utility in it's given *parent* layer. Monotonically increasing.
24+
* @property {VariantOption[]} options Some information on how we can sort arbitrary variants
1725
*/
1826

1927
export class Offsets {
@@ -77,6 +85,7 @@ export class Offsets {
7785
variants: 0n,
7886
parallelIndex: 0n,
7987
index: this.offsets[layer]++,
88+
options: [],
8089
}
8190
}
8291

@@ -112,14 +121,16 @@ export class Offsets {
112121
/**
113122
* @param {RuleOffset} rule
114123
* @param {RuleOffset} variant
124+
* @param {VariantOption} options
115125
* @returns {RuleOffset}
116126
*/
117-
applyVariantOffset(rule, variant) {
127+
applyVariantOffset(rule, variant, options) {
118128
return {
119129
...rule,
120130
layer: 'variants',
121131
parentLayer: rule.layer === 'variants' ? rule.parentLayer : rule.layer,
122132
variants: rule.variants | variant.variants,
133+
options: options.sort ? [].concat(options, rule.options) : rule.options,
123134

124135
// TODO: Technically this is wrong. We should be handling parallel index on a per variant basis.
125136
// We'll take the max of all the parallel indexes for now.
@@ -151,7 +162,7 @@ export class Offsets {
151162
* @param {(name: string) => number} getLength
152163
*/
153164
recordVariants(variants, getLength) {
154-
for (const variant of variants) {
165+
for (let variant of variants) {
155166
this.recordVariant(variant, getLength(variant))
156167
}
157168
}
@@ -193,6 +204,16 @@ export class Offsets {
193204
return this.layerPositions[a.layer] - this.layerPositions[b.layer]
194205
}
195206

207+
// Sort based on the sorting function
208+
for (let aOptions of a.options) {
209+
for (let bOptions of b.options) {
210+
if (aOptions.id !== bOptions.id) continue
211+
if (!aOptions.sort || !bOptions.sort) continue
212+
let result = aOptions.sort(aOptions.value, bOptions.value)
213+
if (result !== 0) return result
214+
}
215+
}
216+
196217
// Sort variants in the order they were registered
197218
if (a.variants !== b.variants) {
198219
return a.variants - b.variants

src/lib/setupContextUtils.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -496,19 +496,23 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
496496

497497
insertInto(variantList, variantName, options)
498498
variantMap.set(variantName, variantFunctions)
499+
context.variantOptions.set(variantName, options)
499500
},
500501
}
501502

502503
if (flagEnabled(tailwindConfig, 'matchVariant')) {
504+
let variantIdentifier = 0
503505
api.matchVariant = function (variant, variantFn, options) {
506+
let id = ++variantIdentifier // A unique identifier that "groups" these variables together.
507+
504508
for (let [key, value] of Object.entries(options?.values ?? {})) {
505-
api.addVariant(`${variant}-${key}`, variantFn({ value }))
509+
api.addVariant(`${variant}-${key}`, variantFn({ value }), { ...options, value, id })
506510
}
507511

508512
api.addVariant(
509513
variant,
510514
Object.assign(({ args }) => variantFn({ value: args }), { [MATCH_VARIANT]: true }),
511-
options
515+
{ ...options, id }
512516
)
513517
}
514518
}
@@ -919,6 +923,7 @@ export function createContext(tailwindConfig, changedContent = [], root = postcs
919923
changedContent: changedContent,
920924
variantMap: new Map(),
921925
stylesheetCache: null,
926+
variantOptions: new Map(),
922927

923928
markInvalidUtilityCandidate: (candidate) => markInvalidUtilityCandidate(context, candidate),
924929
markInvalidUtilityNode: (node) => markInvalidUtilityNode(context, node),

0 commit comments

Comments
 (0)