Skip to content

Commit e5c1f9a

Browse files
authored
fix(transformer-directives): resolve selector group (#3485)
1 parent cb0849a commit e5c1f9a

File tree

2 files changed

+46
-12
lines changed

2 files changed

+46
-12
lines changed

packages/transformer-directives/src/apply.ts

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { StringifiedUtil } from '@unocss/core'
22
import { expandVariantGroup, notNull, regexScopePlaceholder } from '@unocss/core'
33
import type { CssNode, Rule, Selector, SelectorList } from 'css-tree'
4-
import { clone, generate, parse } from 'css-tree'
4+
import { List, clone, generate, parse } from 'css-tree'
55
import type { TransformerDirectivesContext } from '.'
66
import { transformDirectives } from '.'
77

@@ -63,24 +63,28 @@ export async function parseApply({ code, uno, offset, applyVariable }: Transform
6363

6464
for (const i of utils) {
6565
const [, _selector, body, parent] = i
66-
const selector = _selector?.replace(regexScopePlaceholder, ' ') || _selector
66+
const selectorOrGroup = _selector?.replace(regexScopePlaceholder, ' ') || _selector
6767

68-
if (parent || (selector && selector !== '.\\-')) {
68+
if (parent || (selectorOrGroup && selectorOrGroup !== '.\\-')) {
6969
let newSelector = generate(node.prelude)
70-
if (selector && selector !== '.\\-') {
71-
const selectorAST = parse(selector, {
72-
context: 'selector',
73-
}) as Selector
70+
if (selectorOrGroup && selectorOrGroup !== '.\\-') {
71+
// use rule context since it could be a selector(.foo) or a selector group(.foo, .bar)
72+
const ruleAST = parse(`${selectorOrGroup}{}`, {
73+
context: 'rule',
74+
}) as Rule
7475

7576
const prelude = clone(node.prelude) as SelectorList
7677

7778
prelude.children.forEach((child) => {
78-
const parentSelectorAst = clone(selectorAST) as Selector
79-
parentSelectorAst.children.forEach((i) => {
80-
if (i.type === 'ClassSelector' && i.name === '\\-')
81-
Object.assign(i, clone(child))
79+
const selectorListAst = clone(ruleAST.prelude) as SelectorList
80+
const classSelectors: List<CssNode> = new List()
81+
82+
selectorListAst.children.forEach((selectorAst) => {
83+
classSelectors.appendList((selectorAst as Selector).children.filter(i => i.type === 'ClassSelector' && i.name === '\\-'))
8284
})
83-
Object.assign(child, parentSelectorAst)
85+
classSelectors.forEach(i => Object.assign(i, clone(child)))
86+
87+
Object.assign(child, selectorListAst)
8488
})
8589
newSelector = generate(prelude)
8690
}

test/transformer-directives.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,19 @@ describe('transformer-directives', () => {
3434
xxl: '1536px',
3535
},
3636
},
37+
variants: [
38+
(matcher) => {
39+
const prefix = 'sgroup:' // selector group
40+
41+
if (!matcher.startsWith(prefix))
42+
return matcher
43+
44+
return {
45+
matcher: matcher.slice(prefix.length),
46+
selector: s => `${s}:hover, ${s}:focus`,
47+
}
48+
},
49+
],
3750
})
3851

3952
async function transform(code: string, _uno: UnoGenerator = uno) {
@@ -529,4 +542,21 @@ div {
529542
"
530543
`)
531544
})
545+
546+
it('@apply selector group', async () => {
547+
const result = await transform(
548+
'.btn { @apply: sgroup:bg-orange }',
549+
)
550+
expect(result)
551+
.toMatchInlineSnapshot(`
552+
".btn {
553+
}
554+
.btn:hover,
555+
.btn:focus {
556+
--un-bg-opacity: 1;
557+
background-color: rgb(251 146 60 / var(--un-bg-opacity));
558+
}
559+
"
560+
`)
561+
})
532562
})

0 commit comments

Comments
 (0)