Skip to content

Commit bb4f5da

Browse files
Fix matchVariants that use at-rules and placeholders (#8392)
* Fix matchVariants that use at-rules and placeholders * update changelog * Update CHANGELOG.md * Only parseVariant when result is defined Co-authored-by: Robin Malfait <[email protected]>
1 parent 1a564fa commit bb4f5da

File tree

3 files changed

+82
-16
lines changed

3 files changed

+82
-16
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2323
- Move `important` selector to the front when `@apply`-ing selector-modifying variants in custom utilities ([#8313](https://github.com/tailwindlabs/tailwindcss/pull/8313))
2424
- Error when registering an invalid custom variant ([#8345](https://github.com/tailwindlabs/tailwindcss/pull/8345))
2525
- Create tailwind.config.cjs file in ESM package when running init ([#8363](https://github.com/tailwindlabs/tailwindcss/pull/8363))
26+
- Fix `matchVariants` that use at-rules and placeholders ([#8392](https://github.com/tailwindlabs/tailwindcss/pull/8392))
2627

2728
### Changed
2829

src/lib/setupContextUtils.js

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,8 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
439439
variantFunctions = [].concat(variantFunctions).map((variantFunction) => {
440440
if (typeof variantFunction !== 'string') {
441441
// Safelist public API functions
442-
return ({ args, modifySelectors, container, separator, wrap, format }) => {
442+
return (api) => {
443+
let { args, modifySelectors, container, separator, wrap, format } = api
443444
let result = variantFunction(
444445
Object.assign(
445446
{ modifySelectors, container, separator },
@@ -453,7 +454,8 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
453454
)
454455
}
455456

456-
return result
457+
// result may be undefined with legacy variants that use APIs like `modifySelectors`
458+
return result && parseVariant(result)(api)
457459
}
458460
}
459461

@@ -477,20 +479,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
477479

478480
api.addVariant(
479481
variant,
480-
Object.assign(
481-
({ args, wrap }) => {
482-
let formatString = variants[variant](args)
483-
if (!formatString) return null
484-
485-
if (!formatString.startsWith('@')) {
486-
return formatString
487-
}
488-
489-
let [, name, params] = /@(.*?)( .+|[({].*)/g.exec(formatString)
490-
return wrap(postcss.atRule({ name, params: params.trim() }))
491-
},
492-
{ [MATCH_VARIANT]: true }
493-
),
482+
Object.assign(({ args }) => variants[variant](args), { [MATCH_VARIANT]: true }),
494483
options
495484
)
496485
}

tests/match-variants.test.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,82 @@ test('partial arbitrary variants', () => {
3535
})
3636
})
3737

38+
test('partial arbitrary variants with at-rules', () => {
39+
let config = {
40+
content: [
41+
{
42+
raw: html`<div class="potato-[yellow]:bg-yellow-200 potato-[baked]:w-3"></div> `,
43+
},
44+
],
45+
corePlugins: { preflight: false },
46+
plugins: [
47+
({ matchVariant }) => {
48+
matchVariant({
49+
potato: (flavor) => `@media (potato: ${flavor})`,
50+
})
51+
},
52+
],
53+
}
54+
55+
let input = css`
56+
@tailwind utilities;
57+
`
58+
59+
return run(input, config).then((result) => {
60+
expect(result.css).toMatchFormattedCss(css`
61+
@media (potato: baked) {
62+
.potato-\[baked\]\:w-3 {
63+
width: 0.75rem;
64+
}
65+
}
66+
@media (potato: yellow) {
67+
.potato-\[yellow\]\:bg-yellow-200 {
68+
--tw-bg-opacity: 1;
69+
background-color: rgb(254 240 138 / var(--tw-bg-opacity));
70+
}
71+
}
72+
`)
73+
})
74+
})
75+
76+
test('partial arbitrary variants with at-rules and placeholder', () => {
77+
let config = {
78+
content: [
79+
{
80+
raw: html`<div class="potato-[yellow]:bg-yellow-200 potato-[baked]:w-3"></div> `,
81+
},
82+
],
83+
corePlugins: { preflight: false },
84+
plugins: [
85+
({ matchVariant }) => {
86+
matchVariant({
87+
potato: (flavor) => `@media (potato: ${flavor}) { &:potato }`,
88+
})
89+
},
90+
],
91+
}
92+
93+
let input = css`
94+
@tailwind utilities;
95+
`
96+
97+
return run(input, config).then((result) => {
98+
expect(result.css).toMatchFormattedCss(css`
99+
@media (potato: baked) {
100+
.potato-\[baked\]\:w-3:potato {
101+
width: 0.75rem;
102+
}
103+
}
104+
@media (potato: yellow) {
105+
.potato-\[yellow\]\:bg-yellow-200:potato {
106+
--tw-bg-opacity: 1;
107+
background-color: rgb(254 240 138 / var(--tw-bg-opacity));
108+
}
109+
}
110+
`)
111+
})
112+
})
113+
38114
test('partial arbitrary variants with default values', () => {
39115
let config = {
40116
content: [

0 commit comments

Comments
 (0)