Skip to content

Commit

Permalink
bugfix: use portal as 'rootDom' for children when searching for neigh…
Browse files Browse the repository at this point in the history
…bouring mounted element
  • Loading branch information
LankyMoose committed Jun 19, 2024
1 parent c2c7da7 commit 03a00f2
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 5 deletions.
11 changes: 6 additions & 5 deletions packages/lib/src/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { EffectTag, elementTypes } from "./constants.js"
import { Component } from "./component.js"
import { Signal } from "./signal.js"
import { renderMode } from "./globals.js"
import { Portal } from "./portal.js"

export { commitWork, createDom, updateDom }

Expand Down Expand Up @@ -210,7 +211,8 @@ function placeDom(
// edge cases are encountered.

// first, try to find next dom by traversing through siblings
let nextDom = findMountedDomRecursive(appCtx, vNode.sibling)
const rootDom = Portal.isPortal(node.type) ? element : appCtx.rootNode?.dom
let nextDom = findMountedDomRecursive(rootDom, vNode.sibling)
if (nextDom === undefined) {
// try to find next dom by traversing (up and across) through the tree
// handles cases like the following:
Expand All @@ -227,7 +229,7 @@ function placeDom(
let parent = vNode.parent

while (!nextDom && parent && parent !== node) {
nextDom = findMountedDomRecursive(appCtx, parent.sibling)
nextDom = findMountedDomRecursive(rootDom, parent.sibling)
parent = parent.parent
}
}
Expand Down Expand Up @@ -339,15 +341,14 @@ function commitDeletion(vNode: VNode, deleteSibling = false) {
}

function findMountedDomRecursive(
appCtx: AppContext,
rootDom: HTMLElement | SVGElement | Text | undefined,
vNode?: VNode
): HTMLElement | SVGElement | Text | undefined {
if (!vNode) return
const stack: VNode[] = [vNode]
while (stack.length) {
const n = stack.pop()!
if (n.dom?.isConnected && appCtx.rootNode?.dom?.contains(n.dom))
return n.dom
if (n.dom?.isConnected && rootDom?.contains(n.dom)) return n.dom
if (n.sibling) stack.push(n.sibling)
if (n.child) stack.push(n.child)
}
Expand Down
7 changes: 7 additions & 0 deletions packages/lib/src/portal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,20 @@ type PortalProps = {
container: HTMLElement
}

const portalIdentifier = Symbol.for("kaioken.portal")

class Portal extends Component<PortalProps> {
doNotModifyDom = true
static [portalIdentifier] = true
constructor(props: PortalProps) {
super(props)
this.vNode.dom = this.props.container
}

static isPortal(type: unknown): type is typeof Portal {
return !!type && typeof type === "function" && portalIdentifier in type
}

render(): JSX.Element {
return (this.props.children as JSX.Element) ?? null
}
Expand Down

0 comments on commit 03a00f2

Please sign in to comment.