Skip to content

Commit 34678d1

Browse files
committed
implement in-* as a compound variant
1 parent d177f4c commit 34678d1

File tree

4 files changed

+39
-55
lines changed

4 files changed

+39
-55
lines changed

packages/tailwindcss/src/utils/is-alpha.bench.ts

Lines changed: 0 additions & 25 deletions
This file was deleted.

packages/tailwindcss/src/utils/is-alpha.ts

Lines changed: 0 additions & 14 deletions
This file was deleted.

packages/tailwindcss/src/variants.test.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1694,13 +1694,20 @@ test('not', async () => {
16941694
})
16951695

16961696
test('in', async () => {
1697-
expect(await run(['in-p:flex', 'in-[p]:flex', 'in-[.group]:flex', 'not-in-p:flex']))
1698-
.toMatchInlineSnapshot(`
1699-
".not-in-p\\:flex:not(:where(p) *), :where(p) .in-p\\:flex, :where(.group) .in-\\[\\.group\\]\\:flex, :where(p) .in-\\[p\\]\\:flex {
1700-
display: flex;
1701-
}"
1702-
`)
1703-
expect(await run(['in-foo-bar:flex'])).toEqual('')
1697+
expect(
1698+
await run([
1699+
'in-[p]:flex',
1700+
'in-[.group]:flex',
1701+
'not-in-[p]:flex',
1702+
'not-in-[.group]:flex',
1703+
'in-data-visible:flex',
1704+
]),
1705+
).toMatchInlineSnapshot(`
1706+
".not-in-\\[\\.group\\]\\:flex:not(:where(.group) *), .not-in-\\[p\\]\\:flex:not(:where(:is(p)) *), :where([data-visible]) .in-data-visible\\:flex, :where(.group) .in-\\[\\.group\\]\\:flex, :where(:is(p)) .in-\\[p\\]\\:flex {
1707+
display: flex;
1708+
}"
1709+
`)
1710+
expect(await run(['in-p:flex', 'in-foo-bar:flex'])).toEqual('')
17041711
})
17051712

17061713
test('has', async () => {

packages/tailwindcss/src/variants.ts

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import type { Theme } from './theme'
1616
import { compareBreakpoints } from './utils/compare-breakpoints'
1717
import { DefaultMap } from './utils/default-map'
1818
import { isPositiveInteger } from './utils/infer-data-type'
19-
import { isAlpha } from './utils/is-alpha'
2019
import { segment } from './utils/segment'
2120

2221
type VariantFn<T extends Variant['kind']> = (
@@ -712,16 +711,33 @@ export function createVariants(theme: Theme): Variants {
712711

713712
staticVariant('inert', ['&:is([inert], [inert] *)'])
714713

715-
variants.functional('in', (ruleNode, variant) => {
716-
if (!variant.value || variant.modifier) return null
714+
variants.compound('in', Compounds.StyleRules, (ruleNode, variant) => {
715+
if (variant.modifier) return null
717716

718-
// Named values should be alpha (tag selector). This prevents `in-foo-bar`
719-
// from being used as a variant.
720-
if (variant.value.kind === 'named' && !isAlpha(variant.value.value)) {
721-
return null
722-
}
717+
let didApply = false
718+
719+
walk([ruleNode], (node, { path }) => {
720+
if (node.kind !== 'rule') return WalkAction.Continue
721+
722+
// Throw out any candidates with variants using nested style rules
723+
for (let parent of path.slice(0, -1)) {
724+
if (parent.kind !== 'rule') continue
723725

724-
ruleNode.nodes = [styleRule(`:where(${variant.value.value}) &`, ruleNode.nodes)]
726+
didApply = false
727+
return WalkAction.Stop
728+
}
729+
730+
// Replace `&` in target variant with `*`, so variants like `&:hover`
731+
// become `:where(*:hover) &`. The `*` will often be optimized away.
732+
node.selector = `:where(${node.selector.replaceAll('&', '*')}) &`
733+
734+
// Track that the variant was actually applied
735+
didApply = true
736+
})
737+
738+
// If the node wasn't modified, this variant is not compatible with
739+
// `in-*` so discard the candidate.
740+
if (!didApply) return null
725741
})
726742

727743
variants.compound('has', Compounds.StyleRules, (ruleNode, variant) => {

0 commit comments

Comments
 (0)