Skip to content

Commit 669109e

Browse files
Don't prefix classes in arbitrary values of has-*, group-has-*, and 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 <[email protected]>
1 parent 9fda461 commit 669109e

File tree

3 files changed

+155
-8
lines changed

3 files changed

+155
-8
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Fixed
1111

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

1415
## [3.4.3] - 2024-03-27
1516

src/corePlugins.js

+25-8
Original file line numberDiff line numberDiff line change
@@ -434,23 +434,40 @@ export let variantPlugins = {
434434
)
435435
},
436436

437-
hasVariants: ({ matchVariant }) => {
438-
matchVariant('has', (value) => `&:has(${normalize(value)})`, { values: {} })
437+
hasVariants: ({ matchVariant, prefix }) => {
438+
matchVariant('has', (value) => `&:has(${normalize(value)})`, {
439+
values: {},
440+
[INTERNAL_FEATURES]: {
441+
respectPrefix: false,
442+
},
443+
})
444+
439445
matchVariant(
440446
'group-has',
441447
(value, { modifier }) =>
442448
modifier
443-
? `:merge(.group\\/${modifier}):has(${normalize(value)}) &`
444-
: `:merge(.group):has(${normalize(value)}) &`,
445-
{ values: {} }
449+
? `:merge(${prefix('.group')}\\/${modifier}):has(${normalize(value)}) &`
450+
: `:merge(${prefix('.group')}):has(${normalize(value)}) &`,
451+
{
452+
values: {},
453+
[INTERNAL_FEATURES]: {
454+
respectPrefix: false,
455+
},
456+
}
446457
)
458+
447459
matchVariant(
448460
'peer-has',
449461
(value, { modifier }) =>
450462
modifier
451-
? `:merge(.peer\\/${modifier}):has(${normalize(value)}) ~ &`
452-
: `:merge(.peer):has(${normalize(value)}) ~ &`,
453-
{ values: {} }
463+
? `:merge(${prefix('.peer')}\\/${modifier}):has(${normalize(value)}) ~ &`
464+
: `:merge(${prefix('.peer')}):has(${normalize(value)}) ~ &`,
465+
{
466+
values: {},
467+
[INTERNAL_FEATURES]: {
468+
respectPrefix: false,
469+
},
470+
}
454471
)
455472
},
456473

tests/prefix.test.js

+129
Original file line numberDiff line numberDiff line change
@@ -637,3 +637,132 @@ test('does not prefix arbitrary group/peer classes', async () => {
637637
}
638638
`)
639639
})
640+
641+
test('does not prefix has-* variants with arbitrary values', async () => {
642+
let config = {
643+
prefix: 'tw-',
644+
content: [
645+
{
646+
raw: html`
647+
<div class="has-[.active]:tw-flex foo">
648+
<figure class="has-[figcaption]:tw-inline-block"></figure>
649+
<div class="has-[.foo]:tw-flex"></div>
650+
<div class="has-[.foo:hover]:tw-block"></div>
651+
<div class="has-[[data-active]]:tw-inline"></div>
652+
<div class="has-[>_.potato]:tw-table"></div>
653+
<div class="has-[+_h2]:tw-grid"></div>
654+
<div class="has-[>_h1_+_h2]:tw-contents"></div>
655+
<div class="has-[h2]:has-[.banana]:tw-hidden"></div>
656+
</div>
657+
`,
658+
},
659+
],
660+
corePlugins: { preflight: false },
661+
}
662+
663+
let input = css`
664+
@tailwind utilities;
665+
`
666+
667+
const result = await run(input, config)
668+
669+
expect(result.css).toMatchFormattedCss(css`
670+
.has-\[\.foo\:hover\]\:tw-block:has(.foo:hover) {
671+
display: block;
672+
}
673+
.has-\[figcaption\]\:tw-inline-block:has(figcaption) {
674+
display: inline-block;
675+
}
676+
.has-\[\[data-active\]\]\:tw-inline:has([data-active]) {
677+
display: inline;
678+
}
679+
.has-\[\.active\]\:tw-flex:has(.active),
680+
.has-\[\.foo\]\:tw-flex:has(.foo) {
681+
display: flex;
682+
}
683+
.has-\[\>_\.potato\]\:tw-table:has(> .potato) {
684+
display: table;
685+
}
686+
.has-\[\+_h2\]\:tw-grid:has(+ h2) {
687+
display: grid;
688+
}
689+
.has-\[\>_h1_\+_h2\]\:tw-contents:has(> h1 + h2) {
690+
display: contents;
691+
}
692+
.has-\[h2\]\:has-\[\.banana\]\:tw-hidden:has(.banana):has(h2) {
693+
display: none;
694+
}
695+
`)
696+
})
697+
698+
test('does not prefix group-has-* variants with arbitrary values', () => {
699+
let config = {
700+
prefix: 'tw-',
701+
theme: {},
702+
content: [
703+
{
704+
raw: html`
705+
<div class="tw-group">
706+
<div class="group-has-[>_h1_+_.foo]:tw-block"></div>
707+
</div>
708+
<div class="tw-group/two">
709+
<div class="group-has-[>_h1_+_.foo]/two:tw-flex"></div>
710+
</div>
711+
`,
712+
},
713+
],
714+
corePlugins: { preflight: false },
715+
}
716+
717+
let input = css`
718+
@tailwind utilities;
719+
`
720+
721+
return run(input, config).then((result) => {
722+
expect(result.css).toMatchFormattedCss(css`
723+
.tw-group:has(> h1 + .foo) .group-has-\[\>_h1_\+_\.foo\]\:tw-block {
724+
display: block;
725+
}
726+
.tw-group\/two:has(> h1 + .foo) .group-has-\[\>_h1_\+_\.foo\]\/two\:tw-flex {
727+
display: flex;
728+
}
729+
`)
730+
})
731+
})
732+
733+
test('does not prefix peer-has-* variants with arbitrary values', () => {
734+
let config = {
735+
prefix: 'tw-',
736+
theme: {},
737+
content: [
738+
{
739+
raw: html`
740+
<div>
741+
<div className="tw-peer"></div>
742+
<div class="peer-has-[>_h1_+_.foo]:tw-block"></div>
743+
</div>
744+
<div>
745+
<div className="tw-peer"></div>
746+
<div class="peer-has-[>_h1_+_.foo]/two:tw-flex"></div>
747+
</div>
748+
`,
749+
},
750+
],
751+
corePlugins: { preflight: false },
752+
}
753+
754+
let input = css`
755+
@tailwind utilities;
756+
`
757+
758+
return run(input, config).then((result) => {
759+
expect(result.css).toMatchFormattedCss(css`
760+
.tw-peer:has(> h1 + .foo) ~ .peer-has-\[\>_h1_\+_\.foo\]\:tw-block {
761+
display: block;
762+
}
763+
.tw-peer\/two:has(> h1 + .foo) ~ .peer-has-\[\>_h1_\+_\.foo\]\/two\:tw-flex {
764+
display: flex;
765+
}
766+
`)
767+
})
768+
})

0 commit comments

Comments
 (0)