Skip to content

Commit 3ab4964

Browse files
committed
feat(compiler-sfc): deep selector supports multiple values
1 parent a778034 commit 3ab4964

File tree

2 files changed

+105
-13
lines changed

2 files changed

+105
-13
lines changed

packages/compiler-sfc/__tests__/compileStyle.spec.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,36 @@ describe('SFC scoped CSS', () => {
7070
"[data-v-test] .foo { color: red;
7171
}"
7272
`)
73+
expect(compileScoped(`:deep(.foo) .bar { color: red; }`))
74+
.toMatchInlineSnapshot(`
75+
"[data-v-test] .foo .bar { color: red;
76+
}"
77+
`)
78+
expect(compileScoped(`::v-deep(.foo,.baz) { color: red; }`))
79+
.toMatchInlineSnapshot(`
80+
"[data-v-test] .foo,[data-v-test] .baz { color: red;
81+
}"
82+
`)
83+
expect(compileScoped(`::v-deep(.foo,.baz,.bar,.fcc) { color: red; }`))
84+
.toMatchInlineSnapshot(`
85+
"[data-v-test] .foo,[data-v-test] .baz,[data-v-test] .bar,[data-v-test] .fcc { color: red;
86+
}"
87+
`)
88+
expect(compileScoped(`::v-deep(.foo,.baz) .fc { color: red; }`))
89+
.toMatchInlineSnapshot(`
90+
"[data-v-test] .foo .fc,[data-v-test] .baz .fc { color: red;
91+
}"
92+
`)
93+
expect(compileScoped(`::v-deep(.foo,.baz .bar) .fc { color: red; }`))
94+
.toMatchInlineSnapshot(`
95+
"[data-v-test] .foo .fc,[data-v-test] .baz .bar .fc { color: red;
96+
}"
97+
`)
98+
expect(compileScoped(`.bar :deep(.foo,.baz,.abc) { color: red; }`))
99+
.toMatchInlineSnapshot(`
100+
".bar[data-v-test] .foo,.bar[data-v-test] .baz,.bar[data-v-test] .abc { color: red;
101+
}"
102+
`)
73103
expect(compileScoped(`::v-deep(.foo) { color: red; }`))
74104
.toMatchInlineSnapshot(`
75105
"[data-v-test] .foo { color: red;
@@ -85,6 +115,16 @@ describe('SFC scoped CSS', () => {
85115
".baz .qux[data-v-test] .foo .bar { color: red;
86116
}"
87117
`)
118+
expect(compileScoped(`.baz .qux ::v-deep(.foo,.bar) { color: red; }`))
119+
.toMatchInlineSnapshot(`
120+
".baz .qux[data-v-test] .foo,.baz .qux[data-v-test] .bar { color: red;
121+
}"
122+
`)
123+
expect(compileScoped(`.baz .qux ::v-deep(.foo,.bar) .m { color: red; }`))
124+
.toMatchInlineSnapshot(`
125+
".baz .qux[data-v-test] .foo .m,.baz .qux[data-v-test] .bar .m { color: red;
126+
}"
127+
`)
88128
})
89129

90130
test('::v-slotted', () => {

packages/compiler-sfc/src/style/pluginScoped.ts

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ function rewriteSelector(
8585
slotted = false
8686
) {
8787
let node: selectorParser.Node | null = null
88+
const nodes: (selectorParser.Node | null)[] = []
89+
const nextNodes = [] as typeof selector.nodes
8890
let shouldInject = true
8991
// find the last child node to insert attribute selector
9092
selector.each(n => {
@@ -111,9 +113,55 @@ function rewriteSelector(
111113
// .foo ::v-deep(.bar) -> .foo[xxxxxxx] .bar
112114
// replace the current node with ::v-deep's inner selector
113115
let last: selectorParser.Selector['nodes'][0] = n
114-
n.nodes[0].each(ss => {
115-
selector.insertAfter(last, ss)
116-
last = ss
116+
if (node) {
117+
nodes.push(node)
118+
}
119+
n.nodes.forEach((_node, i) => {
120+
const index = selector.index(n)
121+
if (i > 0) {
122+
const prevList = selector.nodes
123+
.slice(0, index)
124+
.concat(_node.nodes)
125+
if (nextNodes.length) {
126+
prevList.push(...nextNodes)
127+
nextNodes.forEach(s => {
128+
selector.removeChild(s)
129+
selector.insertAfter(last, s)
130+
last = s
131+
})
132+
}
133+
const newList = prevList.map(s => {
134+
const _newNode = s.clone(
135+
{}
136+
) as selectorParser.Selector['nodes'][0]
137+
if (nodes.includes(s)) {
138+
nodes.push(_newNode)
139+
}
140+
return _newNode
141+
})
142+
newList.unshift(selectorParser.combinator({ value: ',' }))
143+
if (!nodes.length) {
144+
nodes.push(null, newList[0])
145+
} else {
146+
// :deep(.a,.b,.c) -> [xxx] .a,[xxx] .b,[xxx] .c
147+
if (nodes[0] === null) {
148+
nodes.push(newList[0])
149+
}
150+
}
151+
if (!node) {
152+
newList.splice(1, 0, selectorParser.combinator({ value: ' ' }))
153+
}
154+
newList.forEach(s => {
155+
selector.insertAfter(last, s)
156+
last = s
157+
})
158+
} else {
159+
nextNodes.push(...selector.nodes.slice(index + 1))
160+
_node.each(ss => {
161+
selector.insertAfter(last, ss)
162+
last = ss
163+
})
164+
}
117165
})
118166
// insert a space combinator before if it doesn't already have one
119167
const prev = selector.at(selector.index(n) - 1)
@@ -173,7 +221,9 @@ function rewriteSelector(
173221
node = n
174222
}
175223
})
176-
224+
if (!nodes.length) {
225+
nodes.push(node)
226+
}
177227
if (node) {
178228
;(node as selectorParser.Node).spaces.after = ''
179229
} else {
@@ -185,17 +235,19 @@ function rewriteSelector(
185235

186236
if (shouldInject) {
187237
const idToAdd = slotted ? id + '-s' : id
188-
selector.insertAfter(
238+
nodes.forEach(n => {
189239
// If node is null it means we need to inject [id] at the start
190240
// insertAfter can handle `null` here
191-
node as any,
192-
selectorParser.attribute({
193-
attribute: idToAdd,
194-
value: idToAdd,
195-
raws: {},
196-
quoteMark: `"`
197-
})
198-
)
241+
selector.insertAfter(
242+
n as any,
243+
selectorParser.attribute({
244+
attribute: idToAdd,
245+
value: idToAdd,
246+
raws: {},
247+
quoteMark: `"`
248+
})
249+
)
250+
})
199251
}
200252
}
201253

0 commit comments

Comments
 (0)