Skip to content

Commit 1b651fc

Browse files
committed
Don’t prefix classes in arbitrary values for group and peer
1 parent 988f29b commit 1b651fc

File tree

3 files changed

+53
-2
lines changed

3 files changed

+53
-2
lines changed

src/corePlugins.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -187,9 +187,13 @@ export let variantPlugins = {
187187
}
188188

189189
// Basically this but can handle quotes:
190-
// result.replace(/&(\S+)?/g, (_, pseudo = '') => a + pseudo + b)
190+
// result.replace(/&(\S+)?/g, (_, pseudo = '') => a + `:tw-no-prefix(${pseudo})` + b)
191191

192-
return result.slice(0, start) + a + result.slice(start + 1, end) + b + result.slice(end)
192+
let pseudo = result.slice(start + 1, end)
193+
194+
pseudo = config('prefix') ? `:tw-no-prefix(${pseudo})` : pseudo
195+
196+
return result.slice(0, start) + a + pseudo + b + result.slice(end)
193197
},
194198
{ values: Object.fromEntries(pseudoVariants) }
195199
)

src/util/prefixSelector.js

+7
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ export default function (prefix, selector, prependNegative = false) {
2222

2323
// ast.walk bails too early when returning so it's not usable here
2424
function prefixClasses(node) {
25+
// Here we look for `:tw-no-prefix` which is an *internal-use-only* marker
26+
// used to stop traversal so we don't replace any classes inside it
27+
if (node.type === 'pseudo' && node.value === ':tw-no-prefix') {
28+
node.replaceWith(...node.nodes)
29+
return
30+
}
31+
2532
// Prefix any classes we find
2633
if (node.type === 'class') {
2734
let baseClass = node.value

tests/prefix.test.js

+40
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import prefixSelector from '../src/util/prefixSelector'
12
import { run, html, css, defaults } from './util/run'
23

34
test('prefix', () => {
@@ -607,3 +608,42 @@ test('supports non-word prefixes (2)', async () => {
607608
}
608609
`)
609610
})
611+
612+
test('does not prefix arbitrary group/peer classes', async () => {
613+
let config = {
614+
prefix: 'tw-',
615+
content: [
616+
{
617+
raw: html`
618+
<div class="tw-group tw-peer lol">
619+
<div class="group-[&.lol]:tw-flex"></div>
620+
</div>
621+
<div class="peer-[&.lol]:tw-flex"></div>
622+
`,
623+
},
624+
],
625+
corePlugins: { preflight: false },
626+
}
627+
628+
let input = css`
629+
@tailwind utilities;
630+
`
631+
632+
const result = await run(input, config)
633+
634+
expect(result.css).toMatchFormattedCss(css`
635+
.tw-group.lol .group-\[\&\.lol\]\:tw-flex,
636+
.tw-peer.lol ~ .peer-\[\&\.lol\]\:tw-flex {
637+
display: flex;
638+
}
639+
`)
640+
})
641+
642+
// Unit tests for prefixSelector
643+
describe('prefixSelector', () => {
644+
it('works', () => {
645+
expect(prefixSelector('tw-', '.foo', false)).toBe('.tw-foo')
646+
expect(prefixSelector('tw-', '.foo.bar.baz', false)).toBe('.tw-foo.tw-bar.tw-baz')
647+
expect(prefixSelector('tw-', '.foo:tw-no-prefix(.bar).baz', false)).toBe('.tw-foo.bar.tw-baz')
648+
})
649+
})

0 commit comments

Comments
 (0)