node_modules/preact/src/diff/children.js in isomorfeus-preact-10.6.2 vs node_modules/preact/src/diff/children.js in isomorfeus-preact-10.6.3
- old
+ new
@@ -1,335 +1,335 @@
-import { diff, unmount, applyRef } from './index';
-import { createVNode, Fragment } from '../create-element';
-import { EMPTY_OBJ, EMPTY_ARR } from '../constants';
-import { getDomSibling } from '../component';
-
-/**
- * Diff the children of a virtual node
- * @param {import('../internal').PreactElement} parentDom The DOM element whose
- * children are being diffed
- * @param {import('../internal').ComponentChildren[]} renderResult
- * @param {import('../internal').VNode} newParentVNode The new virtual
- * node whose children should be diff'ed against oldParentVNode
- * @param {import('../internal').VNode} oldParentVNode The old virtual
- * node whose children should be diff'ed against newParentVNode
- * @param {object} globalContext The current context object - modified by getChildContext
- * @param {boolean} isSvg Whether or not this DOM node is an SVG node
- * @param {Array<import('../internal').PreactElement>} excessDomChildren
- * @param {Array<import('../internal').Component>} commitQueue List of components
- * which have callbacks to invoke in commitRoot
- * @param {import('../internal').PreactElement} oldDom The current attached DOM
- * element any new dom elements should be placed around. Likely `null` on first
- * render (except when hydrating). Can be a sibling DOM element when diffing
- * Fragments that have siblings. In most cases, it starts out as `oldChildren[0]._dom`.
- * @param {boolean} isHydrating Whether or not we are in hydration
- */
-export function diffChildren(
- parentDom,
- renderResult,
- newParentVNode,
- oldParentVNode,
- globalContext,
- isSvg,
- excessDomChildren,
- commitQueue,
- oldDom,
- isHydrating
-) {
- let i, j, oldVNode, childVNode, newDom, firstChildDom, refs;
-
- // This is a compression of oldParentVNode!=null && oldParentVNode != EMPTY_OBJ && oldParentVNode._children || EMPTY_ARR
- // as EMPTY_OBJ._children should be `undefined`.
- let oldChildren = (oldParentVNode && oldParentVNode._children) || EMPTY_ARR;
-
- let oldChildrenLength = oldChildren.length;
-
- newParentVNode._children = [];
- for (i = 0; i < renderResult.length; i++) {
- childVNode = renderResult[i];
-
- if (childVNode == null || typeof childVNode == 'boolean') {
- childVNode = newParentVNode._children[i] = null;
- }
- // If this newVNode is being reused (e.g. <div>{reuse}{reuse}</div>) in the same diff,
- // or we are rendering a component (e.g. setState) copy the oldVNodes so it can have
- // it's own DOM & etc. pointers
- else if (
- typeof childVNode == 'string' ||
- typeof childVNode == 'number' ||
- // eslint-disable-next-line valid-typeof
- typeof childVNode == 'bigint'
- ) {
- childVNode = newParentVNode._children[i] = createVNode(
- null,
- childVNode,
- null,
- null,
- childVNode
- );
- } else if (Array.isArray(childVNode)) {
- childVNode = newParentVNode._children[i] = createVNode(
- Fragment,
- { children: childVNode },
- null,
- null,
- null
- );
- } else if (childVNode._depth > 0) {
- // VNode is already in use, clone it. This can happen in the following
- // scenario:
- // const reuse = <div />
- // <div>{reuse}<span />{reuse}</div>
- childVNode = newParentVNode._children[i] = createVNode(
- childVNode.type,
- childVNode.props,
- childVNode.key,
- null,
- childVNode._original
- );
- } else {
- childVNode = newParentVNode._children[i] = childVNode;
- }
-
- // Terser removes the `continue` here and wraps the loop body
- // in a `if (childVNode) { ... } condition
- if (childVNode == null) {
- continue;
- }
-
- childVNode._parent = newParentVNode;
- childVNode._depth = newParentVNode._depth + 1;
-
- // Check if we find a corresponding element in oldChildren.
- // If found, delete the array item by setting to `undefined`.
- // We use `undefined`, as `null` is reserved for empty placeholders
- // (holes).
- oldVNode = oldChildren[i];
-
- if (
- oldVNode === null ||
- (oldVNode &&
- childVNode.key == oldVNode.key &&
- childVNode.type === oldVNode.type)
- ) {
- oldChildren[i] = undefined;
- } else {
- // Either oldVNode === undefined or oldChildrenLength > 0,
- // so after this loop oldVNode == null or oldVNode is a valid value.
- for (j = 0; j < oldChildrenLength; j++) {
- oldVNode = oldChildren[j];
- // If childVNode is unkeyed, we only match similarly unkeyed nodes, otherwise we match by key.
- // We always match by type (in either case).
- if (
- oldVNode &&
- childVNode.key == oldVNode.key &&
- childVNode.type === oldVNode.type
- ) {
- oldChildren[j] = undefined;
- break;
- }
- oldVNode = null;
- }
- }
-
- oldVNode = oldVNode || EMPTY_OBJ;
-
- // Morph the old element into the new one, but don't append it to the dom yet
- diff(
- parentDom,
- childVNode,
- oldVNode,
- globalContext,
- isSvg,
- excessDomChildren,
- commitQueue,
- oldDom,
- isHydrating
- );
-
- newDom = childVNode._dom;
-
- if ((j = childVNode.ref) && oldVNode.ref != j) {
- if (!refs) refs = [];
- if (oldVNode.ref) refs.push(oldVNode.ref, null, childVNode);
- refs.push(j, childVNode._component || newDom, childVNode);
- }
-
- if (newDom != null) {
- if (firstChildDom == null) {
- firstChildDom = newDom;
- }
-
- if (
- typeof childVNode.type == 'function' &&
- childVNode._children === oldVNode._children
- ) {
- childVNode._nextDom = oldDom = reorderChildren(
- childVNode,
- oldDom,
- parentDom
- );
- } else {
- oldDom = placeChild(
- parentDom,
- childVNode,
- oldVNode,
- oldChildren,
- newDom,
- oldDom
- );
- }
-
- if (typeof newParentVNode.type == 'function') {
- // Because the newParentVNode is Fragment-like, we need to set it's
- // _nextDom property to the nextSibling of its last child DOM node.
- //
- // `oldDom` contains the correct value here because if the last child
- // is a Fragment-like, then oldDom has already been set to that child's _nextDom.
- // If the last child is a DOM VNode, then oldDom will be set to that DOM
- // node's nextSibling.
- newParentVNode._nextDom = oldDom;
- }
- } else if (
- oldDom &&
- oldVNode._dom == oldDom &&
- oldDom.parentNode != parentDom
- ) {
- // The above condition is to handle null placeholders. See test in placeholder.test.js:
- // `efficiently replace null placeholders in parent rerenders`
- oldDom = getDomSibling(oldVNode);
- }
- }
-
- newParentVNode._dom = firstChildDom;
-
- // Remove remaining oldChildren if there are any.
- for (i = oldChildrenLength; i--; ) {
- if (oldChildren[i] != null) {
- if (
- typeof newParentVNode.type == 'function' &&
- oldChildren[i]._dom != null &&
- oldChildren[i]._dom == newParentVNode._nextDom
- ) {
- // If the newParentVNode.__nextDom points to a dom node that is about to
- // be unmounted, then get the next sibling of that vnode and set
- // _nextDom to it
- newParentVNode._nextDom = getDomSibling(oldParentVNode, i + 1);
- }
-
- unmount(oldChildren[i], oldChildren[i]);
- }
- }
-
- // Set refs only after unmount
- if (refs) {
- for (i = 0; i < refs.length; i++) {
- applyRef(refs[i], refs[++i], refs[++i]);
- }
- }
-}
-
-function reorderChildren(childVNode, oldDom, parentDom) {
- // Note: VNodes in nested suspended trees may be missing _children.
- let c = childVNode._children;
- let tmp = 0;
- for (; c && tmp < c.length; tmp++) {
- let vnode = c[tmp];
- if (vnode) {
- // We typically enter this code path on sCU bailout, where we copy
- // oldVNode._children to newVNode._children. If that is the case, we need
- // to update the old children's _parent pointer to point to the newVNode
- // (childVNode here).
- vnode._parent = childVNode;
-
- if (typeof vnode.type == 'function') {
- oldDom = reorderChildren(vnode, oldDom, parentDom);
- } else {
- oldDom = placeChild(
- parentDom,
- vnode,
- vnode,
- c,
- vnode._dom,
- oldDom
- );
- }
- }
- }
-
- return oldDom;
-}
-
-/**
- * Flatten and loop through the children of a virtual node
- * @param {import('../index').ComponentChildren} children The unflattened
- * children of a virtual node
- * @returns {import('../internal').VNode[]}
- */
-export function toChildArray(children, out) {
- out = out || [];
- if (children == null || typeof children == 'boolean') {
- } else if (Array.isArray(children)) {
- children.some(child => {
- toChildArray(child, out);
- });
- } else {
- out.push(children);
- }
- return out;
-}
-
-function placeChild(
- parentDom,
- childVNode,
- oldVNode,
- oldChildren,
- newDom,
- oldDom
-) {
- let nextDom;
- if (childVNode._nextDom !== undefined) {
- // Only Fragments or components that return Fragment like VNodes will
- // have a non-undefined _nextDom. Continue the diff from the sibling
- // of last DOM child of this child VNode
- nextDom = childVNode._nextDom;
-
- // Eagerly cleanup _nextDom. We don't need to persist the value because
- // it is only used by `diffChildren` to determine where to resume the diff after
- // diffing Components and Fragments. Once we store it the nextDOM local var, we
- // can clean up the property
- childVNode._nextDom = undefined;
- } else if (
- oldVNode == null ||
- newDom != oldDom ||
- newDom.parentNode == null
- ) {
- outer: if (oldDom == null || oldDom.parentNode !== parentDom) {
- parentDom.appendChild(newDom);
- nextDom = null;
- } else {
- // `j<oldChildrenLength; j+=2` is an alternative to `j++<oldChildrenLength/2`
- for (
- let sibDom = oldDom, j = 0;
- (sibDom = sibDom.nextSibling) && j < oldChildren.length;
- j += 2
- ) {
- if (sibDom == newDom) {
- break outer;
- }
- }
- parentDom.insertBefore(newDom, oldDom);
- nextDom = oldDom;
- }
- }
-
- // If we have pre-calculated the nextDOM node, use it. Else calculate it now
- // Strictly check for `undefined` here cuz `null` is a valid value of `nextDom`.
- // See more detail in create-element.js:createVNode
- if (nextDom !== undefined) {
- oldDom = nextDom;
- } else {
- oldDom = newDom.nextSibling;
- }
-
- return oldDom;
-}
+import { diff, unmount, applyRef } from './index';
+import { createVNode, Fragment } from '../create-element';
+import { EMPTY_OBJ, EMPTY_ARR } from '../constants';
+import { getDomSibling } from '../component';
+
+/**
+ * Diff the children of a virtual node
+ * @param {import('../internal').PreactElement} parentDom The DOM element whose
+ * children are being diffed
+ * @param {import('../internal').ComponentChildren[]} renderResult
+ * @param {import('../internal').VNode} newParentVNode The new virtual
+ * node whose children should be diff'ed against oldParentVNode
+ * @param {import('../internal').VNode} oldParentVNode The old virtual
+ * node whose children should be diff'ed against newParentVNode
+ * @param {object} globalContext The current context object - modified by getChildContext
+ * @param {boolean} isSvg Whether or not this DOM node is an SVG node
+ * @param {Array<import('../internal').PreactElement>} excessDomChildren
+ * @param {Array<import('../internal').Component>} commitQueue List of components
+ * which have callbacks to invoke in commitRoot
+ * @param {import('../internal').PreactElement} oldDom The current attached DOM
+ * element any new dom elements should be placed around. Likely `null` on first
+ * render (except when hydrating). Can be a sibling DOM element when diffing
+ * Fragments that have siblings. In most cases, it starts out as `oldChildren[0]._dom`.
+ * @param {boolean} isHydrating Whether or not we are in hydration
+ */
+export function diffChildren(
+ parentDom,
+ renderResult,
+ newParentVNode,
+ oldParentVNode,
+ globalContext,
+ isSvg,
+ excessDomChildren,
+ commitQueue,
+ oldDom,
+ isHydrating
+) {
+ let i, j, oldVNode, childVNode, newDom, firstChildDom, refs;
+
+ // This is a compression of oldParentVNode!=null && oldParentVNode != EMPTY_OBJ && oldParentVNode._children || EMPTY_ARR
+ // as EMPTY_OBJ._children should be `undefined`.
+ let oldChildren = (oldParentVNode && oldParentVNode._children) || EMPTY_ARR;
+
+ let oldChildrenLength = oldChildren.length;
+
+ newParentVNode._children = [];
+ for (i = 0; i < renderResult.length; i++) {
+ childVNode = renderResult[i];
+
+ if (childVNode == null || typeof childVNode == 'boolean') {
+ childVNode = newParentVNode._children[i] = null;
+ }
+ // If this newVNode is being reused (e.g. <div>{reuse}{reuse}</div>) in the same diff,
+ // or we are rendering a component (e.g. setState) copy the oldVNodes so it can have
+ // it's own DOM & etc. pointers
+ else if (
+ typeof childVNode == 'string' ||
+ typeof childVNode == 'number' ||
+ // eslint-disable-next-line valid-typeof
+ typeof childVNode == 'bigint'
+ ) {
+ childVNode = newParentVNode._children[i] = createVNode(
+ null,
+ childVNode,
+ null,
+ null,
+ childVNode
+ );
+ } else if (Array.isArray(childVNode)) {
+ childVNode = newParentVNode._children[i] = createVNode(
+ Fragment,
+ { children: childVNode },
+ null,
+ null,
+ null
+ );
+ } else if (childVNode._depth > 0) {
+ // VNode is already in use, clone it. This can happen in the following
+ // scenario:
+ // const reuse = <div />
+ // <div>{reuse}<span />{reuse}</div>
+ childVNode = newParentVNode._children[i] = createVNode(
+ childVNode.type,
+ childVNode.props,
+ childVNode.key,
+ null,
+ childVNode._original
+ );
+ } else {
+ childVNode = newParentVNode._children[i] = childVNode;
+ }
+
+ // Terser removes the `continue` here and wraps the loop body
+ // in a `if (childVNode) { ... } condition
+ if (childVNode == null) {
+ continue;
+ }
+
+ childVNode._parent = newParentVNode;
+ childVNode._depth = newParentVNode._depth + 1;
+
+ // Check if we find a corresponding element in oldChildren.
+ // If found, delete the array item by setting to `undefined`.
+ // We use `undefined`, as `null` is reserved for empty placeholders
+ // (holes).
+ oldVNode = oldChildren[i];
+
+ if (
+ oldVNode === null ||
+ (oldVNode &&
+ childVNode.key == oldVNode.key &&
+ childVNode.type === oldVNode.type)
+ ) {
+ oldChildren[i] = undefined;
+ } else {
+ // Either oldVNode === undefined or oldChildrenLength > 0,
+ // so after this loop oldVNode == null or oldVNode is a valid value.
+ for (j = 0; j < oldChildrenLength; j++) {
+ oldVNode = oldChildren[j];
+ // If childVNode is unkeyed, we only match similarly unkeyed nodes, otherwise we match by key.
+ // We always match by type (in either case).
+ if (
+ oldVNode &&
+ childVNode.key == oldVNode.key &&
+ childVNode.type === oldVNode.type
+ ) {
+ oldChildren[j] = undefined;
+ break;
+ }
+ oldVNode = null;
+ }
+ }
+
+ oldVNode = oldVNode || EMPTY_OBJ;
+
+ // Morph the old element into the new one, but don't append it to the dom yet
+ diff(
+ parentDom,
+ childVNode,
+ oldVNode,
+ globalContext,
+ isSvg,
+ excessDomChildren,
+ commitQueue,
+ oldDom,
+ isHydrating
+ );
+
+ newDom = childVNode._dom;
+
+ if ((j = childVNode.ref) && oldVNode.ref != j) {
+ if (!refs) refs = [];
+ if (oldVNode.ref) refs.push(oldVNode.ref, null, childVNode);
+ refs.push(j, childVNode._component || newDom, childVNode);
+ }
+
+ if (newDom != null) {
+ if (firstChildDom == null) {
+ firstChildDom = newDom;
+ }
+
+ if (
+ typeof childVNode.type == 'function' &&
+ childVNode._children === oldVNode._children
+ ) {
+ childVNode._nextDom = oldDom = reorderChildren(
+ childVNode,
+ oldDom,
+ parentDom
+ );
+ } else {
+ oldDom = placeChild(
+ parentDom,
+ childVNode,
+ oldVNode,
+ oldChildren,
+ newDom,
+ oldDom
+ );
+ }
+
+ if (typeof newParentVNode.type == 'function') {
+ // Because the newParentVNode is Fragment-like, we need to set it's
+ // _nextDom property to the nextSibling of its last child DOM node.
+ //
+ // `oldDom` contains the correct value here because if the last child
+ // is a Fragment-like, then oldDom has already been set to that child's _nextDom.
+ // If the last child is a DOM VNode, then oldDom will be set to that DOM
+ // node's nextSibling.
+ newParentVNode._nextDom = oldDom;
+ }
+ } else if (
+ oldDom &&
+ oldVNode._dom == oldDom &&
+ oldDom.parentNode != parentDom
+ ) {
+ // The above condition is to handle null placeholders. See test in placeholder.test.js:
+ // `efficiently replace null placeholders in parent rerenders`
+ oldDom = getDomSibling(oldVNode);
+ }
+ }
+
+ newParentVNode._dom = firstChildDom;
+
+ // Remove remaining oldChildren if there are any.
+ for (i = oldChildrenLength; i--; ) {
+ if (oldChildren[i] != null) {
+ if (
+ typeof newParentVNode.type == 'function' &&
+ oldChildren[i]._dom != null &&
+ oldChildren[i]._dom == newParentVNode._nextDom
+ ) {
+ // If the newParentVNode.__nextDom points to a dom node that is about to
+ // be unmounted, then get the next sibling of that vnode and set
+ // _nextDom to it
+ newParentVNode._nextDom = getDomSibling(oldParentVNode, i + 1);
+ }
+
+ unmount(oldChildren[i], oldChildren[i]);
+ }
+ }
+
+ // Set refs only after unmount
+ if (refs) {
+ for (i = 0; i < refs.length; i++) {
+ applyRef(refs[i], refs[++i], refs[++i]);
+ }
+ }
+}
+
+function reorderChildren(childVNode, oldDom, parentDom) {
+ // Note: VNodes in nested suspended trees may be missing _children.
+ let c = childVNode._children;
+ let tmp = 0;
+ for (; c && tmp < c.length; tmp++) {
+ let vnode = c[tmp];
+ if (vnode) {
+ // We typically enter this code path on sCU bailout, where we copy
+ // oldVNode._children to newVNode._children. If that is the case, we need
+ // to update the old children's _parent pointer to point to the newVNode
+ // (childVNode here).
+ vnode._parent = childVNode;
+
+ if (typeof vnode.type == 'function') {
+ oldDom = reorderChildren(vnode, oldDom, parentDom);
+ } else {
+ oldDom = placeChild(
+ parentDom,
+ vnode,
+ vnode,
+ c,
+ vnode._dom,
+ oldDom
+ );
+ }
+ }
+ }
+
+ return oldDom;
+}
+
+/**
+ * Flatten and loop through the children of a virtual node
+ * @param {import('../index').ComponentChildren} children The unflattened
+ * children of a virtual node
+ * @returns {import('../internal').VNode[]}
+ */
+export function toChildArray(children, out) {
+ out = out || [];
+ if (children == null || typeof children == 'boolean') {
+ } else if (Array.isArray(children)) {
+ children.some(child => {
+ toChildArray(child, out);
+ });
+ } else {
+ out.push(children);
+ }
+ return out;
+}
+
+function placeChild(
+ parentDom,
+ childVNode,
+ oldVNode,
+ oldChildren,
+ newDom,
+ oldDom
+) {
+ let nextDom;
+ if (childVNode._nextDom !== undefined) {
+ // Only Fragments or components that return Fragment like VNodes will
+ // have a non-undefined _nextDom. Continue the diff from the sibling
+ // of last DOM child of this child VNode
+ nextDom = childVNode._nextDom;
+
+ // Eagerly cleanup _nextDom. We don't need to persist the value because
+ // it is only used by `diffChildren` to determine where to resume the diff after
+ // diffing Components and Fragments. Once we store it the nextDOM local var, we
+ // can clean up the property
+ childVNode._nextDom = undefined;
+ } else if (
+ oldVNode == null ||
+ newDom != oldDom ||
+ newDom.parentNode == null
+ ) {
+ outer: if (oldDom == null || oldDom.parentNode !== parentDom) {
+ parentDom.appendChild(newDom);
+ nextDom = null;
+ } else {
+ // `j<oldChildrenLength; j+=2` is an alternative to `j++<oldChildrenLength/2`
+ for (
+ let sibDom = oldDom, j = 0;
+ (sibDom = sibDom.nextSibling) && j < oldChildren.length;
+ j += 2
+ ) {
+ if (sibDom == newDom) {
+ break outer;
+ }
+ }
+ parentDom.insertBefore(newDom, oldDom);
+ nextDom = oldDom;
+ }
+ }
+
+ // If we have pre-calculated the nextDOM node, use it. Else calculate it now
+ // Strictly check for `undefined` here cuz `null` is a valid value of `nextDom`.
+ // See more detail in create-element.js:createVNode
+ if (nextDom !== undefined) {
+ oldDom = nextDom;
+ } else {
+ oldDom = newDom.nextSibling;
+ }
+
+ return oldDom;
+}