Skip to content

Implement @variant #15663

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions integrations/postcss/multi-root.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ test(
`,
'src/root1.css': css`
@import './shared.css';
@variant one (&:is([data-root='1']));
@custom-variant one (&:is([data-root='1']));
`,
'src/root2.css': css`
@import './shared.css';
@variant two (&:is([data-root='2']));
@custom-variant two (&:is([data-root='2']));
`,
},
},
Expand Down
6 changes: 3 additions & 3 deletions integrations/upgrade/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1433,7 +1433,7 @@ test(
@tailwind components;
@tailwind utilities;

@variant hocus (&:hover, &:focus);
@custom-variant hocus (&:hover, &:focus);

@theme {
--color-red-500: #f00;
Expand Down Expand Up @@ -1539,7 +1539,7 @@ test(

@config './tailwind.config.ts';

@variant hocus (&:hover, &:focus);
@custom-variant hocus (&:hover, &:focus);

@theme {
--color-red-500: #f00;
Expand Down Expand Up @@ -1675,7 +1675,7 @@ test(
@tailwind components;
@tailwind utilities;

@variant hocus (&:hover, &:focus);
@custom-variant hocus (&:hover, &:focus);

@theme {
--color-red-500: #f00;
Expand Down
2 changes: 1 addition & 1 deletion integrations/upgrade/js-config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ test(

@source '../node_modules/my-external-lib/**/*.{html}';

@variant dark (&:where(.dark, .dark *));
@custom-variant dark (&:where(.dark, .dark *));

@theme {
--shadow-*: initial;
Expand Down
8 changes: 4 additions & 4 deletions integrations/vite/multi-root.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ test(
`,
'src/root1.css': css`
@import './shared.css';
@variant one (&:is([data-root='1']));
@custom-variant one (&:is([data-root='1']));
`,
'root2.html': html`
<head>
Expand All @@ -60,7 +60,7 @@ test(
`,
'src/root2.css': css`
@import './shared.css';
@variant two (&:is([data-root='2']));
@custom-variant two (&:is([data-root='2']));
`,
},
},
Expand Down Expand Up @@ -124,7 +124,7 @@ test(
`,
'src/root1.css': css`
@import './shared.css';
@variant one (&:is([data-root='1']));
@custom-variant one (&:is([data-root='1']));
`,
'root2.html': html`
<head>
Expand All @@ -136,7 +136,7 @@ test(
`,
'src/root2.css': css`
@import './shared.css';
@variant two (&:is([data-root='2']));
@custom-variant two (&:is([data-root='2']));
`,
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export function migrateMissingLayers(): Plugin {
node.name === 'source' ||
node.name === 'theme' ||
node.name === 'utility' ||
node.name === 'custom-variant' ||
node.name === 'variant'
) {
if (bucket.length > 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ it('should add the compatibility CSS before the first `@layer base` (if the "tai
await migrate(css`
@import 'tailwindcss';

@variant foo {
@custom-variant foo {
}

@utility bar {
Expand All @@ -153,7 +153,7 @@ it('should add the compatibility CSS before the first `@layer base` (if the "tai
).toMatchInlineSnapshot(`
"@import 'tailwindcss';

@variant foo {
@custom-variant foo {
}

/*
Expand Down Expand Up @@ -193,7 +193,7 @@ it('should add the compatibility CSS before the first `@layer base` (if the "tai
await migrate(css`
@import 'tailwindcss/preflight';

@variant foo {
@custom-variant foo {
}

@utility bar {
Expand All @@ -211,7 +211,7 @@ it('should add the compatibility CSS before the first `@layer base` (if the "tai
).toMatchInlineSnapshot(`
"@import 'tailwindcss/preflight';

@variant foo {
@custom-variant foo {
}

/*
Expand Down Expand Up @@ -249,7 +249,7 @@ it('should add the compatibility CSS before the first `@layer base` (if the "tai
it('should not add the backwards compatibility CSS when no `@import "tailwindcss"` or `@import "tailwindcss/preflight"` exists', async () => {
expect(
await migrate(css`
@variant foo {
@custom-variant foo {
}

@utility bar {
Expand All @@ -265,7 +265,7 @@ it('should not add the backwards compatibility CSS when no `@import "tailwindcss
}
`),
).toMatchInlineSnapshot(`
"@variant foo {
"@custom-variant foo {
}

@utility bar {
Expand All @@ -287,7 +287,7 @@ it('should not add the backwards compatibility CSS when another `@import "tailwi
await migrate(css`
@import 'tailwindcss/theme';

@variant foo {
@custom-variant foo {
}

@utility bar {
Expand All @@ -305,7 +305,7 @@ it('should not add the backwards compatibility CSS when another `@import "tailwi
).toMatchInlineSnapshot(`
"@import 'tailwindcss/theme';

@variant foo {
@custom-variant foo {
}

@utility bar {
Expand Down
4 changes: 2 additions & 2 deletions packages/@tailwindcss-upgrade/src/codemods/sort-buckets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const BUCKET_ORDER = [
'config', // @config
'plugin', // @plugin
'source', // @source
'variant', // @variant
'custom-variant', // @custom-variant
'theme', // @theme

// Styles
Expand Down Expand Up @@ -75,7 +75,7 @@ export function sortBuckets(): Plugin {
// Known at-rules
else if (
node.type === 'atrule' &&
['config', 'plugin', 'source', 'theme', 'utility', 'variant'].includes(node.name)
['config', 'plugin', 'source', 'theme', 'utility', 'custom-variant'].includes(node.name)
) {
injectInto(node.name, node)
}
Expand Down
2 changes: 1 addition & 1 deletion packages/@tailwindcss-upgrade/src/migrate-js-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ function migrateDarkMode(unresolvedConfig: Config & { darkMode: any }): string {
if (variant === '') {
return ''
}
return `\n@tw-bucket variant {\n@variant dark (${variant});\n}\n`
return `\n@tw-bucket custom-variant {\n@custom-variant dark (${variant});\n}\n`
}

// Returns a string identifier used to section theme declarations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,19 @@ test('it works with custom variants', async () => {
let designSystem = await __unstable__loadDesignSystem(
css`
@import 'tailwindcss';
@variant atrule {
@custom-variant atrule {
@media (print) {
@slot;
}
}

@variant combinator {
@custom-variant combinator {
> * {
@slot;
}
}

@variant pseudo {
@custom-variant pseudo {
&::before {
@slot;
}
Expand Down
20 changes: 16 additions & 4 deletions packages/tailwindcss/src/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,11 +256,23 @@ export function optimizeAst(ast: AstNode[]) {

// Rule
else if (node.kind === 'rule') {
let copy = { ...node, nodes: [] }
for (let child of node.nodes) {
transform(child, copy.nodes, depth + 1)
// Rules with `&` as the selector should be flattened
if (node.selector === '&') {
for (let child of node.nodes) {
let nodes: AstNode[] = []
transform(child, nodes, depth + 1)
parent.push(...nodes)
}
}
Comment on lines +259 to +266
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just an optimization to flatten:

.foo {
  & {
    color: red;
  }
}

Into:

.foo {
  color: red;
}

Which is more relevant when introducing this new @variant you can use.


//
else {
let copy = { ...node, nodes: [] }
for (let child of node.nodes) {
transform(child, copy.nodes, depth + 1)
}
parent.push(copy)
}
parent.push(copy)
}

// AtRule `@property`
Expand Down
4 changes: 2 additions & 2 deletions packages/tailwindcss/src/compat/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,8 @@ test('Variants in CSS overwrite variants from plugins', async () => {
let input = css`
@tailwind utilities;
@config "./config.js";
@variant dark (&:is(.my-dark));
@variant light (&:is(.my-light));
@custom-variant dark (&:is(.my-dark));
@custom-variant light (&:is(.my-light));
`

let compiler = await compile(input, {
Expand Down
8 changes: 7 additions & 1 deletion packages/tailwindcss/src/compat/plugin-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { DefaultMap } from '../utils/default-map'
import { inferDataType } from '../utils/infer-data-type'
import { segment } from '../utils/segment'
import { toKeyPath } from '../utils/to-key-path'
import { compoundsForSelectors, substituteAtSlot } from '../variants'
import { compoundsForSelectors, IS_VALID_VARIANT_NAME, substituteAtSlot } from '../variants'
import type { ResolvedConfig, UserConfig } from './config/types'
import { createThemeFn } from './plugin-functions'
import * as SelectorParser from './selector-parser'
Expand Down Expand Up @@ -108,6 +108,12 @@ export function buildPluginApi({
},

addVariant(name, variant) {
if (!IS_VALID_VARIANT_NAME.test(name)) {
throw new Error(
`\`addVariant('${name}')\` defines an invalid variant name. Variants should only contain alphanumeric, dashes or underscore characters.`,
)
}

// Single selector or multiple parallel selectors
if (typeof variant === 'string' || Array.isArray(variant)) {
designSystem.variants.static(
Expand Down
Loading