Skip to content

Commit c49cfed

Browse files
committed
wip: save
1 parent aec2dfb commit c49cfed

File tree

3 files changed

+122
-88
lines changed

3 files changed

+122
-88
lines changed

packages/runtime-core/src/renderer.ts

+12
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,18 @@ function baseCreateRenderer(
711711
if (needCallTransitionHooks) {
712712
transition!.beforeEnter(el)
713713
}
714+
715+
// For custom element with shadowRoot: false, the anchor node may be moved
716+
// to the slot container. In this case, it need to use the anchor's parent
717+
// node as the actual container.
718+
if (
719+
container._isVueCE &&
720+
container._def.shadowRoot === false &&
721+
anchor &&
722+
anchor.$parentNode
723+
) {
724+
container = anchor.$parentNode
725+
}
714726
hostInsert(el, container, anchor)
715727
if (
716728
(vnodeHook = props && props.onVnodeMounted) ||

packages/runtime-dom/__tests__/customElement.spec.ts

+89-84
Original file line numberDiff line numberDiff line change
@@ -1212,7 +1212,7 @@ describe('defineCustomElement', () => {
12121212
app.mount(container)
12131213
expect(container.innerHTML).toBe(
12141214
`<ce-shadow-root-false-optimized data-v-app="">` +
1215-
`<div>false</div><!--v-if-->` +
1215+
`<div>false</div><!--v-if--><!--v-if-->` +
12161216
`</ce-shadow-root-false-optimized>`,
12171217
)
12181218

@@ -1228,20 +1228,20 @@ describe('defineCustomElement', () => {
12281228
await nextTick()
12291229
expect(container.innerHTML).toBe(
12301230
`<ce-shadow-root-false-optimized data-v-app="">` +
1231-
`<div>false</div><!--v-if-->` +
1231+
`<div>false</div><!--v-if--><!--v-if-->` +
12321232
`</ce-shadow-root-false-optimized>`,
12331233
)
12341234

12351235
click()
12361236
await nextTick()
12371237
expect(container.innerHTML).toBe(
12381238
`<ce-shadow-root-false-optimized data-v-app="" is-shown="">` +
1239-
`<div><div>true</div><div>hi</div></div>` +
1239+
`<!--v-if--><div><div>true</div><div>hi</div></div>` +
12401240
`</ce-shadow-root-false-optimized>`,
12411241
)
12421242
})
12431243

1244-
test.todo('update slotted v-if nodes w/ shadowRoot false', async () => {
1244+
test('update slotted v-if nodes w/ shadowRoot false', async () => {
12451245
const E = defineCustomElement(
12461246
defineComponent({
12471247
props: {
@@ -1298,25 +1298,33 @@ describe('defineCustomElement', () => {
12981298
const app = createApp(App)
12991299
app.mount(container)
13001300
expect(container.innerHTML).toBe(
1301-
`<ce-shadow-root-false data-v-app=""><div>false</div><!--v-if--></ce-shadow-root-false>`,
1301+
`<ce-shadow-root-false data-v-app="">` +
1302+
`<div>false</div><!--v-if--><!--v-if-->` +
1303+
`</ce-shadow-root-false>`,
13021304
)
13031305

13041306
click()
13051307
await nextTick()
13061308
expect(container.innerHTML).toBe(
1307-
`<ce-shadow-root-false data-v-app="" is-shown=""><div><div>true</div><!--v-if--></div></ce-shadow-root-false>`,
1309+
`<ce-shadow-root-false data-v-app="" is-shown="">` +
1310+
`<div><div>true</div><!--v-if--></div>` +
1311+
`</ce-shadow-root-false>`,
13081312
)
13091313

13101314
click()
13111315
await nextTick()
13121316
expect(container.innerHTML).toBe(
1313-
`<ce-shadow-root-false data-v-app=""><div>false</div><!--v-if--></ce-shadow-root-false>`,
1317+
`<ce-shadow-root-false data-v-app="">` +
1318+
`<div>false</div><!--v-if--><!--v-if-->` +
1319+
`</ce-shadow-root-false>`,
13141320
)
13151321

13161322
click()
13171323
await nextTick()
13181324
expect(container.innerHTML).toBe(
1319-
`<ce-shadow-root-false data-v-app="" is-shown=""><div><div>true</div><div>hi</div></div></ce-shadow-root-false>`,
1325+
`<ce-shadow-root-false data-v-app="" is-shown="">` +
1326+
`<!--v-if--><div><div>true</div><div>hi</div></div>` +
1327+
`</ce-shadow-root-false>`,
13201328
)
13211329
})
13221330

@@ -1389,7 +1397,7 @@ describe('defineCustomElement', () => {
13891397
app.mount(container)
13901398
expect(container.innerHTML).toBe(
13911399
`<ce-with-fallback-shadow-root-false-optimized data-v-app="">` +
1392-
`fallback` +
1400+
`<!--v-if-->fallback` +
13931401
`</ce-with-fallback-shadow-root-false-optimized>`,
13941402
)
13951403

@@ -1405,90 +1413,87 @@ describe('defineCustomElement', () => {
14051413
await nextTick()
14061414
expect(container.innerHTML).toBe(
14071415
`<ce-with-fallback-shadow-root-false-optimized data-v-app="">` +
1408-
`fallback<!--v-if-->` +
1416+
`<!--v-if-->fallback` +
14091417
`</ce-with-fallback-shadow-root-false-optimized>`,
14101418
)
14111419
})
14121420

1413-
test.todo(
1414-
'switch between slotted and fallback nodes w/ shadowRoot false',
1415-
async () => {
1416-
const E = defineCustomElement(
1417-
defineComponent({
1418-
render() {
1419-
return renderSlot(this.$slots, 'foo', {}, () => [
1420-
createTextVNode('fallback'),
1421-
])
1422-
},
1423-
}),
1424-
{ shadowRoot: false },
1425-
)
1426-
customElements.define('ce-with-fallback-shadow-root-false', E)
1427-
1428-
const Comp = defineComponent({
1421+
test('switch between slotted and fallback nodes w/ shadowRoot false', async () => {
1422+
const E = defineCustomElement(
1423+
defineComponent({
14291424
render() {
1430-
return h('ce-with-fallback-shadow-root-false', null, [
1431-
this.$slots.foo
1432-
? h('div', { key: 0, slot: 'foo' }, [
1433-
renderSlot(this.$slots, 'foo'),
1434-
])
1435-
: createCommentVNode('v-if', true),
1436-
renderSlot(this.$slots, 'default'),
1425+
return renderSlot(this.$slots, 'foo', {}, () => [
1426+
createTextVNode('fallback'),
14371427
])
14381428
},
1439-
})
1429+
}),
1430+
{ shadowRoot: false },
1431+
)
1432+
customElements.define('ce-with-fallback-shadow-root-false', E)
14401433

1441-
const isShown = ref(false)
1442-
const App = defineComponent({
1443-
components: { Comp },
1444-
render() {
1445-
return h(
1446-
Comp,
1447-
null,
1448-
createSlots(
1449-
{ _: 2 /* DYNAMIC */ } as any,
1450-
[
1451-
isShown.value
1452-
? {
1453-
name: 'foo',
1454-
fn: withCtx(() => [createTextVNode('foo')]),
1455-
key: '0',
1456-
}
1457-
: undefined,
1458-
] as any,
1459-
),
1460-
)
1461-
},
1462-
})
1434+
const Comp = defineComponent({
1435+
render() {
1436+
return h('ce-with-fallback-shadow-root-false', null, [
1437+
this.$slots.foo
1438+
? h('div', { key: 0, slot: 'foo' }, [
1439+
renderSlot(this.$slots, 'foo'),
1440+
])
1441+
: createCommentVNode('v-if', true),
1442+
renderSlot(this.$slots, 'default'),
1443+
])
1444+
},
1445+
})
14631446

1464-
const container = document.createElement('div')
1465-
document.body.appendChild(container)
1466-
1467-
const app = createApp(App)
1468-
app.mount(container)
1469-
expect(container.innerHTML).toBe(
1470-
`<ce-with-fallback-shadow-root-false data-v-app="">` +
1471-
`fallback` +
1472-
`</ce-with-fallback-shadow-root-false>`,
1473-
)
1474-
1475-
isShown.value = true
1476-
await nextTick()
1477-
expect(container.innerHTML).toBe(
1478-
`<ce-with-fallback-shadow-root-false data-v-app="">` +
1479-
`<div slot="foo">foo</div>` +
1480-
`</ce-with-fallback-shadow-root-false>`,
1481-
)
1482-
1483-
isShown.value = false
1484-
await nextTick()
1485-
expect(container.innerHTML).toBe(
1486-
`<ce-with-fallback-shadow-root-false data-v-app="">` +
1487-
`fallback<!--v-if-->` +
1488-
`</ce-with-fallback-shadow-root-false>`,
1489-
)
1490-
},
1491-
)
1447+
const isShown = ref(false)
1448+
const App = defineComponent({
1449+
components: { Comp },
1450+
render() {
1451+
return h(
1452+
Comp,
1453+
null,
1454+
createSlots(
1455+
{ _: 2 /* DYNAMIC */ } as any,
1456+
[
1457+
isShown.value
1458+
? {
1459+
name: 'foo',
1460+
fn: withCtx(() => [createTextVNode('foo')]),
1461+
key: '0',
1462+
}
1463+
: undefined,
1464+
] as any,
1465+
),
1466+
)
1467+
},
1468+
})
1469+
1470+
const container = document.createElement('div')
1471+
document.body.appendChild(container)
1472+
1473+
const app = createApp(App)
1474+
app.mount(container)
1475+
expect(container.innerHTML).toBe(
1476+
`<ce-with-fallback-shadow-root-false data-v-app="">` +
1477+
`<!--v-if-->fallback` +
1478+
`</ce-with-fallback-shadow-root-false>`,
1479+
)
1480+
1481+
isShown.value = true
1482+
await nextTick()
1483+
expect(container.innerHTML).toBe(
1484+
`<ce-with-fallback-shadow-root-false data-v-app="">` +
1485+
`<div slot="foo">foo</div>` +
1486+
`</ce-with-fallback-shadow-root-false>`,
1487+
)
1488+
1489+
isShown.value = false
1490+
await nextTick()
1491+
expect(container.innerHTML).toBe(
1492+
`<ce-with-fallback-shadow-root-false data-v-app="">` +
1493+
`<!--v-if-->fallback` +
1494+
`</ce-with-fallback-shadow-root-false>`,
1495+
)
1496+
})
14921497
})
14931498

14941499
describe('helpers', () => {

packages/runtime-dom/src/apiCustomElement.ts

+21-4
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ export class VueElement
247247
private _slots?: Record<string, Node[]>
248248
private _slotFallbacks?: Record<string, Node[]>
249249
private _slotAnchors?: Map<string, Node>
250+
private _slotNames: Set<string> | undefined
250251

251252
constructor(
252253
/**
@@ -632,6 +633,7 @@ export class VueElement
632633
const slotName =
633634
(n.nodeType === 1 && (n as Element).getAttribute('slot')) || 'default'
634635
;(slots[slotName] || (slots[slotName] = [])).push(n)
636+
;(this._slotNames || (this._slotNames = new Set())).add(slotName)
635637
const next = n.nextSibling
636638
// store the parentNode reference since node will be removed
637639
// but it is needed during patching
@@ -679,11 +681,25 @@ export class VueElement
679681
if (!processedSlots.has('default')) {
680682
let content = this._slots!['default']
681683
if (content) {
682-
// TODO
683-
content = content.filter(
684-
n => !(n.nodeType === 8 && (n as Comment).data === 'v-if'),
684+
let anchor
685+
// if the default slot is not the first one, insert it behind the previous slot
686+
if (this._slotAnchors) {
687+
const slotNames = Array.from(this._slotNames!)
688+
const defaultSlotIndex = slotNames.indexOf('default')
689+
if (defaultSlotIndex > 0) {
690+
const prevSlotAnchor = this._slotAnchors!.get(
691+
slotNames[defaultSlotIndex - 1],
692+
)
693+
if (prevSlotAnchor) anchor = prevSlotAnchor.nextSibling
694+
}
695+
}
696+
697+
insertSlottedContent(
698+
content,
699+
scopeId,
700+
this._root,
701+
anchor || this.firstChild,
685702
)
686-
insertSlottedContent(content, scopeId, this, this.firstChild)
687703
}
688704
}
689705
}
@@ -830,6 +846,7 @@ function insertSlottedContent(
830846
;(child as Element).setAttribute(id, '')
831847
}
832848
}
849+
;(n as any).$parentNode = parent
833850
parent.insertBefore(n, anchor)
834851
}
835852
}

0 commit comments

Comments
 (0)