|
|
@@ -1,5 +1,5 @@
|
|
|
import type { ChildItem, InsertionParent } from '../insertionState'
|
|
|
-import { isComment, locateEndAnchor } from './hydration'
|
|
|
+import { isComment, isHydrating, locateEndAnchor } from './hydration'
|
|
|
|
|
|
/*@__NO_SIDE_EFFECTS__*/
|
|
|
export function createElement(tagName: string): HTMLElement {
|
|
|
@@ -26,48 +26,50 @@ export function parentNode(node: Node): ParentNode | null {
|
|
|
return node.parentNode
|
|
|
}
|
|
|
|
|
|
-const _txt: typeof _child = _child
|
|
|
-
|
|
|
-/**
|
|
|
- * Hydration-specific version of `txt`.
|
|
|
- */
|
|
|
/*@__NO_SIDE_EFFECTS__*/
|
|
|
-const __txt = (node: ParentNode): Node => {
|
|
|
- let n = node.firstChild!
|
|
|
-
|
|
|
- // since SSR doesn't generate blank text nodes,
|
|
|
- // manually insert a text node as the first child
|
|
|
- if (!n) {
|
|
|
- return node.appendChild(createTextNode())
|
|
|
+export function txt(node: ParentNode): Node {
|
|
|
+ if (isHydrating) {
|
|
|
+ // since SSR doesn't generate blank text nodes,
|
|
|
+ // manually insert a text node as the first child
|
|
|
+ let n = _child(node)
|
|
|
+ if (!n) {
|
|
|
+ return node.appendChild(createTextNode())
|
|
|
+ }
|
|
|
+ return n
|
|
|
}
|
|
|
-
|
|
|
- return n
|
|
|
+ return _child(node)
|
|
|
}
|
|
|
|
|
|
/*@__NO_SIDE_EFFECTS__*/
|
|
|
-export function _child(node: InsertionParent): Node {
|
|
|
- return node.firstChild!
|
|
|
+export function child(node: InsertionParent, logicalIndex?: number): Node {
|
|
|
+ if (isHydrating) {
|
|
|
+ return locateChildByLogicalIndex(node, logicalIndex ?? 0)!
|
|
|
+ }
|
|
|
+ return _child(node)
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * Hydration-specific version of `child`.
|
|
|
- */
|
|
|
/*@__NO_SIDE_EFFECTS__*/
|
|
|
-export function __child(node: ParentNode, logicalIndex: number = 0): Node {
|
|
|
- return locateChildByLogicalIndex(node as InsertionParent, logicalIndex)!
|
|
|
+export function nthChild(node: InsertionParent, i: number): Node {
|
|
|
+ if (isHydrating) {
|
|
|
+ return locateChildByLogicalIndex(node, i)!
|
|
|
+ }
|
|
|
+ return node.childNodes[i]
|
|
|
}
|
|
|
|
|
|
/*@__NO_SIDE_EFFECTS__*/
|
|
|
-export function _nthChild(node: InsertionParent, i: number): Node {
|
|
|
- return node.childNodes[i]
|
|
|
+export function next(node: Node, logicalIndex?: number): Node {
|
|
|
+ if (isHydrating) {
|
|
|
+ return locateChildByLogicalIndex(
|
|
|
+ node.parentNode! as InsertionParent,
|
|
|
+ logicalIndex!,
|
|
|
+ )!
|
|
|
+ }
|
|
|
+ return _next(node)
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * Hydration-specific version of `nthChild`.
|
|
|
- */
|
|
|
/*@__NO_SIDE_EFFECTS__*/
|
|
|
-export function __nthChild(node: Node, logicalIndex: number): Node {
|
|
|
- return locateChildByLogicalIndex(node as InsertionParent, logicalIndex)!
|
|
|
+export function _child(node: InsertionParent): Node {
|
|
|
+ return node.firstChild!
|
|
|
}
|
|
|
|
|
|
/*@__NO_SIDE_EFFECTS__*/
|
|
|
@@ -75,67 +77,6 @@ export function _next(node: Node): Node {
|
|
|
return node.nextSibling!
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * Hydration-specific version of `next`.
|
|
|
- */
|
|
|
-/*@__NO_SIDE_EFFECTS__*/
|
|
|
-export function __next(node: Node, logicalIndex: number): Node {
|
|
|
- return locateChildByLogicalIndex(
|
|
|
- node.parentNode! as InsertionParent,
|
|
|
- logicalIndex,
|
|
|
- )!
|
|
|
-}
|
|
|
-
|
|
|
-type DelegatedFunction<T extends (...args: any[]) => any> = T & {
|
|
|
- impl: T
|
|
|
-}
|
|
|
-
|
|
|
-/*@__NO_SIDE_EFFECTS__*/
|
|
|
-export const txt: DelegatedFunction<typeof _txt> = (...args) => {
|
|
|
- return txt.impl(...args)
|
|
|
-}
|
|
|
-txt.impl = _txt
|
|
|
-
|
|
|
-/*@__NO_SIDE_EFFECTS__*/
|
|
|
-export const child: DelegatedFunction<typeof _child> = (...args) => {
|
|
|
- return child.impl(...args)
|
|
|
-}
|
|
|
-child.impl = _child
|
|
|
-
|
|
|
-/*@__NO_SIDE_EFFECTS__*/
|
|
|
-export const next: DelegatedFunction<typeof _next> = (...args) => {
|
|
|
- return next.impl(...args)
|
|
|
-}
|
|
|
-next.impl = _next
|
|
|
-
|
|
|
-/*@__NO_SIDE_EFFECTS__*/
|
|
|
-export const nthChild: DelegatedFunction<typeof _nthChild> = (...args) => {
|
|
|
- return nthChild.impl(...args)
|
|
|
-}
|
|
|
-nthChild.impl = _nthChild
|
|
|
-
|
|
|
-/**
|
|
|
- * Enables hydration-specific node lookup behavior.
|
|
|
- *
|
|
|
- * Temporarily switches the implementations of the exported
|
|
|
- * `txt`, `child`, `next`, and `nthChild` functions to their hydration-specific
|
|
|
- * versions (`__txt`, `__child`, `__next`, `__nthChild`). This allows traversal
|
|
|
- * logic to correctly handle SSR comment anchors during hydration.
|
|
|
- */
|
|
|
-export function enableHydrationNodeLookup(): void {
|
|
|
- txt.impl = __txt
|
|
|
- child.impl = __child as typeof _child
|
|
|
- next.impl = __next as typeof _next
|
|
|
- nthChild.impl = __nthChild as any as typeof _nthChild
|
|
|
-}
|
|
|
-
|
|
|
-export function disableHydrationNodeLookup(): void {
|
|
|
- txt.impl = _txt
|
|
|
- child.impl = _child
|
|
|
- next.impl = _next
|
|
|
- nthChild.impl = _nthChild
|
|
|
-}
|
|
|
-
|
|
|
export function locateChildByLogicalIndex(
|
|
|
parent: InsertionParent,
|
|
|
logicalIndex: number,
|