Skip to content

Commit

Permalink
Don't prefix classes in arbitrary values of has-*, group-has-*, a…
Browse files Browse the repository at this point in the history
…nd `peer-has-*` variants (#13770)

* Added tests to verify that classes are prefixed when using `has-*` variants with arbitrary values

* Fix test

* Don't prefix classes in arbitrary values in `has-*` variants

* Update changelog

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
  • Loading branch information
elalemanyo and thecrypticace authored Jun 1, 2024
1 parent 9fda461 commit 669109e
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed

- Make it possible to use multiple `<alpha-value>` placeholders in a single color definition ([#13740](https://github.com/tailwindlabs/tailwindcss/pull/13740))
- Don't prefix classes in arbitrary values of `has-*`, `group-has-*`, and `peer-has-*` variants ([#13770](https://github.com/tailwindlabs/tailwindcss/pull/13770))

## [3.4.3] - 2024-03-27

Expand Down
33 changes: 25 additions & 8 deletions src/corePlugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -434,23 +434,40 @@ export let variantPlugins = {
)
},

hasVariants: ({ matchVariant }) => {
matchVariant('has', (value) => `&:has(${normalize(value)})`, { values: {} })
hasVariants: ({ matchVariant, prefix }) => {
matchVariant('has', (value) => `&:has(${normalize(value)})`, {
values: {},
[INTERNAL_FEATURES]: {
respectPrefix: false,
},
})

matchVariant(
'group-has',
(value, { modifier }) =>
modifier
? `:merge(.group\\/${modifier}):has(${normalize(value)}) &`
: `:merge(.group):has(${normalize(value)}) &`,
{ values: {} }
? `:merge(${prefix('.group')}\\/${modifier}):has(${normalize(value)}) &`
: `:merge(${prefix('.group')}):has(${normalize(value)}) &`,
{
values: {},
[INTERNAL_FEATURES]: {
respectPrefix: false,
},
}
)

matchVariant(
'peer-has',
(value, { modifier }) =>
modifier
? `:merge(.peer\\/${modifier}):has(${normalize(value)}) ~ &`
: `:merge(.peer):has(${normalize(value)}) ~ &`,
{ values: {} }
? `:merge(${prefix('.peer')}\\/${modifier}):has(${normalize(value)}) ~ &`
: `:merge(${prefix('.peer')}):has(${normalize(value)}) ~ &`,
{
values: {},
[INTERNAL_FEATURES]: {
respectPrefix: false,
},
}
)
},

Expand Down
129 changes: 129 additions & 0 deletions tests/prefix.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -637,3 +637,132 @@ test('does not prefix arbitrary group/peer classes', async () => {
}
`)
})

test('does not prefix has-* variants with arbitrary values', async () => {
let config = {
prefix: 'tw-',
content: [
{
raw: html`
<div class="has-[.active]:tw-flex foo">
<figure class="has-[figcaption]:tw-inline-block"></figure>
<div class="has-[.foo]:tw-flex"></div>
<div class="has-[.foo:hover]:tw-block"></div>
<div class="has-[[data-active]]:tw-inline"></div>
<div class="has-[>_.potato]:tw-table"></div>
<div class="has-[+_h2]:tw-grid"></div>
<div class="has-[>_h1_+_h2]:tw-contents"></div>
<div class="has-[h2]:has-[.banana]:tw-hidden"></div>
</div>
`,
},
],
corePlugins: { preflight: false },
}

let input = css`
@tailwind utilities;
`

const result = await run(input, config)

expect(result.css).toMatchFormattedCss(css`
.has-\[\.foo\:hover\]\:tw-block:has(.foo:hover) {
display: block;
}
.has-\[figcaption\]\:tw-inline-block:has(figcaption) {
display: inline-block;
}
.has-\[\[data-active\]\]\:tw-inline:has([data-active]) {
display: inline;
}
.has-\[\.active\]\:tw-flex:has(.active),
.has-\[\.foo\]\:tw-flex:has(.foo) {
display: flex;
}
.has-\[\>_\.potato\]\:tw-table:has(> .potato) {
display: table;
}
.has-\[\+_h2\]\:tw-grid:has(+ h2) {
display: grid;
}
.has-\[\>_h1_\+_h2\]\:tw-contents:has(> h1 + h2) {
display: contents;
}
.has-\[h2\]\:has-\[\.banana\]\:tw-hidden:has(.banana):has(h2) {
display: none;
}
`)
})

test('does not prefix group-has-* variants with arbitrary values', () => {
let config = {
prefix: 'tw-',
theme: {},
content: [
{
raw: html`
<div class="tw-group">
<div class="group-has-[>_h1_+_.foo]:tw-block"></div>
</div>
<div class="tw-group/two">
<div class="group-has-[>_h1_+_.foo]/two:tw-flex"></div>
</div>
`,
},
],
corePlugins: { preflight: false },
}

let input = css`
@tailwind utilities;
`

return run(input, config).then((result) => {
expect(result.css).toMatchFormattedCss(css`
.tw-group:has(> h1 + .foo) .group-has-\[\>_h1_\+_\.foo\]\:tw-block {
display: block;
}
.tw-group\/two:has(> h1 + .foo) .group-has-\[\>_h1_\+_\.foo\]\/two\:tw-flex {
display: flex;
}
`)
})
})

test('does not prefix peer-has-* variants with arbitrary values', () => {
let config = {
prefix: 'tw-',
theme: {},
content: [
{
raw: html`
<div>
<div className="tw-peer"></div>
<div class="peer-has-[>_h1_+_.foo]:tw-block"></div>
</div>
<div>
<div className="tw-peer"></div>
<div class="peer-has-[>_h1_+_.foo]/two:tw-flex"></div>
</div>
`,
},
],
corePlugins: { preflight: false },
}

let input = css`
@tailwind utilities;
`

return run(input, config).then((result) => {
expect(result.css).toMatchFormattedCss(css`
.tw-peer:has(> h1 + .foo) ~ .peer-has-\[\>_h1_\+_\.foo\]\:tw-block {
display: block;
}
.tw-peer\/two:has(> h1 + .foo) ~ .peer-has-\[\>_h1_\+_\.foo\]\/two\:tw-flex {
display: flex;
}
`)
})
})

0 comments on commit 669109e

Please sign in to comment.