Skip to content

Commit

Permalink
fix(compiler-sfc): correct scoped injection for nesting selector (#11854
Browse files Browse the repository at this point in the history
)

close #10567
  • Loading branch information
KazariEX committed Sep 10, 2024
1 parent fe2ab1b commit b1de75e
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 5 deletions.
13 changes: 13 additions & 0 deletions packages/compiler-sfc/__tests__/compileStyle.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ describe('SFC scoped CSS', () => {
)
})

test('nesting selector', () => {
expect(compileScoped(`h1 { color: red; .foo { color: red; } }`)).toMatch(
`h1 {\n&[data-v-test] { color: red;\n}\n.foo[data-v-test] { color: red;`,
)
})

test('multiple selectors', () => {
expect(compileScoped(`h1 .foo, .bar, .baz { color: red; }`)).toMatch(
`h1 .foo[data-v-test], .bar[data-v-test], .baz[data-v-test] { color: red;`,
Expand Down Expand Up @@ -95,6 +101,13 @@ describe('SFC scoped CSS', () => {
":where(.foo[data-v-test] .bar) { color: red;
}"
`)
expect(compileScoped(`:deep(.foo) { color: red; .bar { color: red; } }`))
.toMatchInlineSnapshot(`
"[data-v-test] .foo { color: red;
.bar { color: red;
}
}"
`)
})

test('::v-slotted', () => {
Expand Down
51 changes: 46 additions & 5 deletions packages/compiler-sfc/src/style/pluginScoped.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import type { AtRule, PluginCreator, Rule } from 'postcss'
import {
type AtRule,
type Container,
type Document,
type PluginCreator,
Rule,
} from 'postcss'
import selectorParser from 'postcss-selector-parser'
import { warn } from '../warn'

Expand Down Expand Up @@ -71,21 +77,32 @@ function processRule(id: string, rule: Rule) {
return
}
processedRules.add(rule)
let deep = false
let parent: Document | Container | undefined = rule.parent
while (parent && parent.type !== 'root') {
if ((parent as any).__deep) {
deep = true
break
}
parent = parent.parent
}
rule.selector = selectorParser(selectorRoot => {
selectorRoot.each(selector => {
rewriteSelector(id, selector, selectorRoot)
rewriteSelector(id, rule, selector, selectorRoot, deep)
})
}).processSync(rule.selector)
}

function rewriteSelector(
id: string,
rule: Rule,
selector: selectorParser.Selector,
selectorRoot: selectorParser.Root,
deep: boolean,
slotted = false,
) {
let node: selectorParser.Node | null = null
let shouldInject = true
let shouldInject = !deep
// find the last child node to insert attribute selector
selector.each(n => {
// DEPRECATED ">>>" and "/deep/" combinator
Expand All @@ -107,6 +124,7 @@ function rewriteSelector(
// deep: inject [id] attribute at the node before the ::v-deep
// combinator.
if (value === ':deep' || value === '::v-deep') {
;(rule as any).__deep = true
if (n.nodes.length) {
// .foo ::v-deep(.bar) -> .foo[xxxxxxx] .bar
// replace the current node with ::v-deep's inner selector
Expand Down Expand Up @@ -147,7 +165,14 @@ function rewriteSelector(
// instead.
// ::v-slotted(.foo) -> .foo[xxxxxxx-s]
if (value === ':slotted' || value === '::v-slotted') {
rewriteSelector(id, n.nodes[0], selectorRoot, true /* slotted */)
rewriteSelector(
id,
rule,
n.nodes[0],
selectorRoot,
deep,
true /* slotted */,
)
let last: selectorParser.Selector['nodes'][0] = n
n.nodes[0].each(ss => {
selector.insertAfter(last, ss)
Expand Down Expand Up @@ -206,11 +231,27 @@ function rewriteSelector(
}
})

if (rule.nodes.some(node => node.type === 'rule')) {
const deep = (rule as any).__deep
const decls = rule.nodes.filter(node => node.type === 'decl')
if (!deep && decls.length) {
for (const decl of decls) {
rule.removeChild(decl)
}
const hostRule = new Rule({
nodes: decls,
selector: '&',
})
rule.prepend(hostRule)
}
shouldInject = deep
}

if (node) {
const { type, value } = node as selectorParser.Node
if (type === 'pseudo' && (value === ':is' || value === ':where')) {
;(node as selectorParser.Pseudo).nodes.forEach(value =>
rewriteSelector(id, value, selectorRoot, slotted),
rewriteSelector(id, rule, value, selectorRoot, deep, slotted),
)
shouldInject = false
}
Expand Down

0 comments on commit b1de75e

Please sign in to comment.