Add has-* variants for :has(...) pseudo-class (#11318)
* Add `has-*` variants for `:has(...)` pseudo-class * Update changelog * Fix mistake in test --------- Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This commit is contained in:
parent
b70f8fd036
commit
d72c1893c8
4 changed files with 148 additions and 0 deletions
|
|
@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
### Added
|
||||
|
||||
- Add `svh`, `lvh`, and `dvh` values to default `height`/`min-height`/`max-height` theme ([#11317](https://github.com/tailwindlabs/tailwindcss/pull/11317))
|
||||
- Add `has-*` variants for `:has(...)` pseudo-class ([#11318](https://github.com/tailwindlabs/tailwindcss/pull/11318))
|
||||
|
||||
## [3.3.7] - 2023-12-18
|
||||
|
||||
|
|
|
|||
|
|
@ -392,6 +392,26 @@ export let variantPlugins = {
|
|||
)
|
||||
},
|
||||
|
||||
hasVariants: ({ matchVariant }) => {
|
||||
matchVariant('has', (value) => `&:has(${normalize(value)})`, { values: {} })
|
||||
matchVariant(
|
||||
'group-has',
|
||||
(value, { modifier }) =>
|
||||
modifier
|
||||
? `:merge(.group\\/${modifier}):has(${normalize(value)}) &`
|
||||
: `:merge(.group):has(${normalize(value)}) &`,
|
||||
{ values: {} }
|
||||
)
|
||||
matchVariant(
|
||||
'peer-has',
|
||||
(value, { modifier }) =>
|
||||
modifier
|
||||
? `:merge(.peer\\/${modifier}):has(${normalize(value)}) ~ &`
|
||||
: `:merge(.peer):has(${normalize(value)}) ~ &`,
|
||||
{ values: {} }
|
||||
)
|
||||
},
|
||||
|
||||
ariaVariants: ({ matchVariant, theme }) => {
|
||||
matchVariant('aria', (value) => `&[aria-${normalize(value)}]`, { values: theme('aria') ?? {} })
|
||||
matchVariant(
|
||||
|
|
|
|||
|
|
@ -758,6 +758,7 @@ function resolvePlugins(context, root) {
|
|||
let beforeVariants = [
|
||||
variantPlugins['pseudoElementVariants'],
|
||||
variantPlugins['pseudoClassVariants'],
|
||||
variantPlugins['hasVariants'],
|
||||
variantPlugins['ariaVariants'],
|
||||
variantPlugins['dataVariants'],
|
||||
]
|
||||
|
|
|
|||
|
|
@ -845,6 +845,132 @@ crosscheck(({ stable, oxide }) => {
|
|||
})
|
||||
})
|
||||
|
||||
test('has-* variants with arbitrary values', () => {
|
||||
let config = {
|
||||
theme: {},
|
||||
content: [
|
||||
{
|
||||
raw: html`
|
||||
<div>
|
||||
<figure class="has-[figcaption]:inline-block"></figure>
|
||||
<div class="has-[.foo]:flex"></div>
|
||||
<div class="has-[.foo:hover]:block"></div>
|
||||
<div class="has-[[data-active]]:inline"></div>
|
||||
<div class="has-[>_.potato]:table"></div>
|
||||
<div class="has-[+_h2]:grid"></div>
|
||||
<div class="has-[>_h1_+_h2]:contents"></div>
|
||||
<div class="has-[h2]:has-[.banana]:hidden"></div>
|
||||
</div>
|
||||
`,
|
||||
},
|
||||
],
|
||||
corePlugins: { preflight: false },
|
||||
}
|
||||
|
||||
let input = css`
|
||||
@tailwind utilities;
|
||||
`
|
||||
|
||||
return run(input, config).then((result) => {
|
||||
expect(result.css).toMatchFormattedCss(css`
|
||||
.has-\[\.foo\:hover\]\:block:has(.foo:hover) {
|
||||
display: block;
|
||||
}
|
||||
.has-\[figcaption\]\:inline-block:has(figcaption) {
|
||||
display: inline-block;
|
||||
}
|
||||
.has-\[\[data-active\]\]\:inline:has([data-active]) {
|
||||
display: inline;
|
||||
}
|
||||
.has-\[\.foo\]\:flex:has(.foo) {
|
||||
display: flex;
|
||||
}
|
||||
.has-\[\>_\.potato\]\:table:has(> .potato) {
|
||||
display: table;
|
||||
}
|
||||
.has-\[\+_h2\]\:grid:has(+ h2) {
|
||||
display: grid;
|
||||
}
|
||||
.has-\[\>_h1_\+_h2\]\:contents:has(> h1 + h2) {
|
||||
display: contents;
|
||||
}
|
||||
.has-\[h2\]\:has-\[\.banana\]\:hidden:has(.banana):has(h2) {
|
||||
display: none;
|
||||
}
|
||||
`)
|
||||
})
|
||||
})
|
||||
|
||||
test('group-has-* variants with arbitrary values', () => {
|
||||
let config = {
|
||||
theme: {},
|
||||
content: [
|
||||
{
|
||||
raw: html`
|
||||
<div class="group">
|
||||
<div class="group-has-[>_h1_+_.foo]:block"></div>
|
||||
</div>
|
||||
<div class="group/two">
|
||||
<div class="group-has-[>_h1_+_.foo]/two:flex"></div>
|
||||
</div>
|
||||
`,
|
||||
},
|
||||
],
|
||||
corePlugins: { preflight: false },
|
||||
}
|
||||
|
||||
let input = css`
|
||||
@tailwind utilities;
|
||||
`
|
||||
|
||||
return run(input, config).then((result) => {
|
||||
expect(result.css).toMatchFormattedCss(css`
|
||||
.group:has(> h1 + .foo) .group-has-\[\>_h1_\+_\.foo\]\:block {
|
||||
display: block;
|
||||
}
|
||||
.group\/two:has(> h1 + .foo) .group-has-\[\>_h1_\+_\.foo\]\/two\:flex {
|
||||
display: flex;
|
||||
}
|
||||
`)
|
||||
})
|
||||
})
|
||||
|
||||
test('peer-has-* variants with arbitrary values', () => {
|
||||
let config = {
|
||||
theme: {},
|
||||
content: [
|
||||
{
|
||||
raw: html`
|
||||
<div>
|
||||
<div className="peer"></div>
|
||||
<div class="peer-has-[>_h1_+_.foo]:block"></div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="peer"></div>
|
||||
<div class="peer-has-[>_h1_+_.foo]/two:flex"></div>
|
||||
</div>
|
||||
`,
|
||||
},
|
||||
],
|
||||
corePlugins: { preflight: false },
|
||||
}
|
||||
|
||||
let input = css`
|
||||
@tailwind utilities;
|
||||
`
|
||||
|
||||
return run(input, config).then((result) => {
|
||||
expect(result.css).toMatchFormattedCss(css`
|
||||
.peer:has(> h1 + .foo) ~ .peer-has-\[\>_h1_\+_\.foo\]\:block {
|
||||
display: block;
|
||||
}
|
||||
.peer\/two:has(> h1 + .foo) ~ .peer-has-\[\>_h1_\+_\.foo\]\/two\:flex {
|
||||
display: flex;
|
||||
}
|
||||
`)
|
||||
})
|
||||
})
|
||||
|
||||
it('should be possible to use modifiers and arbitrary groups', () => {
|
||||
let config = {
|
||||
content: [
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue