|
|
@@ -30,13 +30,7 @@ export const VaporTeleportImpl = {
|
|
|
? new TeleportFragment('teleport')
|
|
|
: new TeleportFragment()
|
|
|
|
|
|
- const resolvedProps = new Proxy(
|
|
|
- props,
|
|
|
- rawPropsProxyHandlers,
|
|
|
- ) as any as TeleportProps
|
|
|
-
|
|
|
let children: Block
|
|
|
-
|
|
|
renderEffect(() => {
|
|
|
frag.updateChildren(
|
|
|
(children = slots.default && (slots.default as BlockFn)()),
|
|
|
@@ -44,21 +38,28 @@ export const VaporTeleportImpl = {
|
|
|
})
|
|
|
|
|
|
renderEffect(() => {
|
|
|
- // access the props to trigger tracking
|
|
|
- frag.update(extend({}, resolvedProps), children!)
|
|
|
+ frag.update(
|
|
|
+ // access the props to trigger tracking
|
|
|
+ extend(
|
|
|
+ {},
|
|
|
+ new Proxy(props, rawPropsProxyHandlers) as any as TeleportProps,
|
|
|
+ ),
|
|
|
+ children!,
|
|
|
+ )
|
|
|
})
|
|
|
|
|
|
return frag
|
|
|
},
|
|
|
}
|
|
|
|
|
|
-export class TeleportFragment extends VaporFragment {
|
|
|
+class TeleportFragment extends VaporFragment {
|
|
|
anchor: Node
|
|
|
- targetStart?: Node | null
|
|
|
- mainAnchor?: Node
|
|
|
- placeholder?: Node
|
|
|
- container?: ParentNode | null
|
|
|
- currentAnchor?: Node | null
|
|
|
+
|
|
|
+ private targetStart?: Node
|
|
|
+ private mainAnchor?: Node
|
|
|
+ private placeholder?: Node
|
|
|
+ private mountContainer?: ParentNode | null
|
|
|
+ private mountAnchor?: Node | null
|
|
|
|
|
|
constructor(anchorLabel?: string) {
|
|
|
super([])
|
|
|
@@ -66,32 +67,37 @@ export class TeleportFragment extends VaporFragment {
|
|
|
__DEV__ && anchorLabel ? createComment(anchorLabel) : createTextNode()
|
|
|
}
|
|
|
|
|
|
- updateChildren(children: Block): void {
|
|
|
- const parent = this.anchor.parentNode
|
|
|
- if (!parent) return
|
|
|
+ get currentParent(): ParentNode {
|
|
|
+ return (this.mountContainer || this.parent)!
|
|
|
+ }
|
|
|
|
|
|
- const container = this.container || parent
|
|
|
+ get currentAnchor(): Node | null {
|
|
|
+ return this.mountAnchor || this.anchor
|
|
|
+ }
|
|
|
|
|
|
- // teardown previous
|
|
|
- remove(this.nodes, container)
|
|
|
+ get parent(): ParentNode | null {
|
|
|
+ return this.anchor.parentNode
|
|
|
+ }
|
|
|
+
|
|
|
+ updateChildren(children: Block): void {
|
|
|
+ // not mounted yet, early return
|
|
|
+ if (!this.parent) return
|
|
|
|
|
|
- insert(
|
|
|
- (this.nodes = children),
|
|
|
- container,
|
|
|
- this.currentAnchor || this.anchor,
|
|
|
- )
|
|
|
+ // teardown previous children
|
|
|
+ remove(this.nodes, this.currentParent)
|
|
|
+
|
|
|
+ // mount new
|
|
|
+ insert((this.nodes = children), this.currentParent, this.currentAnchor)
|
|
|
}
|
|
|
|
|
|
update(props: TeleportProps, children: Block): void {
|
|
|
- const parent = this.anchor.parentNode
|
|
|
this.nodes = children
|
|
|
- const disabled = isTeleportDisabled(props)
|
|
|
|
|
|
const mount = (parent: ParentNode, anchor: Node | null) => {
|
|
|
insert(
|
|
|
this.nodes,
|
|
|
- (this.container = parent),
|
|
|
- (this.currentAnchor = anchor),
|
|
|
+ (this.mountContainer = parent),
|
|
|
+ (this.mountAnchor = anchor),
|
|
|
)
|
|
|
}
|
|
|
|
|
|
@@ -99,10 +105,10 @@ export class TeleportFragment extends VaporFragment {
|
|
|
const target = (this.target = resolveTarget(props, querySelector))
|
|
|
if (target) {
|
|
|
if (
|
|
|
- // initial mount
|
|
|
- !this.targetStart ||
|
|
|
+ // initial mount into target
|
|
|
+ !this.targetAnchor ||
|
|
|
// target changed
|
|
|
- this.targetStart.parentNode !== target
|
|
|
+ this.targetAnchor.parentNode !== target
|
|
|
) {
|
|
|
;[this.targetAnchor, this.targetStart] = prepareAnchor(target)
|
|
|
}
|
|
|
@@ -110,33 +116,36 @@ export class TeleportFragment extends VaporFragment {
|
|
|
mount(target, this.targetAnchor!)
|
|
|
} else if (__DEV__) {
|
|
|
warn(
|
|
|
- `Invalid Teleport target on ${this.targetStart ? 'update' : 'mount'}:`,
|
|
|
+ `Invalid Teleport target on ${this.targetAnchor ? 'update' : 'mount'}:`,
|
|
|
target,
|
|
|
`(${typeof target})`,
|
|
|
)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (parent && disabled) {
|
|
|
- if (!this.mainAnchor) {
|
|
|
- this.mainAnchor = __DEV__
|
|
|
- ? createComment('teleport end')
|
|
|
- : createTextNode()
|
|
|
- }
|
|
|
- if (!this.placeholder) {
|
|
|
- this.placeholder = __DEV__
|
|
|
- ? createComment('teleport start')
|
|
|
- : createTextNode()
|
|
|
- }
|
|
|
- if (!this.mainAnchor.isConnected) {
|
|
|
- insert(this.placeholder, parent, this.anchor)
|
|
|
- insert(this.mainAnchor, parent, this.anchor)
|
|
|
- }
|
|
|
+ // mount into main container
|
|
|
+ if (isTeleportDisabled(props)) {
|
|
|
+ if (this.parent) {
|
|
|
+ if (!this.mainAnchor) {
|
|
|
+ this.mainAnchor = __DEV__
|
|
|
+ ? createComment('teleport end')
|
|
|
+ : createTextNode()
|
|
|
+ }
|
|
|
+ if (!this.placeholder) {
|
|
|
+ this.placeholder = __DEV__
|
|
|
+ ? createComment('teleport start')
|
|
|
+ : createTextNode()
|
|
|
+ }
|
|
|
+ if (!this.mainAnchor.isConnected) {
|
|
|
+ insert(this.placeholder, this.parent, this.anchor)
|
|
|
+ insert(this.mainAnchor, this.parent, this.anchor)
|
|
|
+ }
|
|
|
|
|
|
- mount(parent, this.mainAnchor)
|
|
|
+ mount(this.parent, this.mainAnchor)
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
- if (!disabled) {
|
|
|
+ // mount into target container
|
|
|
+ else {
|
|
|
if (isTeleportDeferred(props)) {
|
|
|
queuePostFlushCb(mountToTarget)
|
|
|
} else {
|
|
|
@@ -147,13 +156,12 @@ export class TeleportFragment extends VaporFragment {
|
|
|
|
|
|
remove = (parent: ParentNode | undefined): void => {
|
|
|
// remove nodes
|
|
|
- remove(this.nodes, this.container || parent)
|
|
|
+ remove(this.nodes, this.currentParent)
|
|
|
|
|
|
// remove anchors
|
|
|
if (this.targetStart) {
|
|
|
- let parentNode = this.targetStart.parentNode!
|
|
|
- remove(this.targetStart!, parentNode)
|
|
|
- remove(this.targetAnchor!, parentNode)
|
|
|
+ remove(this.targetStart!, this.target!)
|
|
|
+ remove(this.targetAnchor!, this.target!)
|
|
|
}
|
|
|
if (this.placeholder) {
|
|
|
remove(this.placeholder!, parent)
|
|
|
@@ -167,12 +175,11 @@ export class TeleportFragment extends VaporFragment {
|
|
|
}
|
|
|
|
|
|
function prepareAnchor(target: ParentNode | null) {
|
|
|
- const targetStart = createTextNode('')
|
|
|
+ const targetStart = createTextNode('') as Text & { [TeleportEndKey]: Node }
|
|
|
const targetAnchor = createTextNode('')
|
|
|
|
|
|
// attach a special property, so we can skip teleported content in
|
|
|
// renderer's nextSibling search
|
|
|
- // @ts-expect-error
|
|
|
targetStart[TeleportEndKey] = targetAnchor
|
|
|
|
|
|
if (target) {
|