Skip to content

Commit 836db6b

Browse files
committed
wip: save
1 parent 4edb144 commit 836db6b

File tree

2 files changed

+65
-4
lines changed

2 files changed

+65
-4
lines changed

packages/runtime-dom/src/apiCustomElement.ts

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -632,11 +632,15 @@ export abstract class VueElementBase<
632632
protected _renderSlots(): void {
633633
const outlets = this._getSlots()
634634
const scopeId = this._instance!.type.__scopeId
635+
const slotReplacements: Map<Node, Node[]> = new Map()
636+
635637
for (let i = 0; i < outlets.length; i++) {
636638
const o = outlets[i] as HTMLSlotElement
637639
const slotName = o.getAttribute('name') || 'default'
638640
const content = this._slots![slotName]
639641
const parent = o.parentNode!
642+
const replacementNodes: Node[] = []
643+
640644
if (content) {
641645
for (const n of content) {
642646
// for :slotted css
@@ -650,11 +654,66 @@ export abstract class VueElementBase<
650654
}
651655
}
652656
parent.insertBefore(n, o)
657+
replacementNodes.push(n)
658+
}
659+
} else {
660+
while (o.firstChild) {
661+
const child = o.firstChild
662+
parent.insertBefore(child, o)
663+
replacementNodes.push(child)
664+
}
665+
}
666+
667+
slotReplacements.set(o, replacementNodes)
668+
}
669+
670+
// For Vapor: update fragment nodes before removing slots from DOM
671+
if (slotReplacements.size > 0 && this._instance && this._instance.vapor) {
672+
// @ts-expect-error TODO refactor
673+
this._replaceNodesInFragments(this._instance.block, slotReplacements)
674+
}
675+
676+
// Now safe to remove slots from DOM
677+
slotReplacements.forEach((_, o) => o.parentNode!.removeChild(o))
678+
}
679+
680+
/**
681+
* Replace slot nodes with their content in fragment nodes arrays
682+
* @internal
683+
*/
684+
private _replaceNodesInFragments(
685+
block: any,
686+
replacements: Map<Node, Node[]>,
687+
): void {
688+
if (!block) return
689+
690+
if (Array.isArray(block)) {
691+
for (let i = 0; i < block.length; i++) {
692+
this._replaceNodesInFragments(block[i], replacements)
693+
}
694+
} else if (block.nodes !== undefined) {
695+
// This is a fragment with nodes property
696+
if (Array.isArray(block.nodes)) {
697+
// Replace slot nodes with their content
698+
const newNodes: any[] = []
699+
for (const node of block.nodes) {
700+
if (node instanceof Node && replacements.has(node)) {
701+
// Replace with the content nodes
702+
newNodes.push(...replacements.get(node)!)
703+
} else {
704+
newNodes.push(node)
705+
// Recursively process nested fragments
706+
this._replaceNodesInFragments(node, replacements)
707+
}
653708
}
709+
block.nodes = newNodes
710+
} else if (block.nodes instanceof Node && replacements.has(block.nodes)) {
711+
// Replace single node with its content
712+
const replacement = replacements.get(block.nodes)!
713+
block.nodes = replacement.length === 1 ? replacement[0] : replacement
654714
} else {
655-
while (o.firstChild) parent.insertBefore(o.firstChild, o)
715+
this._replaceNodesInFragments(block.nodes, replacements)
656716
}
657-
parent.removeChild(o)
658717
}
659718
}
660719

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1344,7 +1344,7 @@ describe('defineVaporCustomElement', () => {
13441344
)
13451345
customElements.define('my-el-shadowroot-false-slots', ES)
13461346

1347-
test.todo('should render slots', async () => {
1347+
test('should render slots', async () => {
13481348
container.innerHTML =
13491349
`<my-el-shadowroot-false-slots>` +
13501350
`<span>default</span>text` +
@@ -1362,7 +1362,9 @@ describe('defineVaporCustomElement', () => {
13621362
toggle.value = false
13631363
await nextTick()
13641364
expect(e.innerHTML).toBe(
1365-
`<span>default</span>text` + `<!--if-->` + `<div>fallback</div>`,
1365+
`<span>default</span>text<!--slot-->` +
1366+
`<!--if-->` +
1367+
`<div>fallback</div><!--slot-->`,
13661368
)
13671369
})
13681370

0 commit comments

Comments
 (0)