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

Support sort function in matchVariant #9423

Merged
merged 2 commits into from Sep 26, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Don't emit generated utilities with invalid uses of theme functions ([#9319](https://github.com/tailwindlabs/tailwindcss/pull/9319))
- Revert change that only listened for stdin close on TTYs ([#9331](https://github.com/tailwindlabs/tailwindcss/pull/9331))
- Ignore unset values (like `null` or `undefined`) when resolving the classList for intellisense ([#9385](https://github.com/tailwindlabs/tailwindcss/pull/9385))
- Support `sort` function in `matchVariant` ([#9423](https://github.com/tailwindlabs/tailwindcss/pull/9423))

## [3.1.8] - 2022-08-05

Expand Down
6 changes: 5 additions & 1 deletion src/lib/generateRules.js
Expand Up @@ -294,7 +294,11 @@ function applyVariant(variant, matches, context) {
let withOffset = [
{
...meta,
sort: context.offsets.applyVariantOffset(meta.sort, variantSort),
sort: context.offsets.applyVariantOffset(
meta.sort,
variantSort,
Object.assign({ value: args }, context.variantOptions.get(variant))
),
collectedFormats: (meta.collectedFormats ?? []).concat(collectedFormats),
isArbitraryVariant: isArbitraryValue(variant),
},
Expand Down
25 changes: 23 additions & 2 deletions src/lib/offsets.js
Expand Up @@ -6,6 +6,13 @@ import bigSign from '../util/bigSign'
* @typedef {'base' | 'defaults' | 'components' | 'utilities' | 'variants' | 'user'} Layer
*/

/**
* @typedef {object} VariantOption
* @property {number} id An unique identifier to identify `matchVariant`
* @property {function | undefined} sort The sort function
* @property {string} value The value we want to compare
*/

/**
* @typedef {object} RuleOffset
* @property {Layer} layer The layer that this rule belongs to
Expand All @@ -14,6 +21,7 @@ import bigSign from '../util/bigSign'
* @property {bigint} variants Dynamic size. 1 bit per registered variant. 0n means no variants
* @property {bigint} parallelIndex Rule index for the parallel variant. 0 if not applicable.
* @property {bigint} index Index of the rule / utility in it's given *parent* layer. Monotonically increasing.
* @property {VariantOption[]} options Some information on how we can sort arbitrary variants
*/

export class Offsets {
Expand Down Expand Up @@ -77,6 +85,7 @@ export class Offsets {
variants: 0n,
parallelIndex: 0n,
index: this.offsets[layer]++,
options: [],
}
}

Expand Down Expand Up @@ -112,14 +121,16 @@ export class Offsets {
/**
* @param {RuleOffset} rule
* @param {RuleOffset} variant
* @param {VariantOption} options
* @returns {RuleOffset}
*/
applyVariantOffset(rule, variant) {
applyVariantOffset(rule, variant, options) {
return {
...rule,
layer: 'variants',
parentLayer: rule.layer === 'variants' ? rule.parentLayer : rule.layer,
variants: rule.variants | variant.variants,
options: options.sort ? [].concat(options, rule.options) : rule.options,

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

// Sort based on the sorting function
for (let aOptions of a.options) {
for (let bOptions of b.options) {
if (aOptions.id !== bOptions.id) continue
if (!aOptions.sort || !bOptions.sort) continue
let result = aOptions.sort(aOptions.value, bOptions.value)
if (result !== 0) return result
}
}

// Sort variants in the order they were registered
if (a.variants !== b.variants) {
return a.variants - b.variants
Expand Down
9 changes: 7 additions & 2 deletions src/lib/setupContextUtils.js
Expand Up @@ -496,19 +496,23 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs

insertInto(variantList, variantName, options)
variantMap.set(variantName, variantFunctions)
context.variantOptions.set(variantName, options)
},
}

if (flagEnabled(tailwindConfig, 'matchVariant')) {
let variantIdentifier = 0
api.matchVariant = function (variant, variantFn, options) {
let id = ++variantIdentifier // A unique identifier that "groups" these variables together.

for (let [key, value] of Object.entries(options?.values ?? {})) {
api.addVariant(`${variant}-${key}`, variantFn({ value }))
api.addVariant(`${variant}-${key}`, variantFn({ value }), { ...options, value, id })
}

api.addVariant(
variant,
Object.assign(({ args }) => variantFn({ value: args }), { [MATCH_VARIANT]: true }),
options
{ ...options, id }
)
}
}
Expand Down Expand Up @@ -919,6 +923,7 @@ export function createContext(tailwindConfig, changedContent = [], root = postcs
changedContent: changedContent,
variantMap: new Map(),
stylesheetCache: null,
variantOptions: new Map(),

markInvalidUtilityCandidate: (candidate) => markInvalidUtilityCandidate(context, candidate),
markInvalidUtilityNode: (node) => markInvalidUtilityNode(context, node),
Expand Down