Skip to content
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

Improve support for custom variants in group-*, peer-*, has-*, and not-* variants #14743

Merged
merged 24 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d141afa
Add function for depth-first AST traversal
thecrypticace Oct 17, 2024
aa5fc87
Fix intellisense variant selector calculation
thecrypticace Oct 14, 2024
f8143a6
Add Intellisense API benchmark
thecrypticace Oct 21, 2024
12b9fae
Use single rule for parallel variants when possible
thecrypticace Oct 17, 2024
5b5bfc9
Add path information to `visit`
thecrypticace Oct 17, 2024
bc391bc
Simplify nesting checks in compound variants
thecrypticace Oct 17, 2024
22673e5
Filter the kinds of rules compound variants support
thecrypticace Oct 21, 2024
6a03a06
Register compound variants with the kinds of rules they support
thecrypticace Oct 21, 2024
8dc719c
Let `not-*` variant handle simple conditional at rules
thecrypticace Oct 21, 2024
cc3e774
Update tests
thecrypticace Oct 21, 2024
414bc16
Update changelog
thecrypticace Oct 21, 2024
22e5614
Use bitfield enum
thecrypticace Oct 22, 2024
9f1a7d3
Compute compounds when using staticVariant
thecrypticace Oct 22, 2024
92e8d31
Add tests
thecrypticace Oct 22, 2024
fa3effb
Refactor
thecrypticace Oct 23, 2024
9e365df
Compute compunds for arbitrary variants
thecrypticace Oct 23, 2024
5b7e104
Compute compounds for `@variant`
thecrypticace Oct 23, 2024
4cc3f16
Compute compounds for `addVariant`
thecrypticace Oct 23, 2024
fb0eabf
Add tests
thecrypticace Oct 23, 2024
a1ab176
Update CHANGELOG.md
thecrypticace Oct 23, 2024
6ac6829
Apply suggestions from code review
thecrypticace Oct 23, 2024
a8ee1fb
Merge branch 'next' into feat/v4-not-tweaks
thecrypticace Oct 24, 2024
48139ad
Update changelog
thecrypticace Oct 24, 2024
ba33ae0
Merge branch 'next' into feat/v4-not-tweaks
thecrypticace Oct 24, 2024
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Added `not-*` versions of all builtin media query and supports variants ([#14743](https://github.com/tailwindlabs/tailwindcss/pull/14743))
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
- Added `not-*` versions of all builtin media query and supports variants ([#14743](https://github.com/tailwindlabs/tailwindcss/pull/14743))
- Support `not-*` with all built-in media query and `supports-*` variants ([#14743](https://github.com/tailwindlabs/tailwindcss/pull/14743))

- Improved support for custom variants with `group-*`, `peer-*`, `has-*`, and `not-*` ([#14743](https://github.com/tailwindlabs/tailwindcss/pull/14743))
Copy link
Member

Choose a reason for hiding this comment

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

Is it possible to be clearer/more specific about what's actually possible now that wasn't before? I try to be really careful about using the format "Improve …" in changelog entries because it's not really clear what has actually changed


### Changed

- Don't convert underscores in the first argument to `var()` and `theme()` to spaces ([#14776](https://github.com/tailwindlabs/tailwindcss/pull/14776), [#14781](https://github.com/tailwindlabs/tailwindcss/pull/14781))
Expand All @@ -17,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Don't migrate important modifiers inside conditional statements in Vue and Alpine (e.g. `<div v-if="!border" />`) ([#14774](https://github.com/tailwindlabs/tailwindcss/pull/14774))
- Ensure third-party plugins with `exports` in their `package.json` are resolved correctly ([#14775](https://github.com/tailwindlabs/tailwindcss/pull/14775))
- Ensure underscores in the `url()` function are never unescaped ([#14776](https://github.com/tailwindlabs/tailwindcss/pull/14776))
- Fixed display of complex variants in Intellisense ([#14743](https://github.com/tailwindlabs/tailwindcss/pull/14743))
Copy link
Member

Choose a reason for hiding this comment

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

Not sure if this is meaningfully more specific but at least should use imperative mood for changelog entries to be consistent with other ones:

Suggested change
- Fixed display of complex variants in Intellisense ([#14743](https://github.com/tailwindlabs/tailwindcss/pull/14743))
- Ensure complex variants are displayed correctly in IntelliSense completions ([#14743](https://github.com/tailwindlabs/tailwindcss/pull/14743))

Also capitalized "IntelliSense" consistent with how we do it elsewhere 👍

- _Upgrade (experimental)_: Ensure `@import` statements for relative CSS files are actually migrated to use relative path syntax ([#14769](https://github.com/tailwindlabs/tailwindcss/pull/14769))
- _Upgrade (experimental)_: Only generate Preflight compatibility styles when Preflight is used ([#14773](https://github.com/tailwindlabs/tailwindcss/pull/14773))
- _Upgrade (experimental)_: Don't escape underscores when printing theme values migrated to CSS variables in arbitrary values (e.g. `m-[var(--spacing-1_5)]` instead of `m-[var(--spacing-1\_5)]`) ([#14778](https://github.com/tailwindlabs/tailwindcss/pull/14778))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3859,7 +3859,68 @@ exports[`getVariants 1`] = `
"isArbitrary": true,
"name": "not",
"selectors": [Function],
"values": [],
"values": [
"not",
"group",
"peer",
"first",
"last",
"only",
"odd",
"even",
"first-of-type",
"last-of-type",
"only-of-type",
"visited",
"target",
"open",
"default",
"checked",
"indeterminate",
"placeholder-shown",
"autofill",
"optional",
"required",
"valid",
"invalid",
"in-range",
"out-of-range",
"read-only",
"empty",
"focus-within",
"hover",
"focus",
"focus-visible",
"active",
"enabled",
"disabled",
"inert",
"has",
"aria",
"data",
"nth",
"nth-last",
"nth-of-type",
"nth-last-of-type",
"supports",
"motion-safe",
"motion-reduce",
"contrast-more",
"contrast-less",
"max",
"sm",
"min",
"@max",
"@",
"@min",
"portrait",
"landscape",
"ltr",
"rtl",
"dark",
"print",
"forced-colors",
],
},
{
"hasDash": true,
Expand Down
53 changes: 49 additions & 4 deletions packages/tailwindcss/src/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,33 +87,37 @@ export function walk(
parent: AstNode | null
replaceWith(newNode: AstNode | AstNode[]): void
context: Record<string, string>
path: AstNode[]
},
) => void | WalkAction,
parent: AstNode | null = null,
parentPath: AstNode[] = [],
context: Record<string, string> = {},
) {
for (let i = 0; i < ast.length; i++) {
let node = ast[i]
let path = [...parentPath, node]
let parent = parentPath.at(-1) ?? null

// We want context nodes to be transparent in walks. This means that
// whenever we encounter one, we immediately walk through its children and
// furthermore we also don't update the parent.
if (node.kind === 'context') {
walk(node.nodes, visit, parent, { ...context, ...node.context })
walk(node.nodes, visit, parentPath, { ...context, ...node.context })
continue
}

let status =
visit(node, {
parent,
context,
path,
replaceWith(newNode) {
ast.splice(i, 1, ...(Array.isArray(newNode) ? newNode : [newNode]))
// We want to visit the newly replaced node(s), which start at the
// current index (i). By decrementing the index here, the next loop
// will process this position (containing the replaced node) again.
i--
},
context,
}) ?? WalkAction.Continue

// Stop the walk entirely
Expand All @@ -123,11 +127,52 @@ export function walk(
if (status === WalkAction.Skip) continue

if (node.kind === 'rule') {
walk(node.nodes, visit, node, context)
walk(node.nodes, visit, path, context)
}
}
}

// This is a depth-first traversal of the AST
export function walkDepth(
ast: AstNode[],
visit: (
node: AstNode,
utils: {
parent: AstNode | null
path: AstNode[]
context: Record<string, string>
replaceWith(newNode: AstNode[]): void
},
) => void,
parentPath: AstNode[] = [],
context: Record<string, string> = {},
) {
for (let i = 0; i < ast.length; i++) {
let node = ast[i]
let path = [...parentPath, node]
let parent = parentPath.at(-1) ?? null

if (node.kind === 'rule') {
walkDepth(node.nodes, visit, path, context)
} else if (node.kind === 'context') {
walkDepth(node.nodes, visit, parentPath, { ...context, ...node.context })
continue
}

visit(node, {
parent,
context,
path,
replaceWith(newNode) {
ast.splice(i, 1, ...newNode)

// Skip over the newly inserted nodes (being depth-first it doesn't make sense to visit them)
i += newNode.length - 1
},
})
}
}

export function toCss(ast: AstNode[]) {
let atRoots: string = ''
let seenAtProperties = new Set<string>()
Expand Down
Loading