diff --git a/CHANGELOG.md b/CHANGELOG.md index 560a1bb2c..8f898437c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added 'place-content-baseline' utility ([#9498](https://github.com/tailwindlabs/tailwindcss/pull/9498)) - Added 'place-items-baseline' utility ([#9507](https://github.com/tailwindlabs/tailwindcss/pull/9507)) - Added 'content-baseline' utility ([#9507](https://github.com/tailwindlabs/tailwindcss/pull/9507)) +- Prepare for container queries setup ([#9526](https://github.com/tailwindlabs/tailwindcss/pull/9526)) ### Fixed diff --git a/src/lib/defaultExtractor.js b/src/lib/defaultExtractor.js index 3aec2e562..965e644d2 100644 --- a/src/lib/defaultExtractor.js +++ b/src/lib/defaultExtractor.js @@ -71,6 +71,9 @@ function* buildRegExps(context) { let variantPatterns = [ // Without quotes regex.any([ + // This is here to provide special support for the `@` variant + regex.pattern([/@\[[^\s"'`]+\](\/[^\s"'`]+)?/, separator]), + regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s"'`]+\]/, separator]), regex.pattern([/[^\s"'`\[\\]+/, separator]), ]), diff --git a/src/lib/generateRules.js b/src/lib/generateRules.js index f70af7839..202004903 100644 --- a/src/lib/generateRules.js +++ b/src/lib/generateRules.js @@ -128,7 +128,8 @@ function applyVariant(variant, matches, context) { return matches } - let args = {} + /** @type {{modifier: string | null, value: string | null}} */ + let args = { modifier: null, value: null } // Retrieve "modifier" { diff --git a/src/lib/offsets.js b/src/lib/offsets.js index f55c2a03f..eaa1fe6dd 100644 --- a/src/lib/offsets.js +++ b/src/lib/offsets.js @@ -10,7 +10,8 @@ import bigSign from '../util/bigSign' * @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 + * @property {string|null} value The value we want to compare + * @property {string|null} modifier The modifier that was used (if any) */ /** @@ -209,7 +210,16 @@ export class Offsets { 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) + let result = aOptions.sort( + { + value: aOptions.value, + modifier: aOptions.modifier, + }, + { + value: bOptions.value, + modifier: bOptions.modifier, + } + ) if (result !== 0) return result } } diff --git a/src/lib/setupContextUtils.js b/src/lib/setupContextUtils.js index fb51e06eb..fa0969ffb 100644 --- a/src/lib/setupContextUtils.js +++ b/src/lib/setupContextUtils.js @@ -520,10 +520,11 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs }, matchVariant(variant, variantFn, options) { let id = ++variantIdentifier // A unique identifier that "groups" these variables together. + let isSpecial = variant === '@' for (let [key, value] of Object.entries(options?.values ?? {})) { api.addVariant( - `${variant}-${key}`, + isSpecial ? `${variant}${key}` : `${variant}-${key}`, Object.assign(({ args, container }) => variantFn({ ...args, container, value }), { [MATCH_VARIANT]: true, }), diff --git a/tests/match-variants.test.js b/tests/match-variants.test.js index e881613c5..7b80a0639 100644 --- a/tests/match-variants.test.js +++ b/tests/match-variants.test.js @@ -245,7 +245,7 @@ it('should be possible to sort variants', () => { ({ matchVariant }) => { matchVariant('min', ({ value }) => `@media (min-width: ${value})`, { sort(a, z) { - return parseInt(a) - parseInt(z) + return parseInt(a.value) - parseInt(z.value) }, }) }, @@ -292,7 +292,7 @@ it('should be possible to compare arbitrary variants and hardcoded variants', () example: '600px', }, sort(a, z) { - return parseInt(a) - parseInt(z) + return parseInt(a.value) - parseInt(z.value) }, }) }, @@ -349,13 +349,13 @@ it('should be possible to sort stacked arbitrary variants correctly', () => { ({ matchVariant }) => { matchVariant('min', ({ value }) => `@media (min-width: ${value})`, { sort(a, z) { - return parseInt(a) - parseInt(z) + return parseInt(a.value) - parseInt(z.value) }, }) matchVariant('max', ({ value }) => `@media (max-width: ${value})`, { sort(a, z) { - return parseInt(z) - parseInt(a) + return parseInt(z.value) - parseInt(a.value) }, }) }, @@ -414,13 +414,13 @@ it('should maintain sort from other variants, if sort functions of arbitrary var ({ matchVariant }) => { matchVariant('min', ({ value }) => `@media (min-width: ${value})`, { sort(a, z) { - return parseInt(a) - parseInt(z) + return parseInt(a.value) - parseInt(z.value) }, }) matchVariant('max', ({ value }) => `@media (max-width: ${value})`, { sort(a, z) { - return parseInt(z) - parseInt(a) + return parseInt(z.value) - parseInt(a.value) }, }) }, @@ -466,12 +466,12 @@ it('should sort arbitrary variants left to right (1)', () => { ({ matchVariant }) => { matchVariant('min', ({ value }) => `@media (min-width: ${value})`, { sort(a, z) { - return parseInt(a) - parseInt(z) + return parseInt(a.value) - parseInt(z.value) }, }) matchVariant('max', ({ value }) => `@media (max-width: ${value})`, { sort(a, z) { - return parseInt(z) - parseInt(a) + return parseInt(z.value) - parseInt(a.value) }, }) }, @@ -534,12 +534,12 @@ it('should sort arbitrary variants left to right (2)', () => { ({ matchVariant }) => { matchVariant('min', ({ value }) => `@media (min-width: ${value})`, { sort(a, z) { - return parseInt(a) - parseInt(z) + return parseInt(a.value) - parseInt(z.value) }, }) matchVariant('max', ({ value }) => `@media (max-width: ${value})`, { sort(a, z) { - return parseInt(z) - parseInt(a) + return parseInt(z.value) - parseInt(a.value) }, }) }, @@ -601,19 +601,19 @@ it('should guarantee that we are not passing values from other variants to the w matchVariant('min', ({ value }) => `@media (min-width: ${value})`, { sort(a, z) { let lookup = ['100px', '200px'] - if (lookup.indexOf(a) === -1 || lookup.indexOf(z) === -1) { + if (lookup.indexOf(a.value) === -1 || lookup.indexOf(z.value) === -1) { throw new Error('We are seeing values that should not be there!') } - return lookup.indexOf(a) - lookup.indexOf(z) + return lookup.indexOf(a.value) - lookup.indexOf(z.value) }, }) matchVariant('max', ({ value }) => `@media (max-width: ${value})`, { sort(a, z) { let lookup = ['300px', '400px'] - if (lookup.indexOf(a) === -1 || lookup.indexOf(z) === -1) { + if (lookup.indexOf(a.value) === -1 || lookup.indexOf(z.value) === -1) { throw new Error('We are seeing values that should not be there!') } - return lookup.indexOf(z) - lookup.indexOf(a) + return lookup.indexOf(z.value) - lookup.indexOf(a.value) }, }) }, diff --git a/types/config.d.ts b/types/config.d.ts index 806cde42a..4ea61e7da 100644 --- a/types/config.d.ts +++ b/types/config.d.ts @@ -296,7 +296,21 @@ export interface PluginAPI { addBase(base: CSSRuleObject | CSSRuleObject[]): void // for registering custom variants addVariant(name: string, definition: string | string[] | (() => string) | (() => string)[]): void - matchVariant(name: string, cb: (options: { value: string }) => string | string[]): void + matchVariant( + name: string, + cb: (options: { value: string; modifier: string | null }) => string | string[] + ): void + matchVariant( + name: string, + cb: (options: { value: string; modifier: string | null }) => string | string[], + options: { + values: Values + sort( + a: { value: keyof Values | string; modifier: string | null }, + b: { value: keyof Values | string; modifier: string | null } + ): number + } + ): void // for looking up values in the user’s theme configuration theme: ( path?: string,