Compare commits
4 commits
release/4.
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa81d697fe | ||
|
|
9798a8ab5b | ||
|
|
722acdfebf | ||
|
|
86f3daf912 |
13 changed files with 358 additions and 107 deletions
|
|
@ -33,6 +33,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Only normalize top-level `and`, `or`, and `not` keywords in `supports-[…]` variants (e.g. `selector(a: not (.foo))` → `selector(a:not(.foo))`) ([#20420](https://github.com/tailwindlabs/tailwindcss/pull/20420))
|
||||
- Don't warn about Angular's `::ng-deep` and `:host-context()` when optimizing CSS ([#20434](https://github.com/tailwindlabs/tailwindcss/pull/20434))
|
||||
- Don't generate CSS for candidates containing an empty additional modifier (e.g. `bg-red-500/50/` and `group-hover/foo//bar:flex`) ([#20466](https://github.com/tailwindlabs/tailwindcss/pull/20466))
|
||||
- Sort `min-*`, `max-*`, and container query variants with decimal values numerically (e.g. `min-[40.25rem]` before `min-[40.5rem]`) ([#20512](https://github.com/tailwindlabs/tailwindcss/pull/20512))
|
||||
- Ensure CSS comments ending with `\*/` are closed correctly instead of swallowing the CSS that follows (e.g. `/* C:\temp\*/`) ([#20508](https://github.com/tailwindlabs/tailwindcss/pull/20508))
|
||||
- Improve style invalidation performance of `group-*` and `peer-*` variants ([#20513](https://github.com/tailwindlabs/tailwindcss/pull/20513))
|
||||
|
||||
## [4.3.3] - 2026-07-16
|
||||
|
||||
|
|
|
|||
|
|
@ -376,7 +376,7 @@ export async function handle(args: Result<ReturnType<typeof options>>) {
|
|||
// Create a new compiler, given the new `input`
|
||||
;[compiler, scanner] = await createCompiler(input, I)
|
||||
|
||||
// Succesfully created a new compiler, so the `fullRebuildPaths`
|
||||
// Successfully created a new compiler, so the `fullRebuildPaths`
|
||||
// will be updated. If other errors occur, we should be able to
|
||||
// restore the paths unconditionally.
|
||||
backupRebuildPaths = fullRebuildPaths.slice()
|
||||
|
|
|
|||
|
|
@ -1098,7 +1098,7 @@ const printArbitraryValueCache = new DefaultMap<string, string>((input) => {
|
|||
node.value = ','
|
||||
}
|
||||
|
||||
// Wrap custom functions starting with `--`, in parentheses if preceeded by
|
||||
// Wrap custom functions starting with `--`, in parentheses if preceded by
|
||||
// a symbol. E.g.: `calc(100%---spacing(2))` → `calc(100%-(--spacing(2)))`
|
||||
else if (node.kind === 'function' && node.value.startsWith('--')) {
|
||||
let idx = ctx.index
|
||||
|
|
|
|||
|
|
@ -1630,7 +1630,7 @@ describe('addVariant', () => {
|
|||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
@layer utilities {
|
||||
.group-hocus\\:flex:is(:is(:where(.group):hover, :where(.group):focus) *) {
|
||||
:is(:is(:where(.group):hover, :where(.group):focus) .group-hocus\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
|
@ -1744,7 +1744,7 @@ describe('addVariant', () => {
|
|||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
@layer utilities {
|
||||
.group-hocus\\:flex:is(:where(.group):hover *), .group-hocus\\:flex:is(:where(.group):focus *) {
|
||||
:is(:where(.group):hover .group-hocus\\:flex), :is(:where(.group):focus .group-hocus\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
|
@ -1784,7 +1784,7 @@ describe('addVariant', () => {
|
|||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
@layer utilities {
|
||||
.group-hocus\\:flex:is(:where(.group):hover *), .group-hocus\\:flex:is(:where(.group):focus *) {
|
||||
:is(:where(.group):hover .group-hocus\\:flex), :is(:where(.group):focus .group-hocus\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
|
@ -1827,12 +1827,12 @@ describe('addVariant', () => {
|
|||
"
|
||||
@layer utilities {
|
||||
@media (hover: hover) {
|
||||
.group-hocus\\:flex:is(:where(.group):hover *) {
|
||||
:is(:where(.group):hover .group-hocus\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.group-hocus\\:flex:is(:where(.group):focus *) {
|
||||
:is(:where(.group):focus .group-hocus\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
|
@ -1964,7 +1964,7 @@ describe('addVariant', () => {
|
|||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
@layer utilities {
|
||||
.group-optional\\:flex:is(:where(.group):optional *), .group-optional\\/foo\\:flex:is(:where(.group\\/foo):optional *), .peer-optional\\:flex:is(:where(.peer):optional ~ *), .optional\\:flex:optional {
|
||||
:is(:where(.group):optional .group-optional\\:flex), :is(:where(.group\\/foo):optional .group-optional\\/foo\\:flex), :is(:where(.peer):optional ~ .peer-optional\\:flex), .optional\\:flex:optional {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
|
@ -2903,7 +2903,7 @@ describe('matchVariant', () => {
|
|||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
@layer utilities {
|
||||
.group-optional-\\[test\\]\\:flex:is(:where(.group):optional:has(test) :where(.group) *), .group-optional-\\[test\\]\\/foo\\:flex:is(:where(.group\\/foo):optional:has(test) :where(.group\\/foo) *), .peer-optional-\\[test\\]\\:flex:is(:where(.peer):optional:has(test) :where(.peer) ~ *), .optional-\\[test\\]\\:flex:optional:has(test) .optional-\\[test\\]\\:flex {
|
||||
:is(:where(.group):optional:has(test) :where(.group) .group-optional-\\[test\\]\\:flex), :is(:where(.group\\/foo):optional:has(test) :where(.group\\/foo) .group-optional-\\[test\\]\\/foo\\:flex), :is(:where(.peer):optional:has(test) :where(.peer) ~ .peer-optional-\\[test\\]\\:flex), .optional-\\[test\\]\\:flex:optional:has(test) .optional-\\[test\\]\\:flex {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,23 @@ describe.each(['Unix', 'Windows'])('Line endings: %s', (lineEndings) => {
|
|||
).toEqual([])
|
||||
})
|
||||
|
||||
it('should end a comment at `*/` even when it is preceded by a `\\`', () => {
|
||||
expect(
|
||||
parse(css`
|
||||
/* C:\temp\*/
|
||||
.foo {
|
||||
color: red;
|
||||
}
|
||||
`),
|
||||
).toEqual([
|
||||
{
|
||||
kind: 'rule',
|
||||
selector: '.foo',
|
||||
nodes: [{ kind: 'declaration', property: 'color', value: 'red', important: false }],
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it('should parse a comment inside of a selector and ignore it', () => {
|
||||
expect(
|
||||
parse(css`
|
||||
|
|
@ -448,6 +465,28 @@ describe.each(['Unix', 'Windows'])('Line endings: %s', (lineEndings) => {
|
|||
])
|
||||
})
|
||||
|
||||
it('should end a comment in a custom property at `*/` even when it is preceded by a `\\`', () => {
|
||||
expect(
|
||||
parse(css`
|
||||
--foo: /* C:\temp\*/ bar;
|
||||
--bar: /* baz */ qux;
|
||||
`),
|
||||
).toEqual([
|
||||
{
|
||||
kind: 'declaration',
|
||||
property: '--foo',
|
||||
value: '/* C:\\temp\\*/ bar',
|
||||
important: false,
|
||||
},
|
||||
{
|
||||
kind: 'declaration',
|
||||
property: '--bar',
|
||||
value: '/* baz */ qux',
|
||||
important: false,
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it('should parse empty custom properties', () => {
|
||||
expect(
|
||||
parse(css`
|
||||
|
|
|
|||
|
|
@ -128,19 +128,24 @@ export function parse(input: string, opts?: ParseOptions) {
|
|||
// ^^^^^^^^^^^^^
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// The escape character `\` in comments are ignored, this means that a
|
||||
// the end of a comment preceded by `\` does _not_ mean that the end of the
|
||||
// comment is escaped and therefore we have to keep parsing.
|
||||
//
|
||||
// This is a valid comment:
|
||||
// ```
|
||||
// /*C:\*/
|
||||
// ```
|
||||
// See: https://www.w3.org/TR/css-syntax-3/#consume-comment
|
||||
else if (currentChar === SLASH && input.charCodeAt(i + 1) === ASTERISK) {
|
||||
let start = i
|
||||
|
||||
for (let j = i + 2; j < input.length; j++) {
|
||||
peekChar = input.charCodeAt(j)
|
||||
|
||||
// Current character is a `\` therefore the next character is escaped.
|
||||
if (peekChar === BACKSLASH) {
|
||||
j += 1
|
||||
}
|
||||
|
||||
// End of the comment
|
||||
else if (peekChar === ASTERISK && input.charCodeAt(j + 1) === SLASH) {
|
||||
// End of the comment.
|
||||
if (peekChar === ASTERISK && input.charCodeAt(j + 1) === SLASH) {
|
||||
i = j + 1
|
||||
break
|
||||
}
|
||||
|
|
@ -224,13 +229,9 @@ export function parse(input: string, opts?: ParseOptions) {
|
|||
else if (peekChar === SLASH && input.charCodeAt(j + 1) === ASTERISK) {
|
||||
for (let k = j + 2; k < input.length; k++) {
|
||||
peekChar = input.charCodeAt(k)
|
||||
// Current character is a `\` therefore the next character is escaped.
|
||||
if (peekChar === BACKSLASH) {
|
||||
k += 1
|
||||
}
|
||||
|
||||
// End of the comment
|
||||
else if (peekChar === ASTERISK && input.charCodeAt(k + 1) === SLASH) {
|
||||
// End of the comment.
|
||||
if (peekChar === ASTERISK && input.charCodeAt(k + 1) === SLASH) {
|
||||
j = k + 1
|
||||
break
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1444,42 +1444,42 @@ describe('sorting', () => {
|
|||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
@media (hover: hover) {
|
||||
.group-hover\\:flex:is(:where(.group):hover *) {
|
||||
:is(:where(.group):hover .group-hover\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.group-focus\\:flex:is(:where(.group):focus *) {
|
||||
:is(:where(.group):focus .group-focus\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.peer-hover\\:flex:is(:where(.peer):hover ~ *) {
|
||||
:is(:where(.peer):hover ~ .peer-hover\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.group-hover\\:peer-hover\\:flex:is(:where(.group):hover *):is(:where(.peer):hover ~ *), .peer-hover\\:group-hover\\:flex:is(:where(.peer):hover ~ *):is(:where(.group):hover *) {
|
||||
:is(:where(.peer):hover ~ :is(:where(.group):hover .group-hover\\:peer-hover\\:flex)), :is(:where(.group):hover :is(:where(.peer):hover ~ .peer-hover\\:group-hover\\:flex)) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.group-focus\\:peer-hover\\:flex:is(:where(.group):focus *):is(:where(.peer):hover ~ *), .peer-hover\\:group-focus\\:flex:is(:where(.peer):hover ~ *):is(:where(.group):focus *) {
|
||||
:is(:where(.peer):hover ~ :is(:where(.group):focus .group-focus\\:peer-hover\\:flex)), :is(:where(.group):focus :is(:where(.peer):hover ~ .peer-hover\\:group-focus\\:flex)) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.peer-focus\\:flex:is(:where(.peer):focus ~ *) {
|
||||
:is(:where(.peer):focus ~ .peer-focus\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.group-hover\\:peer-focus\\:flex:is(:where(.group):hover *):is(:where(.peer):focus ~ *), .peer-focus\\:group-hover\\:flex:is(:where(.peer):focus ~ *):is(:where(.group):hover *) {
|
||||
:is(:where(.peer):focus ~ :is(:where(.group):hover .group-hover\\:peer-focus\\:flex)), :is(:where(.group):hover :is(:where(.peer):focus ~ .peer-focus\\:group-hover\\:flex)) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.group-focus\\:peer-focus\\:flex:is(:where(.group):focus *):is(:where(.peer):focus ~ *), .peer-focus\\:group-focus\\:flex:is(:where(.peer):focus ~ *):is(:where(.group):focus *) {
|
||||
:is(:where(.peer):focus ~ :is(:where(.group):focus .group-focus\\:peer-focus\\:flex)), :is(:where(.group):focus :is(:where(.peer):focus ~ .peer-focus\\:group-focus\\:flex)) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
|
@ -3601,7 +3601,7 @@ describe('plugins', () => {
|
|||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
@layer utilities {
|
||||
.group-hocus\\:flex:is(:is(:where(.group):hover, :where(.group):focus) *) {
|
||||
:is(:is(:where(.group):hover, :where(.group):focus) .group-hocus\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
|
@ -3636,7 +3636,7 @@ describe('plugins', () => {
|
|||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
@layer utilities {
|
||||
.group-hocus\\:flex:is(:where(.group):hover *), .group-hocus\\:flex:is(:where(.group):focus *) {
|
||||
:is(:where(.group):hover .group-hocus\\:flex), :is(:where(.group):focus .group-hocus\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
|
@ -3674,7 +3674,7 @@ describe('plugins', () => {
|
|||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
@layer utilities {
|
||||
.group-hocus\\:flex:is(:where(.group):hover *), .group-hocus\\:flex:is(:where(.group):focus *) {
|
||||
:is(:where(.group):hover .group-hocus\\:flex), :is(:where(.group):focus .group-hocus\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
|
@ -3715,12 +3715,12 @@ describe('plugins', () => {
|
|||
"
|
||||
@layer utilities {
|
||||
@media (hover: hover) {
|
||||
.group-hocus\\:flex:is(:where(.group):hover *) {
|
||||
:is(:where(.group):hover .group-hocus\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.group-hocus\\:flex:is(:where(.group):focus *) {
|
||||
:is(:where(.group):focus .group-hocus\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
|
@ -4199,7 +4199,7 @@ describe('@custom-variant', () => {
|
|||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
@layer utilities {
|
||||
.group-hocus\\:flex:is(:is(:where(.group):hover, :where(.group):focus) *) {
|
||||
:is(:is(:where(.group):hover, :where(.group):focus) .group-hocus\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
|
@ -4294,7 +4294,7 @@ describe('@custom-variant', () => {
|
|||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
@layer utilities {
|
||||
.group-selected\\:underline:is(:where(.group)[data-selected] *), .selected\\:underline[data-selected] {
|
||||
:is(:where(.group)[data-selected] .group-selected\\:underline), .selected\\:underline[data-selected] {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
}
|
||||
|
|
@ -4322,7 +4322,7 @@ describe('@custom-variant', () => {
|
|||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
@layer utilities {
|
||||
.group-hocus\\:underline:is(:is(:where(.group):hover, :where(.group):focus) *), .hocus\\:underline:hover, .hocus\\:underline:focus {
|
||||
:is(:is(:where(.group):hover, :where(.group):focus) .group-hocus\\:underline), .hocus\\:underline:hover, .hocus\\:underline:focus {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
}
|
||||
|
|
@ -4353,7 +4353,7 @@ describe('@custom-variant', () => {
|
|||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
@layer utilities {
|
||||
.group-hocus\\:underline:is(:where(.group):hover *), .group-hocus\\:underline:is(:where(.group):focus *), .hocus\\:underline:hover, .hocus\\:underline:focus {
|
||||
:is(:where(.group):hover .group-hocus\\:underline), :is(:where(.group):focus .group-hocus\\:underline), .hocus\\:underline:hover, .hocus\\:underline:focus {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
}
|
||||
|
|
@ -4458,12 +4458,12 @@ describe('@custom-variant', () => {
|
|||
"
|
||||
@layer utilities {
|
||||
@media (hover: hover) {
|
||||
.group-hocus\\:underline:is(:where(.group):hover *) {
|
||||
:is(:where(.group):hover .group-hocus\\:underline) {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.group-hocus\\:underline:is(:where(.group):focus *) {
|
||||
:is(:where(.group):focus .group-hocus\\:underline) {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
|
||||
|
|
@ -4503,7 +4503,7 @@ describe('@custom-variant', () => {
|
|||
"
|
||||
@layer utilities {
|
||||
@media (hover: hover) {
|
||||
.group-hocus\\:underline:is(:where(.group):hover *), .hocus\\:underline:hover {
|
||||
:is(:where(.group):hover .group-hocus\\:underline), .hocus\\:underline:hover {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,9 +97,9 @@ test('getVariants compound', async () => {
|
|||
]
|
||||
|
||||
expect(list).toEqual([
|
||||
['@media (hover: hover) { &:is(:where(.group):hover *) }'],
|
||||
['@media (hover: hover) { &:is(:where(.group\\/sidebar):hover *) }'],
|
||||
['@media (hover: hover) { &:is(:where(.group):is(:where(.group):hover *) *) }'],
|
||||
['@media (hover: hover) { :is(:where(.group):hover &) }'],
|
||||
['@media (hover: hover) { :is(:where(.group\\/sidebar):hover &) }'],
|
||||
['@media (hover: hover) { :is(:is(:where(.group):hover :where(.group)) &) }'],
|
||||
[],
|
||||
[],
|
||||
])
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ test('utilities must be prefixed', async () => {
|
|||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.tw\\:group-hover\\:flex:is(:where(.tw\\:group):hover *), .tw\\:peer-hover\\:flex:is(:where(.tw\\:peer):hover ~ *) {
|
||||
:is(:where(.tw\\:group):hover .tw\\:group-hover\\:flex), :is(:where(.tw\\:peer):hover ~ .tw\\:peer-hover\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export function compareBreakpoints(a: string, z: string, direction: 'asc' | 'des
|
|||
// Compare by bucket name
|
||||
(aBucket === zBucket ? 0 : aBucket < zBucket ? -1 : 1) ||
|
||||
// If bucket names are the same, compare by value
|
||||
(direction === 'asc' ? parseInt(a) - parseInt(z) : parseInt(z) - parseInt(a))
|
||||
(direction === 'asc' ? parseFloat(a) - parseFloat(z) : parseFloat(z) - parseFloat(a))
|
||||
|
||||
// If the groups are the same, and the contents are not numbers, the
|
||||
// `order` will result in `NaN`. In this case, we want to make sorting
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ test('after', async () => {
|
|||
test('first', async () => {
|
||||
expect(await run(['first:flex', 'group-first:flex', 'peer-first:flex'])).toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-first\\:flex:is(:where(.group):first-child *), .peer-first\\:flex:is(:where(.peer):first-child ~ *), .first\\:flex:first-child {
|
||||
:is(:where(.group):first-child .group-first\\:flex), :is(:where(.peer):first-child ~ .peer-first\\:flex), .first\\:flex:first-child {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -197,7 +197,7 @@ test('first', async () => {
|
|||
test('last', async () => {
|
||||
expect(await run(['last:flex', 'group-last:flex', 'peer-last:flex'])).toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-last\\:flex:is(:where(.group):last-child *), .peer-last\\:flex:is(:where(.peer):last-child ~ *), .last\\:flex:last-child {
|
||||
:is(:where(.group):last-child .group-last\\:flex), :is(:where(.peer):last-child ~ .peer-last\\:flex), .last\\:flex:last-child {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -208,7 +208,7 @@ test('last', async () => {
|
|||
test('only', async () => {
|
||||
expect(await run(['only:flex', 'group-only:flex', 'peer-only:flex'])).toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-only\\:flex:is(:where(.group):only-child *), .peer-only\\:flex:is(:where(.peer):only-child ~ *), .only\\:flex:only-child {
|
||||
:is(:where(.group):only-child .group-only\\:flex), :is(:where(.peer):only-child ~ .peer-only\\:flex), .only\\:flex:only-child {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -219,7 +219,7 @@ test('only', async () => {
|
|||
test('odd', async () => {
|
||||
expect(await run(['odd:flex', 'group-odd:flex', 'peer-odd:flex'])).toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-odd\\:flex:is(:where(.group):nth-child(odd) *), .peer-odd\\:flex:is(:where(.peer):nth-child(odd) ~ *), .odd\\:flex:nth-child(odd) {
|
||||
:is(:where(.group):nth-child(odd) .group-odd\\:flex), :is(:where(.peer):nth-child(odd) ~ .peer-odd\\:flex), .odd\\:flex:nth-child(odd) {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -230,7 +230,7 @@ test('odd', async () => {
|
|||
test('even', async () => {
|
||||
expect(await run(['even:flex', 'group-even:flex', 'peer-even:flex'])).toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-even\\:flex:is(:where(.group):nth-child(2n) *), .peer-even\\:flex:is(:where(.peer):nth-child(2n) ~ *), .even\\:flex:nth-child(2n) {
|
||||
:is(:where(.group):nth-child(2n) .group-even\\:flex), :is(:where(.peer):nth-child(2n) ~ .peer-even\\:flex), .even\\:flex:nth-child(2n) {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -242,7 +242,7 @@ test('first-of-type', async () => {
|
|||
expect(await run(['first-of-type:flex', 'group-first-of-type:flex', 'peer-first-of-type:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-first-of-type\\:flex:is(:where(.group):first-of-type *), .peer-first-of-type\\:flex:is(:where(.peer):first-of-type ~ *), .first-of-type\\:flex:first-of-type {
|
||||
:is(:where(.group):first-of-type .group-first-of-type\\:flex), :is(:where(.peer):first-of-type ~ .peer-first-of-type\\:flex), .first-of-type\\:flex:first-of-type {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -254,7 +254,7 @@ test('last-of-type', async () => {
|
|||
expect(await run(['last-of-type:flex', 'group-last-of-type:flex', 'peer-last-of-type:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-last-of-type\\:flex:is(:where(.group):last-of-type *), .peer-last-of-type\\:flex:is(:where(.peer):last-of-type ~ *), .last-of-type\\:flex:last-of-type {
|
||||
:is(:where(.group):last-of-type .group-last-of-type\\:flex), :is(:where(.peer):last-of-type ~ .peer-last-of-type\\:flex), .last-of-type\\:flex:last-of-type {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -266,7 +266,7 @@ test('only-of-type', async () => {
|
|||
expect(await run(['only-of-type:flex', 'group-only-of-type:flex', 'peer-only-of-type:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-only-of-type\\:flex:is(:where(.group):only-of-type *), .peer-only-of-type\\:flex:is(:where(.peer):only-of-type ~ *), .only-of-type\\:flex:only-of-type {
|
||||
:is(:where(.group):only-of-type .group-only-of-type\\:flex), :is(:where(.peer):only-of-type ~ .peer-only-of-type\\:flex), .only-of-type\\:flex:only-of-type {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -278,7 +278,7 @@ test('visited', async () => {
|
|||
expect(await run(['visited:flex', 'group-visited:flex', 'peer-visited:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-visited\\:flex:is(:where(.group):visited *), .peer-visited\\:flex:is(:where(.peer):visited ~ *), .visited\\:flex:visited {
|
||||
:is(:where(.group):visited .group-visited\\:flex), :is(:where(.peer):visited ~ .peer-visited\\:flex), .visited\\:flex:visited {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -290,7 +290,7 @@ test('target', async () => {
|
|||
expect(await run(['target:flex', 'group-target:flex', 'peer-target:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-target\\:flex:is(:where(.group):target *), .peer-target\\:flex:is(:where(.peer):target ~ *), .target\\:flex:target {
|
||||
:is(:where(.group):target .group-target\\:flex), :is(:where(.peer):target ~ .peer-target\\:flex), .target\\:flex:target {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -302,7 +302,7 @@ test('open', async () => {
|
|||
expect(await run(['open:flex', 'group-open:flex', 'peer-open:flex', 'not-open:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
"
|
||||
.not-open\\:flex:not(:is([open], :popover-open, :open)), .group-open\\:flex:is(:where(.group):is([open], :popover-open, :open) *), .peer-open\\:flex:is(:where(.peer):is([open], :popover-open, :open) ~ *), .open\\:flex:is([open], :popover-open, :open) {
|
||||
.not-open\\:flex:not(:is([open], :popover-open, :open)), :is(:where(.group):is([open], :popover-open, :open) .group-open\\:flex), :is(:where(.peer):is([open], :popover-open, :open) ~ .peer-open\\:flex), .open\\:flex:is([open], :popover-open, :open) {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -314,7 +314,7 @@ test('default', async () => {
|
|||
expect(await run(['default:flex', 'group-default:flex', 'peer-default:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-default\\:flex:is(:where(.group):default *), .peer-default\\:flex:is(:where(.peer):default ~ *), .default\\:flex:default {
|
||||
:is(:where(.group):default .group-default\\:flex), :is(:where(.peer):default ~ .peer-default\\:flex), .default\\:flex:default {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -326,7 +326,7 @@ test('checked', async () => {
|
|||
expect(await run(['checked:flex', 'group-checked:flex', 'peer-checked:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-checked\\:flex:is(:where(.group):checked *), .peer-checked\\:flex:is(:where(.peer):checked ~ *), .checked\\:flex:checked {
|
||||
:is(:where(.group):checked .group-checked\\:flex), :is(:where(.peer):checked ~ .peer-checked\\:flex), .checked\\:flex:checked {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -338,7 +338,7 @@ test('indeterminate', async () => {
|
|||
expect(await run(['indeterminate:flex', 'group-indeterminate:flex', 'peer-indeterminate:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-indeterminate\\:flex:is(:where(.group):indeterminate *), .peer-indeterminate\\:flex:is(:where(.peer):indeterminate ~ *), .indeterminate\\:flex:indeterminate {
|
||||
:is(:where(.group):indeterminate .group-indeterminate\\:flex), :is(:where(.peer):indeterminate ~ .peer-indeterminate\\:flex), .indeterminate\\:flex:indeterminate {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -355,7 +355,7 @@ test('placeholder-shown', async () => {
|
|||
]),
|
||||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-placeholder-shown\\:flex:is(:where(.group):placeholder-shown *), .peer-placeholder-shown\\:flex:is(:where(.peer):placeholder-shown ~ *), .placeholder-shown\\:flex:placeholder-shown {
|
||||
:is(:where(.group):placeholder-shown .group-placeholder-shown\\:flex), :is(:where(.peer):placeholder-shown ~ .peer-placeholder-shown\\:flex), .placeholder-shown\\:flex:placeholder-shown {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -367,7 +367,7 @@ test('autofill', async () => {
|
|||
expect(await run(['autofill:flex', 'group-autofill:flex', 'peer-autofill:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-autofill\\:flex:is(:where(.group):autofill *), .peer-autofill\\:flex:is(:where(.peer):autofill ~ *) {
|
||||
:is(:where(.group):autofill .group-autofill\\:flex), :is(:where(.peer):autofill ~ .peer-autofill\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
|
@ -383,7 +383,7 @@ test('optional', async () => {
|
|||
expect(await run(['optional:flex', 'group-optional:flex', 'peer-optional:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-optional\\:flex:is(:where(.group):optional *), .peer-optional\\:flex:is(:where(.peer):optional ~ *), .optional\\:flex:optional {
|
||||
:is(:where(.group):optional .group-optional\\:flex), :is(:where(.peer):optional ~ .peer-optional\\:flex), .optional\\:flex:optional {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -395,7 +395,7 @@ test('required', async () => {
|
|||
expect(await run(['required:flex', 'group-required:flex', 'peer-required:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-required\\:flex:is(:where(.group):required *), .peer-required\\:flex:is(:where(.peer):required ~ *), .required\\:flex:required {
|
||||
:is(:where(.group):required .group-required\\:flex), :is(:where(.peer):required ~ .peer-required\\:flex), .required\\:flex:required {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -406,7 +406,7 @@ test('required', async () => {
|
|||
test('valid', async () => {
|
||||
expect(await run(['valid:flex', 'group-valid:flex', 'peer-valid:flex'])).toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-valid\\:flex:is(:where(.group):valid *), .peer-valid\\:flex:is(:where(.peer):valid ~ *), .valid\\:flex:valid {
|
||||
:is(:where(.group):valid .group-valid\\:flex), :is(:where(.peer):valid ~ .peer-valid\\:flex), .valid\\:flex:valid {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -418,7 +418,7 @@ test('invalid', async () => {
|
|||
expect(await run(['invalid:flex', 'group-invalid:flex', 'peer-invalid:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-invalid\\:flex:is(:where(.group):invalid *), .peer-invalid\\:flex:is(:where(.peer):invalid ~ *), .invalid\\:flex:invalid {
|
||||
:is(:where(.group):invalid .group-invalid\\:flex), :is(:where(.peer):invalid ~ .peer-invalid\\:flex), .invalid\\:flex:invalid {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -430,7 +430,7 @@ test('user-valid', async () => {
|
|||
expect(await run(['user-valid:flex', 'group-user-valid:flex', 'peer-user-valid:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-user-valid\\:flex:is(:where(.group):user-valid *), .peer-user-valid\\:flex:is(:where(.peer):user-valid ~ *) {
|
||||
:is(:where(.group):user-valid .group-user-valid\\:flex), :is(:where(.peer):user-valid ~ .peer-user-valid\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
|
@ -446,7 +446,7 @@ test('user-invalid', async () => {
|
|||
expect(await run(['user-invalid:flex', 'group-user-invalid:flex', 'peer-user-invalid:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-user-invalid\\:flex:is(:where(.group):user-invalid *), .peer-user-invalid\\:flex:is(:where(.peer):user-invalid ~ *) {
|
||||
:is(:where(.group):user-invalid .group-user-invalid\\:flex), :is(:where(.peer):user-invalid ~ .peer-user-invalid\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
|
@ -462,7 +462,7 @@ test('in-range', async () => {
|
|||
expect(await run(['in-range:flex', 'group-in-range:flex', 'peer-in-range:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-in-range\\:flex:is(:where(.group):in-range *), .peer-in-range\\:flex:is(:where(.peer):in-range ~ *), .in-range\\:flex:in-range {
|
||||
:is(:where(.group):in-range .group-in-range\\:flex), :is(:where(.peer):in-range ~ .peer-in-range\\:flex), .in-range\\:flex:in-range {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -474,7 +474,7 @@ test('out-of-range', async () => {
|
|||
expect(await run(['out-of-range:flex', 'group-out-of-range:flex', 'peer-out-of-range:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-out-of-range\\:flex:is(:where(.group):out-of-range *), .peer-out-of-range\\:flex:is(:where(.peer):out-of-range ~ *), .out-of-range\\:flex:out-of-range {
|
||||
:is(:where(.group):out-of-range .group-out-of-range\\:flex), :is(:where(.peer):out-of-range ~ .peer-out-of-range\\:flex), .out-of-range\\:flex:out-of-range {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -486,7 +486,7 @@ test('read-only', async () => {
|
|||
expect(await run(['read-only:flex', 'group-read-only:flex', 'peer-read-only:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-read-only\\:flex:is(:where(.group):read-only *), .peer-read-only\\:flex:is(:where(.peer):read-only ~ *), .read-only\\:flex:read-only {
|
||||
:is(:where(.group):read-only .group-read-only\\:flex), :is(:where(.peer):read-only ~ .peer-read-only\\:flex), .read-only\\:flex:read-only {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -497,7 +497,7 @@ test('read-only', async () => {
|
|||
test('empty', async () => {
|
||||
expect(await run(['empty:flex', 'group-empty:flex', 'peer-empty:flex'])).toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-empty\\:flex:is(:where(.group):empty *), .peer-empty\\:flex:is(:where(.peer):empty ~ *), .empty\\:flex:empty {
|
||||
:is(:where(.group):empty .group-empty\\:flex), :is(:where(.peer):empty ~ .peer-empty\\:flex), .empty\\:flex:empty {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -509,7 +509,7 @@ test('focus-within', async () => {
|
|||
expect(await run(['focus-within:flex', 'group-focus-within:flex', 'peer-focus-within:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-focus-within\\:flex:is(:where(.group):focus-within *), .peer-focus-within\\:flex:is(:where(.peer):focus-within ~ *), .focus-within\\:flex:focus-within {
|
||||
:is(:where(.group):focus-within .group-focus-within\\:flex), :is(:where(.peer):focus-within ~ .peer-focus-within\\:flex), .focus-within\\:flex:focus-within {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -521,7 +521,7 @@ test('hover', async () => {
|
|||
expect(await run(['hover:flex', 'group-hover:flex', 'peer-hover:flex'])).toMatchInlineSnapshot(`
|
||||
"
|
||||
@media (hover: hover) {
|
||||
.group-hover\\:flex:is(:where(.group):hover *), .peer-hover\\:flex:is(:where(.peer):hover ~ *), .hover\\:flex:hover {
|
||||
:is(:where(.group):hover .group-hover\\:flex), :is(:where(.peer):hover ~ .peer-hover\\:flex), .hover\\:flex:hover {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
|
@ -533,7 +533,7 @@ test('hover', async () => {
|
|||
test('focus', async () => {
|
||||
expect(await run(['focus:flex', 'group-focus:flex', 'peer-focus:flex'])).toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-focus\\:flex:is(:where(.group):focus *), .peer-focus\\:flex:is(:where(.peer):focus ~ *), .focus\\:flex:focus {
|
||||
:is(:where(.group):focus .group-focus\\:flex), :is(:where(.peer):focus ~ .peer-focus\\:flex), .focus\\:flex:focus {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -545,12 +545,12 @@ test('group-hover group-focus sorting', async () => {
|
|||
expect(await run(['group-hover:flex', 'group-focus:flex'])).toMatchInlineSnapshot(`
|
||||
"
|
||||
@media (hover: hover) {
|
||||
.group-hover\\:flex:is(:where(.group):hover *) {
|
||||
:is(:where(.group):hover .group-hover\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.group-focus\\:flex:is(:where(.group):focus *) {
|
||||
:is(:where(.group):focus .group-focus\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -558,23 +558,36 @@ test('group-hover group-focus sorting', async () => {
|
|||
expect(await run(['group-focus:flex', 'group-hover:flex'])).toMatchInlineSnapshot(`
|
||||
"
|
||||
@media (hover: hover) {
|
||||
.group-hover\\:flex:is(:where(.group):hover *) {
|
||||
:is(:where(.group):hover .group-hover\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.group-focus\\:flex:is(:where(.group):focus *) {
|
||||
:is(:where(.group):focus .group-focus\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
`)
|
||||
})
|
||||
|
||||
test('stacking group and peer variants does not duplicate the target selector', async () => {
|
||||
let candidate = Array.from(
|
||||
{ length: 12 },
|
||||
(_, i) => `${i % 2 === 0 ? 'group' : 'peer'}-data-active/name${i}`,
|
||||
).join(':')
|
||||
|
||||
let output = await run([`${candidate}:flex`])
|
||||
expect(output).toContain('display: flex')
|
||||
// Repeating `&` in each variant makes the generated selector grow
|
||||
// exponentially. This many variants should still produce a small rule.
|
||||
expect(output.length).toBeLessThan(2_000)
|
||||
})
|
||||
|
||||
test('focus-visible', async () => {
|
||||
expect(await run(['focus-visible:flex', 'group-focus-visible:flex', 'peer-focus-visible:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-focus-visible\\:flex:is(:where(.group):focus-visible *), .peer-focus-visible\\:flex:is(:where(.peer):focus-visible ~ *), .focus-visible\\:flex:focus-visible {
|
||||
:is(:where(.group):focus-visible .group-focus-visible\\:flex), :is(:where(.peer):focus-visible ~ .peer-focus-visible\\:flex), .focus-visible\\:flex:focus-visible {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -586,7 +599,7 @@ test('active', async () => {
|
|||
expect(await run(['active:flex', 'group-active:flex', 'peer-active:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-active\\:flex:is(:where(.group):active *), .peer-active\\:flex:is(:where(.peer):active ~ *), .active\\:flex:active {
|
||||
:is(:where(.group):active .group-active\\:flex), :is(:where(.peer):active ~ .peer-active\\:flex), .active\\:flex:active {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -598,7 +611,7 @@ test('enabled', async () => {
|
|||
expect(await run(['enabled:flex', 'group-enabled:flex', 'peer-enabled:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-enabled\\:flex:is(:where(.group):enabled *), .peer-enabled\\:flex:is(:where(.peer):enabled ~ *), .enabled\\:flex:enabled {
|
||||
:is(:where(.group):enabled .group-enabled\\:flex), :is(:where(.peer):enabled ~ .peer-enabled\\:flex), .enabled\\:flex:enabled {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -610,7 +623,7 @@ test('disabled', async () => {
|
|||
expect(await run(['disabled:flex', 'group-disabled:flex', 'peer-disabled:flex']))
|
||||
.toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-disabled\\:flex:is(:where(.group):disabled *), .peer-disabled\\:flex:is(:where(.peer):disabled ~ *), .disabled\\:flex:disabled {
|
||||
:is(:where(.group):disabled .group-disabled\\:flex), :is(:where(.peer):disabled ~ .peer-disabled\\:flex), .disabled\\:flex:disabled {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -621,7 +634,7 @@ test('disabled', async () => {
|
|||
test('inert', async () => {
|
||||
expect(await run(['inert:flex', 'group-inert:flex', 'peer-inert:flex'])).toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-inert\\:flex:is(:where(.group):is([inert], [inert] *) *), .peer-inert\\:flex:is(:where(.peer):is([inert], [inert] *) ~ *), .inert\\:flex:is([inert], [inert] *) {
|
||||
:is(:where(.group):is([inert], [inert] *) .group-inert\\:flex), :is(:where(.peer):is([inert], [inert] *) ~ .peer-inert\\:flex), .inert\\:flex:is([inert], [inert] *) {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -640,17 +653,17 @@ test('group-[...]', async () => {
|
|||
]),
|
||||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-\\[\\&_p\\]\\:flex:is(:where(.group) p *), .group-\\[\\&\\:hover\\]\\:group-\\[\\&_p\\]\\:flex:is(:where(.group):hover *):is(:where(.group) p *) {
|
||||
:is(:where(.group) p .group-\\[\\&_p\\]\\:flex), :is(:where(.group) p :is(:where(.group):hover .group-\\[\\&\\:hover\\]\\:group-\\[\\&_p\\]\\:flex)) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.group-\\[\\&_p\\]\\:hover\\:flex:is(:where(.group) p *):hover, .hover\\:group-\\[\\&_p\\]\\:flex:hover:is(:where(.group) p *) {
|
||||
:is(:where(.group) p .group-\\[\\&_p\\]\\:hover\\:flex):hover, :is(:where(.group) p .hover\\:group-\\[\\&_p\\]\\:flex:hover) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.hover\\:group-\\[\\&_p\\]\\:hover\\:flex:hover:is(:where(.group) p *):hover {
|
||||
:is(:where(.group) p .hover\\:group-\\[\\&_p\\]\\:hover\\:flex:hover):hover {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
|
@ -692,22 +705,22 @@ test('group-*', async () => {
|
|||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
@media (hover: hover) {
|
||||
.group-hover\\:flex:is(:where(.group):hover *) {
|
||||
:is(:where(.group):hover .group-hover\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.group-focus\\:flex:is(:where(.group):focus *) {
|
||||
:is(:where(.group):focus .group-focus\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.group-focus\\:group-hover\\:flex:is(:where(.group):focus *):is(:where(.group):hover *), .group-hover\\:group-focus\\:flex:is(:where(.group):hover *):is(:where(.group):focus *) {
|
||||
:is(:where(.group):hover :is(:where(.group):focus .group-focus\\:group-hover\\:flex)), :is(:where(.group):focus :is(:where(.group):hover .group-hover\\:group-focus\\:flex)) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.group-hocus\\:flex:is(:is(:where(.group):hover, :where(.group):focus) *) {
|
||||
:is(:is(:where(.group):hover, :where(.group):focus) .group-hocus\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -742,12 +755,12 @@ test('peer-[...]', async () => {
|
|||
]),
|
||||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
.peer-\\[\\&_p\\]\\:flex:is(:where(.peer) p ~ *), .peer-\\[\\&\\:hover\\]\\:peer-\\[\\&_p\\]\\:flex:is(:where(.peer):hover ~ *):is(:where(.peer) p ~ *) {
|
||||
:is(:where(.peer) p ~ .peer-\\[\\&_p\\]\\:flex), :is(:where(.peer) p ~ :is(:where(.peer):hover ~ .peer-\\[\\&\\:hover\\]\\:peer-\\[\\&_p\\]\\:flex)) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.hover\\:peer-\\[\\&_p\\]\\:flex:hover:is(:where(.peer) p ~ *), .peer-\\[\\&_p\\]\\:hover\\:flex:is(:where(.peer) p ~ *):hover, .hover\\:peer-\\[\\&_p\\]\\:focus\\:flex:hover:is(:where(.peer) p ~ *):focus {
|
||||
:is(:where(.peer) p ~ .hover\\:peer-\\[\\&_p\\]\\:flex:hover), :is(:where(.peer) p ~ .peer-\\[\\&_p\\]\\:hover\\:flex):hover, :is(:where(.peer) p ~ .hover\\:peer-\\[\\&_p\\]\\:focus\\:flex:hover):focus {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
|
@ -782,22 +795,22 @@ test('peer-*', async () => {
|
|||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
@media (hover: hover) {
|
||||
.peer-hover\\:flex:is(:where(.peer):hover ~ *) {
|
||||
:is(:where(.peer):hover ~ .peer-hover\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.peer-focus\\:flex:is(:where(.peer):focus ~ *) {
|
||||
:is(:where(.peer):focus ~ .peer-focus\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.peer-focus\\:peer-hover\\:flex:is(:where(.peer):focus ~ *):is(:where(.peer):hover ~ *), .peer-hover\\:peer-focus\\:flex:is(:where(.peer):hover ~ *):is(:where(.peer):focus ~ *) {
|
||||
:is(:where(.peer):hover ~ :is(:where(.peer):focus ~ .peer-focus\\:peer-hover\\:flex)), :is(:where(.peer):focus ~ :is(:where(.peer):hover ~ .peer-hover\\:peer-focus\\:flex)) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.peer-hocus\\:flex:is(:is(:where(.peer):hover, :where(.peer):focus) ~ *) {
|
||||
:is(:is(:where(.peer):hover, :where(.peer):focus) ~ .peer-hocus\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -1424,6 +1437,80 @@ test('sorting `min` and `max` should sort by unit, then by value, then alphabeti
|
|||
`)
|
||||
})
|
||||
|
||||
test('sorting `min` and `max` should compare decimal values numerically', async () => {
|
||||
expect(
|
||||
await run([
|
||||
'min-[40.5rem]:flex',
|
||||
'min-[40.25rem]:flex',
|
||||
'max-[40.25rem]:flex',
|
||||
'max-[40.5rem]:flex',
|
||||
]),
|
||||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
@media not all and (min-width: 40.5rem) {
|
||||
.max-\\[40\\.5rem\\]\\:flex {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@media not all and (min-width: 40.25rem) {
|
||||
.max-\\[40\\.25rem\\]\\:flex {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 40.25rem) {
|
||||
.min-\\[40\\.25rem\\]\\:flex {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 40.5rem) {
|
||||
.min-\\[40\\.5rem\\]\\:flex {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
"
|
||||
`)
|
||||
})
|
||||
|
||||
test('sorting `@min` and `@max` should compare decimal values numerically', async () => {
|
||||
expect(
|
||||
await run([
|
||||
'@min-[40.5rem]:flex',
|
||||
'@min-[40.25rem]:flex',
|
||||
'@max-[40.25rem]:flex',
|
||||
'@max-[40.5rem]:flex',
|
||||
]),
|
||||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
@container not (min-width: 40.5rem) {
|
||||
.\\@max-\\[40\\.5rem\\]\\:flex {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@container not (min-width: 40.25rem) {
|
||||
.\\@max-\\[40\\.25rem\\]\\:flex {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@container (min-width: 40.25rem) {
|
||||
.\\@min-\\[40\\.25rem\\]\\:flex {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@container (min-width: 40.5rem) {
|
||||
.\\@min-\\[40\\.5rem\\]\\:flex {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
"
|
||||
`)
|
||||
})
|
||||
|
||||
test('supports', async () => {
|
||||
expect(
|
||||
await run([
|
||||
|
|
@ -1823,7 +1910,7 @@ test('not', async () => {
|
|||
}
|
||||
}
|
||||
|
||||
.group-not-checked\\:flex:is(:where(.group):not(:checked) *), .group-not-hocus\\:flex:is(:where(.group):not(:hover, :focus) *), .group-not-hocus\\/parent-name\\:flex:is(:where(.group\\/parent-name):not(:hover, :focus) *), .group-not-\\[\\:checked\\]\\:flex:is(:where(.group):not(:checked) *), .group-not-\\[\\:checked\\]\\/parent-name\\:flex:is(:where(.group\\/parent-name):not(:checked) *), .peer-not-checked\\:flex:is(:where(.peer):not(:checked) ~ *), .peer-not-hocus\\:flex:is(:where(.peer):not(:hover, :focus) ~ *), .peer-not-hocus\\/sibling-name\\:flex:is(:where(.peer\\/sibling-name):not(:hover, :focus) ~ *), .peer-not-\\[\\:checked\\]\\:flex:is(:where(.peer):not(:checked) ~ *), .peer-not-\\[\\:checked\\]\\/sibling-name\\:flex:is(:where(.peer\\/sibling-name):not(:checked) ~ *) {
|
||||
:is(:where(.group):not(:checked) .group-not-checked\\:flex), :is(:where(.group):not(:hover, :focus) .group-not-hocus\\:flex), :is(:where(.group\\/parent-name):not(:hover, :focus) .group-not-hocus\\/parent-name\\:flex), :is(:where(.group):not(:checked) .group-not-\\[\\:checked\\]\\:flex), :is(:where(.group\\/parent-name):not(:checked) .group-not-\\[\\:checked\\]\\/parent-name\\:flex), :is(:where(.peer):not(:checked) ~ .peer-not-checked\\:flex), :is(:where(.peer):not(:hover, :focus) ~ .peer-not-hocus\\:flex), :is(:where(.peer\\/sibling-name):not(:hover, :focus) ~ .peer-not-hocus\\/sibling-name\\:flex), :is(:where(.peer):not(:checked) ~ .peer-not-\\[\\:checked\\]\\:flex), :is(:where(.peer\\/sibling-name):not(:checked) ~ .peer-not-\\[\\:checked\\]\\/sibling-name\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -2052,7 +2139,7 @@ test('has', async () => {
|
|||
),
|
||||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-has-checked\\:flex:is(:where(.group):has(:checked) *), .group-has-checked\\/parent-name\\:flex:is(:where(.group\\/parent-name):has(:checked) *), .group-has-hocus\\:flex:is(:where(.group):has(:hover, :focus) *), .group-has-hocus\\/parent-name\\:flex:is(:where(.group\\/parent-name):has(:hover, :focus) *), .group-has-\\[\\:checked\\]\\:flex:is(:where(.group):has(:checked) *), .group-has-\\[\\:checked\\]\\/parent-name\\:flex:is(:where(.group\\/parent-name):has(:checked) *), .group-has-\\[\\&\\>img\\]\\:flex:is(:where(.group):has(* > img) *), .group-has-\\[\\&\\>img\\]\\/parent-name\\:flex:is(:where(.group\\/parent-name):has(* > img) *), .group-has-\\[\\+img\\]\\:flex:is(:where(.group):has( + img) *), .group-has-\\[\\>img\\]\\:flex:is(:where(.group):has( > img) *), .group-has-\\[\\>img\\]\\/parent-name\\:flex:is(:where(.group\\/parent-name):has( > img) *), .group-has-\\[\\~img\\]\\:flex:is(:where(.group):has( ~ img) *), .peer-has-checked\\:flex:is(:where(.peer):has(:checked) ~ *), .peer-has-checked\\/sibling-name\\:flex:is(:where(.peer\\/sibling-name):has(:checked) ~ *), .peer-has-hocus\\:flex:is(:where(.peer):has(:hover, :focus) ~ *), .peer-has-hocus\\/sibling-name\\:flex:is(:where(.peer\\/sibling-name):has(:hover, :focus) ~ *), .peer-has-\\[\\:checked\\]\\:flex:is(:where(.peer):has(:checked) ~ *), .peer-has-\\[\\:checked\\]\\/sibling-name\\:flex:is(:where(.peer\\/sibling-name):has(:checked) ~ *), .peer-has-\\[\\&\\>img\\]\\:flex:is(:where(.peer):has(* > img) ~ *), .peer-has-\\[\\&\\>img\\]\\/sibling-name\\:flex:is(:where(.peer\\/sibling-name):has(* > img) ~ *), .peer-has-\\[\\+img\\]\\:flex:is(:where(.peer):has( + img) ~ *), .peer-has-\\[\\>img\\]\\:flex:is(:where(.peer):has( > img) ~ *), .peer-has-\\[\\>img\\]\\/sibling-name\\:flex:is(:where(.peer\\/sibling-name):has( > img) ~ *), .peer-has-\\[\\~img\\]\\:flex:is(:where(.peer):has( ~ img) ~ *), .has-checked\\:flex:has(:checked), .has-hocus\\:flex:has(:hover, :focus), .has-\\[\\:checked\\]\\:flex:has(:checked), .has-\\[\\&\\>img\\]\\:flex:has(* > img), .has-\\[\\+img\\]\\:flex:has( + img), .has-\\[\\>img\\]\\:flex:has( > img), .has-\\[\\~img\\]\\:flex:has( ~ img) {
|
||||
:is(:where(.group):has(:checked) .group-has-checked\\:flex), :is(:where(.group\\/parent-name):has(:checked) .group-has-checked\\/parent-name\\:flex), :is(:where(.group):has(:hover, :focus) .group-has-hocus\\:flex), :is(:where(.group\\/parent-name):has(:hover, :focus) .group-has-hocus\\/parent-name\\:flex), :is(:where(.group):has(:checked) .group-has-\\[\\:checked\\]\\:flex), :is(:where(.group\\/parent-name):has(:checked) .group-has-\\[\\:checked\\]\\/parent-name\\:flex), :is(:where(.group):has(* > img) .group-has-\\[\\&\\>img\\]\\:flex), :is(:where(.group\\/parent-name):has(* > img) .group-has-\\[\\&\\>img\\]\\/parent-name\\:flex), :is(:where(.group):has( + img) .group-has-\\[\\+img\\]\\:flex), :is(:where(.group):has( > img) .group-has-\\[\\>img\\]\\:flex), :is(:where(.group\\/parent-name):has( > img) .group-has-\\[\\>img\\]\\/parent-name\\:flex), :is(:where(.group):has( ~ img) .group-has-\\[\\~img\\]\\:flex), :is(:where(.peer):has(:checked) ~ .peer-has-checked\\:flex), :is(:where(.peer\\/sibling-name):has(:checked) ~ .peer-has-checked\\/sibling-name\\:flex), :is(:where(.peer):has(:hover, :focus) ~ .peer-has-hocus\\:flex), :is(:where(.peer\\/sibling-name):has(:hover, :focus) ~ .peer-has-hocus\\/sibling-name\\:flex), :is(:where(.peer):has(:checked) ~ .peer-has-\\[\\:checked\\]\\:flex), :is(:where(.peer\\/sibling-name):has(:checked) ~ .peer-has-\\[\\:checked\\]\\/sibling-name\\:flex), :is(:where(.peer):has(* > img) ~ .peer-has-\\[\\&\\>img\\]\\:flex), :is(:where(.peer\\/sibling-name):has(* > img) ~ .peer-has-\\[\\&\\>img\\]\\/sibling-name\\:flex), :is(:where(.peer):has( + img) ~ .peer-has-\\[\\+img\\]\\:flex), :is(:where(.peer):has( > img) ~ .peer-has-\\[\\>img\\]\\:flex), :is(:where(.peer\\/sibling-name):has( > img) ~ .peer-has-\\[\\>img\\]\\/sibling-name\\:flex), :is(:where(.peer):has( ~ img) ~ .peer-has-\\[\\~img\\]\\:flex), .has-checked\\:flex:has(:checked), .has-hocus\\:flex:has(:hover, :focus), .has-\\[\\:checked\\]\\:flex:has(:checked), .has-\\[\\&\\>img\\]\\:flex:has(* > img), .has-\\[\\+img\\]\\:flex:has( + img), .has-\\[\\>img\\]\\:flex:has( > img), .has-\\[\\~img\\]\\:flex:has( ~ img) {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -2105,7 +2192,7 @@ test('aria', async () => {
|
|||
]),
|
||||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-aria-checked\\:flex:is(:where(.group)[aria-checked="true"] *), .group-aria-checked\\/parent-name\\:flex:is(:where(.group\\/parent-name)[aria-checked="true"] *), .group-aria-\\[modal\\]\\:flex:is(:where(.group)[aria-modal] *), .group-aria-\\[modal\\]\\/parent-name\\:flex:is(:where(.group\\/parent-name)[aria-modal] *), .group-aria-\\[valuenow\\=1\\]\\:flex:is(:where(.group)[aria-valuenow="1"] *), .group-aria-\\[valuenow\\=1\\]\\/parent-name\\:flex:is(:where(.group\\/parent-name)[aria-valuenow="1"] *), .peer-aria-checked\\:flex:is(:where(.peer)[aria-checked="true"] ~ *), .peer-aria-checked\\/sibling-name\\:flex:is(:where(.peer\\/sibling-name)[aria-checked="true"] ~ *), .peer-aria-\\[modal\\]\\:flex:is(:where(.peer)[aria-modal] ~ *), .peer-aria-\\[modal\\]\\/sibling-name\\:flex:is(:where(.peer\\/sibling-name)[aria-modal] ~ *), .peer-aria-\\[valuenow\\=1\\]\\:flex:is(:where(.peer)[aria-valuenow="1"] ~ *), .peer-aria-\\[valuenow\\=1\\]\\/sibling-name\\:flex:is(:where(.peer\\/sibling-name)[aria-valuenow="1"] ~ *), .aria-checked\\:flex[aria-checked="true"], .aria-\\[invalid\\=spelling\\]\\:flex[aria-invalid="spelling"], .aria-\\[valuenow_\\=_\\"1\\"\\]\\:flex[aria-valuenow="1"], .aria-\\[valuenow\\=1\\]\\:flex[aria-valuenow="1"] {
|
||||
:is(:where(.group)[aria-checked="true"] .group-aria-checked\\:flex), :is(:where(.group\\/parent-name)[aria-checked="true"] .group-aria-checked\\/parent-name\\:flex), :is(:where(.group)[aria-modal] .group-aria-\\[modal\\]\\:flex), :is(:where(.group\\/parent-name)[aria-modal] .group-aria-\\[modal\\]\\/parent-name\\:flex), :is(:where(.group)[aria-valuenow="1"] .group-aria-\\[valuenow\\=1\\]\\:flex), :is(:where(.group\\/parent-name)[aria-valuenow="1"] .group-aria-\\[valuenow\\=1\\]\\/parent-name\\:flex), :is(:where(.peer)[aria-checked="true"] ~ .peer-aria-checked\\:flex), :is(:where(.peer\\/sibling-name)[aria-checked="true"] ~ .peer-aria-checked\\/sibling-name\\:flex), :is(:where(.peer)[aria-modal] ~ .peer-aria-\\[modal\\]\\:flex), :is(:where(.peer\\/sibling-name)[aria-modal] ~ .peer-aria-\\[modal\\]\\/sibling-name\\:flex), :is(:where(.peer)[aria-valuenow="1"] ~ .peer-aria-\\[valuenow\\=1\\]\\:flex), :is(:where(.peer\\/sibling-name)[aria-valuenow="1"] ~ .peer-aria-\\[valuenow\\=1\\]\\/sibling-name\\:flex), .aria-checked\\:flex[aria-checked="true"], .aria-\\[invalid\\=spelling\\]\\:flex[aria-invalid="spelling"], .aria-\\[valuenow_\\=_\\"1\\"\\]\\:flex[aria-valuenow="1"], .aria-\\[valuenow\\=1\\]\\:flex[aria-valuenow="1"] {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -2144,7 +2231,7 @@ test('data', async () => {
|
|||
]),
|
||||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
.group-data-\\[disabled\\]\\:flex:is(:where(.group)[data-disabled] *), .group-data-\\[disabled\\]\\/parent-name\\:flex:is(:where(.group\\/parent-name)[data-disabled] *), .group-data-\\[foo\\$\\=\\'bar\\'_i\\]\\/parent-name\\:flex:is(:where(.group\\/parent-name)[data-foo$="bar" i] *), .group-data-\\[foo\\$\\=bar_baz_i\\]\\/parent-name\\:flex:is(:where(.group\\/parent-name)[data-foo$="bar baz" i] *), .group-data-\\[foo\\=1\\]\\:flex:is(:where(.group)[data-foo="1"] *), .group-data-\\[foo\\=1\\]\\/parent-name\\:flex:is(:where(.group\\/parent-name)[data-foo="1"] *), .group-data-\\[foo\\=bar\\ baz\\]\\/parent-name\\:flex:is(:where(.group\\/parent-name)[data-foo="bar baz"] *), .peer-data-\\[disabled\\]\\:flex:is(:where(.peer)[data-disabled] ~ *), .peer-data-\\[disabled\\]\\/sibling-name\\:flex:is(:where(.peer\\/sibling-name)[data-disabled] ~ *), .peer-data-\\[foo\\$\\=\\'bar\\'_i\\]\\/sibling-name\\:flex:is(:where(.peer\\/sibling-name)[data-foo$="bar" i] ~ *), .peer-data-\\[foo\\$\\=bar_baz_i\\]\\/sibling-name\\:flex:is(:where(.peer\\/sibling-name)[data-foo$="bar baz" i] ~ *), .peer-data-\\[foo\\=1\\]\\:flex:is(:where(.peer)[data-foo="1"] ~ *), .peer-data-\\[foo\\=1\\]\\/sibling-name\\:flex:is(:where(.peer\\/sibling-name)[data-foo="1"] ~ *), .peer-data-\\[foo\\=bar\\ baz\\]\\/sibling-name\\:flex:is(:where(.peer\\/sibling-name)[data-foo="bar baz"] ~ *), .data-disabled\\:flex[data-disabled], .data-\\[foo\\$\\=\\'bar\\'_i\\]\\:flex[data-foo$="bar" i], .data-\\[foo\\$\\=bar_baz_i\\]\\:flex[data-foo$="bar baz" i], .data-\\[foo\\=1\\]\\:flex[data-foo="1"], .data-\\[foo\\=bar_baz\\]\\:flex[data-foo="bar baz"], .data-\\[potato_\\=_\\"salad\\"\\]\\:flex[data-potato="salad"], .data-\\[potato_\\^\\=_\\"salad\\"\\]\\:flex[data-potato^="salad"], .data-\\[potato\\=\\"\\^_\\=\\"\\]\\:flex[data-potato="^ ="], .data-\\[potato\\=salad\\]\\:flex[data-potato="salad"] {
|
||||
:is(:where(.group)[data-disabled] .group-data-\\[disabled\\]\\:flex), :is(:where(.group\\/parent-name)[data-disabled] .group-data-\\[disabled\\]\\/parent-name\\:flex), :is(:where(.group\\/parent-name)[data-foo$="bar" i] .group-data-\\[foo\\$\\=\\'bar\\'_i\\]\\/parent-name\\:flex), :is(:where(.group\\/parent-name)[data-foo$="bar baz" i] .group-data-\\[foo\\$\\=bar_baz_i\\]\\/parent-name\\:flex), :is(:where(.group)[data-foo="1"] .group-data-\\[foo\\=1\\]\\:flex), :is(:where(.group\\/parent-name)[data-foo="1"] .group-data-\\[foo\\=1\\]\\/parent-name\\:flex), :is(:where(.group\\/parent-name)[data-foo="bar baz"] .group-data-\\[foo\\=bar\\ baz\\]\\/parent-name\\:flex), :is(:where(.peer)[data-disabled] ~ .peer-data-\\[disabled\\]\\:flex), :is(:where(.peer\\/sibling-name)[data-disabled] ~ .peer-data-\\[disabled\\]\\/sibling-name\\:flex), :is(:where(.peer\\/sibling-name)[data-foo$="bar" i] ~ .peer-data-\\[foo\\$\\=\\'bar\\'_i\\]\\/sibling-name\\:flex), :is(:where(.peer\\/sibling-name)[data-foo$="bar baz" i] ~ .peer-data-\\[foo\\$\\=bar_baz_i\\]\\/sibling-name\\:flex), :is(:where(.peer)[data-foo="1"] ~ .peer-data-\\[foo\\=1\\]\\:flex), :is(:where(.peer\\/sibling-name)[data-foo="1"] ~ .peer-data-\\[foo\\=1\\]\\/sibling-name\\:flex), :is(:where(.peer\\/sibling-name)[data-foo="bar baz"] ~ .peer-data-\\[foo\\=bar\\ baz\\]\\/sibling-name\\:flex), .data-disabled\\:flex[data-disabled], .data-\\[foo\\$\\=\\'bar\\'_i\\]\\:flex[data-foo$="bar" i], .data-\\[foo\\$\\=bar_baz_i\\]\\:flex[data-foo$="bar baz" i], .data-\\[foo\\=1\\]\\:flex[data-foo="1"], .data-\\[foo\\=bar_baz\\]\\:flex[data-foo="bar baz"], .data-\\[potato_\\=_\\"salad\\"\\]\\:flex[data-potato="salad"], .data-\\[potato_\\^\\=_\\"salad\\"\\]\\:flex[data-potato^="salad"], .data-\\[potato\\=\\"\\^_\\=\\"\\]\\:flex[data-potato="^ ="], .data-\\[potato\\=salad\\]\\:flex[data-potato="salad"] {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
@ -2643,7 +2730,7 @@ test('variant order', async () => {
|
|||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.group-hover\\:flex:is(:where(.group):hover *), .peer-hover\\:flex:is(:where(.peer):hover ~ *) {
|
||||
:is(:where(.group):hover .group-hover\\:flex), :is(:where(.peer):hover ~ .peer-hover\\:flex) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
|
@ -2916,7 +3003,7 @@ test('move modifier of compound variant to sub-variant if its also a compound va
|
|||
]),
|
||||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
.not-group-focus\\/name\\:flex:not(:is(:where(.group\\/name):focus *)), .group-peer-focus\\/name\\:flex:is(:where(.group\\/name):is(:where(.peer):focus ~ *) *), :where(:is(:where(.group\\/name):focus *)) .in-group-focus\\/name\\:flex, .has-group-focus\\/name\\:flex:has(:is(:where(.group\\/name):focus *)) {
|
||||
.not-group-focus\\/name\\:flex:not(:is(:where(.group\\/name):focus *)), :is(:is(:where(.peer):focus ~ :where(.group\\/name)) .group-peer-focus\\/name\\:flex), :where(:is(:where(.group\\/name):focus *)) .in-group-focus\\/name\\:flex, .has-group-focus\\/name\\:flex:has(:is(:where(.group\\/name):focus *)) {
|
||||
display: flex;
|
||||
}
|
||||
"
|
||||
|
|
|
|||
|
|
@ -610,7 +610,13 @@ export function createVariants(theme: Theme): Variants {
|
|||
selector = `:is(${selector})`
|
||||
}
|
||||
|
||||
node.selector = `&:is(${selector} *)`
|
||||
// Put the target inside `:is` so browsers can limit style invalidation to
|
||||
// it when the group changes. Keep `&` instead of the candidate's class so
|
||||
// this also works with `@apply` and variants that change the target.
|
||||
//
|
||||
// The `:is` wrapper also keeps `has-group-*` from anchoring the group
|
||||
// itself to the element carrying the utility.
|
||||
node.selector = `:is(${selector} &)`
|
||||
|
||||
// Track that the variant was actually applied
|
||||
didApply = true
|
||||
|
|
@ -651,7 +657,7 @@ export function createVariants(theme: Theme): Variants {
|
|||
|
||||
// For most variants we rely entirely on CSS nesting to build-up the final
|
||||
// selector, but there is no way to use CSS nesting to make `&` refer to
|
||||
// just the `.group` class the way we'd need to for these variants, so we
|
||||
// just the `.peer` class the way we'd need to for these variants, so we
|
||||
// need to replace it in the selector ourselves.
|
||||
let selector = node.selector.replaceAll('&', variantSelector)
|
||||
|
||||
|
|
@ -662,7 +668,8 @@ export function createVariants(theme: Theme): Variants {
|
|||
selector = `:is(${selector})`
|
||||
}
|
||||
|
||||
node.selector = `&:is(${selector} ~ *)`
|
||||
// As with `group`, constrain the target without repeating its selector.
|
||||
node.selector = `:is(${selector} ~ &)`
|
||||
|
||||
// Track that the variant was actually applied
|
||||
didApply = true
|
||||
|
|
|
|||
|
|
@ -2387,6 +2387,120 @@ test('shadow DOM has access to variables', async ({ page }) => {
|
|||
}
|
||||
}
|
||||
|
||||
for (let kind of ['group', 'peer']) {
|
||||
test(`${kind}-* variants`, async ({ page }) => {
|
||||
let targets = html`
|
||||
<div id="target" class="${kind}-focus:z-10"></div>
|
||||
<div id="applied" class="applied"></div>
|
||||
`
|
||||
|
||||
let { getPropertyValue } = await render(
|
||||
page,
|
||||
kind === 'group'
|
||||
? html`<div id="trigger" tabindex="0" class="group owner">${targets}</div>`
|
||||
: html`<div class="owner">
|
||||
<div id="trigger" tabindex="0" class="peer"></div>
|
||||
${targets}
|
||||
</div>`,
|
||||
css`
|
||||
.owner > .applied {
|
||||
@apply ${kind}-focus:z-20;
|
||||
}
|
||||
`,
|
||||
)
|
||||
|
||||
expect(await getPropertyValue('#target', 'z-index')).toEqual('auto')
|
||||
expect(await getPropertyValue('#applied', 'z-index')).toEqual('auto')
|
||||
|
||||
await page.locator('#trigger').focus()
|
||||
|
||||
expect(await getPropertyValue('#target', 'z-index')).toEqual('10')
|
||||
expect(await getPropertyValue('#applied', 'z-index')).toEqual('20')
|
||||
|
||||
await page.locator('#trigger').blur()
|
||||
|
||||
expect(await getPropertyValue('#target', 'z-index')).toEqual('auto')
|
||||
expect(await getPropertyValue('#applied', 'z-index')).toEqual('auto')
|
||||
})
|
||||
}
|
||||
|
||||
test('group-* variants do not change specificity', async ({ page }) => {
|
||||
let { getPropertyValue } = await render(
|
||||
page,
|
||||
html`
|
||||
<div id="trigger" tabindex="0" class="group">
|
||||
<div id="target" class="target group-focus:z-10"></div>
|
||||
</div>
|
||||
`,
|
||||
css`
|
||||
@layer utilities {
|
||||
.target {
|
||||
z-index: 20;
|
||||
}
|
||||
.target.equal {
|
||||
z-index: 30;
|
||||
}
|
||||
}
|
||||
`,
|
||||
)
|
||||
|
||||
await page.locator('#trigger').focus()
|
||||
|
||||
expect(await getPropertyValue('#target', 'z-index')).toEqual('10')
|
||||
|
||||
await page.locator('#target').evaluate((element) => element.classList.add('equal'))
|
||||
|
||||
expect(await getPropertyValue('#target', 'z-index')).toEqual('30')
|
||||
})
|
||||
|
||||
test('stacked group-* variants match regardless of the order of the groups', async ({ page }) => {
|
||||
for (let [outer, inner] of [
|
||||
['a', 'b'],
|
||||
['b', 'a'],
|
||||
]) {
|
||||
let { getPropertyValue } = await render(
|
||||
page,
|
||||
html`
|
||||
<div class="group/${outer}" data-active>
|
||||
<div id="inner" class="group/${inner}" data-active>
|
||||
<div id="target" class="group-data-active/a:group-data-active/b:z-10"></div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
)
|
||||
|
||||
expect(await getPropertyValue('#target', 'z-index')).toEqual('10')
|
||||
|
||||
await page.locator('#inner').evaluate((element) => element.removeAttribute('data-active'))
|
||||
|
||||
expect(await getPropertyValue('#target', 'z-index')).toEqual('auto')
|
||||
}
|
||||
})
|
||||
|
||||
test('compound group-* and peer-* variants', async ({ page }) => {
|
||||
let { getPropertyValue } = await render(
|
||||
page,
|
||||
html`
|
||||
<div id="outer" tabindex="0" class="group">
|
||||
<div id="peer" tabindex="0" class="peer"></div>
|
||||
<div id="middle" class="group peer-group-focus:z-20">
|
||||
<div id="target" class="group-peer-focus:z-10"></div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
)
|
||||
|
||||
await page.locator('#peer').focus()
|
||||
|
||||
expect(await getPropertyValue('#target', 'z-index')).toEqual('10')
|
||||
expect(await getPropertyValue('#middle', 'z-index')).toEqual('auto')
|
||||
|
||||
await page.locator('#outer').focus()
|
||||
|
||||
expect(await getPropertyValue('#target', 'z-index')).toEqual('auto')
|
||||
expect(await getPropertyValue('#middle', 'z-index')).toEqual('20')
|
||||
})
|
||||
|
||||
// ---
|
||||
|
||||
const preflight = fs.readFileSync(path.resolve(__dirname, '..', 'preflight.css'), 'utf-8')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue