diff --git a/CHANGELOG.md b/CHANGELOG.md index 38e6742a9da8..3d40c96cf3eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Move `important` selector to the front when `@apply`-ing selector-modifying variants in custom utilities ([#8313](https://github.com/tailwindlabs/tailwindcss/pull/8313)) - Error when registering an invalid custom variant ([#8345](https://github.com/tailwindlabs/tailwindcss/pull/8345)) - Create tailwind.config.cjs file in ESM package when running init ([#8363](https://github.com/tailwindlabs/tailwindcss/pull/8363)) +- Fix `matchVariants` that use at-rules and placeholders ([#8392](https://github.com/tailwindlabs/tailwindcss/pull/8392)) ### Changed diff --git a/src/lib/setupContextUtils.js b/src/lib/setupContextUtils.js index 731ab022d513..f044a70d827b 100644 --- a/src/lib/setupContextUtils.js +++ b/src/lib/setupContextUtils.js @@ -439,7 +439,8 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs variantFunctions = [].concat(variantFunctions).map((variantFunction) => { if (typeof variantFunction !== 'string') { // Safelist public API functions - return ({ args, modifySelectors, container, separator, wrap, format }) => { + return (api) => { + let { args, modifySelectors, container, separator, wrap, format } = api let result = variantFunction( Object.assign( { modifySelectors, container, separator }, @@ -453,7 +454,8 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs ) } - return result + // result may be undefined with legacy variants that use APIs like `modifySelectors` + return result && parseVariant(result)(api) } } @@ -477,20 +479,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs api.addVariant( variant, - Object.assign( - ({ args, wrap }) => { - let formatString = variants[variant](args) - if (!formatString) return null - - if (!formatString.startsWith('@')) { - return formatString - } - - let [, name, params] = /@(.*?)( .+|[({].*)/g.exec(formatString) - return wrap(postcss.atRule({ name, params: params.trim() })) - }, - { [MATCH_VARIANT]: true } - ), + Object.assign(({ args }) => variants[variant](args), { [MATCH_VARIANT]: true }), options ) } diff --git a/tests/match-variants.test.js b/tests/match-variants.test.js index 269edff522e9..1f0252ce8178 100644 --- a/tests/match-variants.test.js +++ b/tests/match-variants.test.js @@ -35,6 +35,82 @@ test('partial arbitrary variants', () => { }) }) +test('partial arbitrary variants with at-rules', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant({ + potato: (flavor) => `@media (potato: ${flavor})`, + }) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (potato: baked) { + .potato-\[baked\]\:w-3 { + width: 0.75rem; + } + } + @media (potato: yellow) { + .potato-\[yellow\]\:bg-yellow-200 { + --tw-bg-opacity: 1; + background-color: rgb(254 240 138 / var(--tw-bg-opacity)); + } + } + `) + }) +}) + +test('partial arbitrary variants with at-rules and placeholder', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant({ + potato: (flavor) => `@media (potato: ${flavor}) { &:potato }`, + }) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (potato: baked) { + .potato-\[baked\]\:w-3:potato { + width: 0.75rem; + } + } + @media (potato: yellow) { + .potato-\[yellow\]\:bg-yellow-200:potato { + --tw-bg-opacity: 1; + background-color: rgb(254 240 138 / var(--tw-bg-opacity)); + } + } + `) + }) +}) + test('partial arbitrary variants with default values', () => { let config = { content: [