Skip to content

Commit

Permalink
Don’t prefix classes in arbitrary values for group and peer
Browse files Browse the repository at this point in the history
  • Loading branch information
thecrypticace committed Jun 19, 2023
1 parent 9bb2de0 commit 9fd458f
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 2 deletions.
10 changes: 8 additions & 2 deletions src/corePlugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,15 @@ export let variantPlugins = {
}

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

return result.slice(0, start) + a + result.slice(start + 1, end) + b + result.slice(end)
let pseudo = result.slice(start + 1, end)

pseudo = config('prefix')
? `:tw-no-prefix(${pseudo})`
: pseudo

return result.slice(0, start) + a + pseudo + b + result.slice(end)
},
{ values: Object.fromEntries(pseudoVariants) }
)
Expand Down
8 changes: 8 additions & 0 deletions src/util/prefixSelector.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ export default function (prefix, selector, prependNegative = false) {

// ast.walk bails to early when returning so it's not usable here
function prefixClasses(node) {
// Here we look for `:tw-no-prefix` which is an *internal-use-only* marker to:
// 1. Remove the wrapper
// 2. Stop traversal of child nodes so we don't replace any classes inside
if (node.type === 'pseudo' && node.value === ':tw-no-prefix') {
node.replaceWith(...node.nodes)
return
}

// Prefix any classes we find
if (node.type === 'class') {
let baseClass = node.value
Expand Down
43 changes: 43 additions & 0 deletions tests/prefix.test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import prefixSelector from '../src/util/prefixSelector.js'
import { run, html, css, defaults } from './util/run'

test('prefix', () => {
Expand Down Expand Up @@ -607,3 +608,45 @@ test('supports non-word prefixes (2)', async () => {
}
`)
})

test('does not prefix arbitrary group/peer classes', async () => {
let config = {
prefix: 'tw-',
content: [
{
raw: html`
<div class="tw-group tw-peer lol">
<div class="group-[&.lol]:tw-flex"></div>
</div>
<div class="peer-[&.lol]:tw-flex"></div>
`,
},
],
corePlugins: { preflight: false },
}

let input = css`
@tailwind utilities;
`

const result = await run(input, config)

// TODO: The class `.hover\:before\:\@\]\$content-\[\'Hovering\'\]:hover::before` is not generated
// This happens because of the parenthesis/brace/bracket clipping performed on candidates

expect(result.css).toMatchFormattedCss(css`
.tw-group.lol .group-\[\&\.lol\]\:tw-flex,
.tw-peer.lol ~ .peer-\[\&\.lol\]\:tw-flex {
display: flex;
}
`)
})

// Unit tests for prefixSelector
describe('prefixSelector', () => {
it('works', () => {
expect(prefixSelector('tw-', '.foo', false)).toBe('.tw-foo')
expect(prefixSelector('tw-', '.foo.bar.baz', false)).toBe('.tw-foo.tw-bar.tw-baz')
expect(prefixSelector('tw-', '.foo:tw-no-prefix(.bar).baz', false)).toBe('.tw-foo.bar.tw-baz')
})
})

0 comments on commit 9fd458f

Please sign in to comment.