Skip to content

Commit cbf18fb

Browse files
committed
refactor: handling slot update
1 parent 836db6b commit cbf18fb

File tree

2 files changed

+60
-50
lines changed

2 files changed

+60
-50
lines changed

packages/runtime-dom/src/apiCustomElement.ts

Lines changed: 10 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ export abstract class VueElementBase<
255255
protected abstract _mount(def: Def): void
256256
protected abstract _update(): void
257257
protected abstract _unmount(): void
258+
protected abstract _updateSlotNodes(slot: Map<Node, Node[]>): void
258259

259260
constructor(
260261
/**
@@ -663,58 +664,11 @@ export abstract class VueElementBase<
663664
replacementNodes.push(child)
664665
}
665666
}
666-
667+
parent.removeChild(o)
667668
slotReplacements.set(o, replacementNodes)
668669
}
669670

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-
}
708-
}
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
714-
} else {
715-
this._replaceNodesInFragments(block.nodes, replacements)
716-
}
717-
}
671+
this._updateSlotNodes(slotReplacements)
718672
}
719673

720674
/**
@@ -814,6 +768,13 @@ export class VueElement extends VueElementBase<
814768
this._app = this._instance = null
815769
}
816770

771+
/**
772+
* Only called when shadowRoot is false
773+
*/
774+
protected _updateSlotNodes(replacements: Map<Node, Node[]>): void {
775+
// do nothing
776+
}
777+
817778
private _createVNode(): VNode<any, any> {
818779
const baseProps: VNodeProps = {}
819780
if (!this.shadowRoot) {

packages/runtime-vapor/src/apiDefineVaporCustomElement.ts

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { extend, isPlainObject } from '@vue/shared'
2-
import { createComponent, createVaporApp, defineVaporComponent } from '.'
2+
import {
3+
createComponent,
4+
createVaporApp,
5+
defineVaporComponent,
6+
isFragment,
7+
} from '.'
38
import {
49
type CreateAppFunction,
510
type CustomElementOptions,
@@ -11,6 +16,7 @@ import type {
1116
VaporComponent,
1217
VaporComponentInstance,
1318
} from './component'
19+
import type { Block } from './block'
1420

1521
export type VaporElementConstructor<P = {}> = {
1622
new (initialProps?: Record<string, any>): VaporElement & P
@@ -124,6 +130,49 @@ export class VaporElement extends VueElementBase<
124130
this._app = this._instance = null
125131
}
126132

133+
/**
134+
* Only called when shadowRoot is false
135+
*/
136+
protected _updateSlotNodes(replacements: Map<Node, Node[]>): void {
137+
this._updateFragmentNodes(
138+
(this._instance! as VaporComponentInstance).block,
139+
replacements,
140+
)
141+
}
142+
143+
/**
144+
* Replace slot nodes with their replace content
145+
* @internal
146+
*/
147+
private _updateFragmentNodes(
148+
block: Block,
149+
replacements: Map<Node, Node[]>,
150+
): void {
151+
if (Array.isArray(block)) {
152+
block.forEach(item => this._updateFragmentNodes(item, replacements))
153+
return
154+
}
155+
156+
if (!isFragment(block)) return
157+
const { nodes } = block
158+
if (Array.isArray(nodes)) {
159+
const newNodes: Block[] = []
160+
for (const node of nodes) {
161+
if (node instanceof HTMLSlotElement) {
162+
newNodes.push(...replacements.get(node)!)
163+
} else {
164+
this._updateFragmentNodes(node, replacements)
165+
newNodes.push(node)
166+
}
167+
}
168+
block.nodes = newNodes
169+
} else if (nodes instanceof HTMLSlotElement) {
170+
block.nodes = replacements.get(nodes)!
171+
} else {
172+
this._updateFragmentNodes(nodes, replacements)
173+
}
174+
}
175+
127176
private _createComponent() {
128177
this._def.ce = instance => {
129178
this._app!._ceComponent = this._instance = instance

0 commit comments

Comments
 (0)