Skip to content

Commit 005c1be

Browse files
Don't prefix arbitrary classes in peer/group variants (#11454)
* Refactor * Don’t prefix classes in arbitrary values for group and peer * use `foo` instead of `lol` * handle the prefix inside the group/peer variants Then add the `NoPrefix` feature to the variant itself, which will skip prefixing any other class in the generated selector (because we already took care of prefixing `.group` and `.peer`). We are using an internal symbol such that: - We can keep it as a private API - We don't introduce a breaking change * refactor to simple object instead We will still use a symbol as an internal/private marker, but the data itself will be a simple object for now. If we want to refactor this (and more) in the future using bitflags then we can refactor that in a separate PR. --------- Co-authored-by: Robin Malfait <[email protected]>
1 parent 5b9cbb3 commit 005c1be

9 files changed

+130
-57
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515
- Ensure `repeating-conic-gradient` is detected as an image ([#11180](https://github.com/tailwindlabs/tailwindcss/pull/11180))
1616
- Move unknown pseudo-elements outside of `:is` by default ([#11345](https://github.com/tailwindlabs/tailwindcss/pull/11345))
1717
- Escape animation names when prefixes contain special characters ([#11470](https://github.com/tailwindlabs/tailwindcss/pull/11470))
18+
- Don't prefix arbitrary classes in `group` and `peer` variants ([#11454](https://github.com/tailwindlabs/tailwindcss/pull/11454))
1819
- Sort classes using position of first matching rule ([#11504](https://github.com/tailwindlabs/tailwindcss/pull/11504))
1920
- Allow variant to be an at-rule without a prelude ([#11589](https://github.com/tailwindlabs/tailwindcss/pull/11589))
2021
- Make PostCSS plugin async to improve performance ([#11548](https://github.com/tailwindlabs/tailwindcss/pull/11548))

src/corePlugins.js

+12-6
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { formatBoxShadowValue, parseBoxShadowValue } from './util/parseBoxShadow
2222
import { removeAlphaVariables } from './util/removeAlphaVariables'
2323
import { flagEnabled } from './featureFlags'
2424
import { normalize } from './util/dataTypes'
25+
import { INTERNAL_FEATURES } from './lib/setupContextUtils'
2526

2627
export let variantPlugins = {
2728
pseudoElementVariants: ({ addVariant }) => {
@@ -80,7 +81,7 @@ export let variantPlugins = {
8081
})
8182
},
8283

83-
pseudoClassVariants: ({ addVariant, matchVariant, config }) => {
84+
pseudoClassVariants: ({ addVariant, matchVariant, config, prefix }) => {
8485
let pseudoVariants = [
8586
// Positional
8687
['first', '&:first-child'],
@@ -151,12 +152,12 @@ export let variantPlugins = {
151152
let variants = {
152153
group: (_, { modifier }) =>
153154
modifier
154-
? [`:merge(.group\\/${escapeClassName(modifier)})`, ' &']
155-
: [`:merge(.group)`, ' &'],
155+
? [`:merge(${prefix('.group')}\\/${escapeClassName(modifier)})`, ' &']
156+
: [`:merge(${prefix('.group')})`, ' &'],
156157
peer: (_, { modifier }) =>
157158
modifier
158-
? [`:merge(.peer\\/${escapeClassName(modifier)})`, ' ~ &']
159-
: [`:merge(.peer)`, ' ~ &'],
159+
? [`:merge(${prefix('.peer')}\\/${escapeClassName(modifier)})`, ' ~ &']
160+
: [`:merge(${prefix('.peer')})`, ' ~ &'],
160161
}
161162

162163
for (let [name, fn] of Object.entries(variants)) {
@@ -192,7 +193,12 @@ export let variantPlugins = {
192193

193194
return result.slice(0, start) + a + result.slice(start + 1, end) + b + result.slice(end)
194195
},
195-
{ values: Object.fromEntries(pseudoVariants) }
196+
{
197+
values: Object.fromEntries(pseudoVariants),
198+
[INTERNAL_FEATURES]: {
199+
respectPrefix: false,
200+
},
201+
}
196202
)
197203
}
198204
},

src/lib/generateRules.js

+11-4
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
} from '../util/formatVariantSelector'
1414
import { asClass } from '../util/nameClass'
1515
import { normalize } from '../util/dataTypes'
16-
import { isValidVariantFormatString, parseVariant } from './setupContextUtils'
16+
import { isValidVariantFormatString, parseVariant, INTERNAL_FEATURES } from './setupContextUtils'
1717
import isValidArbitraryValue from '../util/isSyntacticallyValidPropertyValue'
1818
import { splitAtTopLevelOnly } from '../util/splitAtTopLevelOnly.js'
1919
import { flagEnabled } from '../featureFlags'
@@ -230,9 +230,16 @@ function applyVariant(variant, matches, context) {
230230

231231
if (context.variantMap.has(variant)) {
232232
let isArbitraryVariant = isArbitraryValue(variant)
233+
let internalFeatures = context.variantOptions.get(variant)?.[INTERNAL_FEATURES] ?? {}
233234
let variantFunctionTuples = context.variantMap.get(variant).slice()
234235
let result = []
235236

237+
let respectPrefix = (() => {
238+
if (isArbitraryVariant) return false
239+
if (internalFeatures.respectPrefix === false) return false
240+
return true
241+
})()
242+
236243
for (let [meta, rule] of matches) {
237244
// Don't generate variants for user css
238245
if (meta.layer === 'user') {
@@ -293,7 +300,7 @@ function applyVariant(variant, matches, context) {
293300
format(selectorFormat) {
294301
collectedFormats.push({
295302
format: selectorFormat,
296-
isArbitraryVariant,
303+
respectPrefix,
297304
})
298305
},
299306
args,
@@ -322,7 +329,7 @@ function applyVariant(variant, matches, context) {
322329
if (typeof ruleWithVariant === 'string') {
323330
collectedFormats.push({
324331
format: ruleWithVariant,
325-
isArbitraryVariant,
332+
respectPrefix,
326333
})
327334
}
328335

@@ -366,7 +373,7 @@ function applyVariant(variant, matches, context) {
366373
// format: .foo &
367374
collectedFormats.push({
368375
format: modified.replace(rebuiltBase, '&'),
369-
isArbitraryVariant,
376+
respectPrefix,
370377
})
371378
rule.selector = before
372379
})

src/lib/setupContextUtils.js

+11-2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import { Offsets } from './offsets.js'
2424
import { flagEnabled } from '../featureFlags.js'
2525
import { finalizeSelector, formatVariantSelector } from '../util/formatVariantSelector'
2626

27+
export const INTERNAL_FEATURES = Symbol()
28+
2729
const VARIANT_TYPES = {
2830
AddVariant: Symbol.for('ADD_VARIANT'),
2931
MatchVariant: Symbol.for('MATCH_VARIANT'),
@@ -1123,17 +1125,24 @@ function registerPlugins(plugins, context) {
11231125
}
11241126

11251127
let isArbitraryVariant = !(value in (options.values ?? {}))
1128+
let internalFeatures = options[INTERNAL_FEATURES] ?? {}
1129+
1130+
let respectPrefix = (() => {
1131+
if (isArbitraryVariant) return false
1132+
if (internalFeatures.respectPrefix === false) return false
1133+
return true
1134+
})()
11261135

11271136
formatStrings = formatStrings.map((format) =>
11281137
format.map((str) => ({
11291138
format: str,
1130-
isArbitraryVariant,
1139+
respectPrefix,
11311140
}))
11321141
)
11331142

11341143
manualFormatStrings = manualFormatStrings.map((format) => ({
11351144
format,
1136-
isArbitraryVariant,
1145+
respectPrefix,
11371146
}))
11381147

11391148
let opts = {

src/util/formatVariantSelector.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { movePseudos } from './pseudoElements'
99
/** @typedef {import('postcss-selector-parser').Pseudo} Pseudo */
1010
/** @typedef {import('postcss-selector-parser').Node} Node */
1111

12-
/** @typedef {{format: string, isArbitraryVariant: boolean}[]} RawFormats */
12+
/** @typedef {{format: string, respectPrefix: boolean}[]} RawFormats */
1313
/** @typedef {import('postcss-selector-parser').Root} ParsedFormats */
1414
/** @typedef {RawFormats | ParsedFormats} AcceptedFormats */
1515

@@ -29,7 +29,7 @@ export function formatVariantSelector(formats, { context, candidate }) {
2929

3030
return {
3131
...format,
32-
ast: format.isArbitraryVariant ? ast : prefixSelector(prefix, ast),
32+
ast: format.respectPrefix ? prefixSelector(prefix, ast) : ast,
3333
}
3434
})
3535

src/util/prefixSelector.js

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export default function (prefix, selector, prependNegative = false) {
1717
return selector
1818
}
1919

20+
/** @type {import('postcss-selector-parser').Root} */
2021
let ast = typeof selector === 'string' ? parser().astSync(selector) : selector
2122

2223
ast.walkClasses((classSelector) => {

0 commit comments

Comments
 (0)