Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Don’t prefix classes in arbitrary values for group and peer
  • Loading branch information
thecrypticace committed Jun 28, 2023
commit 1b651fc178bd6ed30cfc3b5f3a085623cba68b43
8 changes: 6 additions & 2 deletions src/corePlugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,13 @@ 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
7 changes: 7 additions & 0 deletions src/util/prefixSelector.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ export default function (prefix, selector, prependNegative = false) {

// ast.walk bails too 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
// used to stop traversal so we don't replace any classes inside it
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
40 changes: 40 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'
import { run, html, css, defaults } from './util/run'

test('prefix', () => {
Expand Down Expand Up @@ -607,3 +608,42 @@ 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)

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')
})
})