Ensure custom variants using the JS API have access to modifiers (#14637)

Fixes https://github.com/tailwindlabs/tailwindcss/discussions/14623

We didn't properly pass through modifiers for all custom variant calls.
This PR fixes that.
This commit is contained in:
Philipp Spiess 2024-10-10 12:14:51 +02:00 committed by GitHub
parent 8b0d22435c
commit df0600361d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 54 additions and 3 deletions

View File

@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Ensure there's always a space before `!important` when stringifying CSS ([#14611](https://github.com/tailwindlabs/tailwindcss/pull/14611))
- Don't set `display: none` on elements that use `hidden="until-found"` ([#14631](https://github.com/tailwindlabs/tailwindcss/pull/14631))
- Fix issue that could cause the CLI to crash when files are deleted while watching ([#14616](https://github.com/tailwindlabs/tailwindcss/pull/14616))
- Ensure custom variants using the JS API have access to modifiers ([#14637](https://github.com/tailwindlabs/tailwindcss/pull/14637))
- _Upgrade (experimental)_: Ensure CSS before a layer stays unlayered when running codemods ([#14596](https://github.com/tailwindlabs/tailwindcss/pull/14596))
- _Upgrade (experimental)_: Resolve issues where some prefixed candidates were not properly migrated ([#14600](https://github.com/tailwindlabs/tailwindcss/pull/14600))

View File

@ -2295,6 +2295,52 @@ describe('matchVariant', () => {
}"
`)
})
test('should be called with eventual modifiers', async () => {
let { build } = await compile(
css`
@plugin "my-plugin";
@tailwind utilities;
`,
{
loadModule: async (id, base) => {
return {
base,
module: ({ matchVariant }: PluginAPI) => {
matchVariant('my-container', (value, { modifier }) => {
function parseValue(value: string) {
const numericValue = value.match(/^(\d+\.\d+|\d+|\.\d+)\D+/)?.[1] ?? null
if (numericValue === null) return null
return parseFloat(value)
}
const parsed = parseValue(value)
return parsed !== null ? `@container ${modifier ?? ''} (min-width: ${value})` : []
})
},
}
},
},
)
let compiled = build([
'my-container-[250px]:underline',
'my-container-[250px]/placement:underline',
])
expect(optimizeCss(compiled).trim()).toMatchInlineSnapshot(`
"@container (width >= 250px) {
.my-container-\\[250px\\]\\:underline {
text-decoration-line: underline;
}
}
@container placement (width >= 250px) {
.my-container-\\[250px\\]\\/placement\\:underline {
text-decoration-line: underline;
}
}"
`)
})
})
describe('addUtilities()', () => {

View File

@ -116,9 +116,13 @@ export function buildPluginApi(
designSystem.variants.group(
() => {
designSystem.variants.functional(name, (ruleNodes, variant) => {
if (!variant.value || variant.modifier) {
if (!variant.value) {
if (options?.values && 'DEFAULT' in options.values) {
ruleNodes.nodes = resolveVariantValue(options.values.DEFAULT, null, ruleNodes.nodes)
ruleNodes.nodes = resolveVariantValue(
options.values.DEFAULT,
variant.modifier,
ruleNodes.nodes,
)
return
}
return null
@ -136,7 +140,7 @@ export function buildPluginApi(
return
}
ruleNodes.nodes = resolveVariantValue(defaultValue, null, ruleNodes.nodes)
ruleNodes.nodes = resolveVariantValue(defaultValue, variant.modifier, ruleNodes.nodes)
}
})
},