Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,6 @@ export const EMPTY_OBJ = /** @type {any} */ ({});
export const EMPTY_ARR = [];

export const MATHML_TOKEN_ELEMENTS = /(mi|mn|mo|ms$|mte|msp)/;

export const HAS_MOVE_BEFORE_SUPPORT =
typeof window !== 'undefined' && 'moveBefore' in Element.prototype;
24 changes: 19 additions & 5 deletions src/diff/children.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
INSERT_VNODE,
MATCHED,
UNDEFINED,
NULL
NULL,
HAS_MOVE_BEFORE_SUPPORT
} from '../constants';
import { isArray } from '../util';
import { getDomSibling } from '../component';
Expand Down Expand Up @@ -127,7 +128,13 @@ export function diffChildren(

let shouldPlace = childVNode._flags & INSERT_VNODE;
if (shouldPlace || oldVNode._children === childVNode._children) {
oldDom = insert(childVNode, oldDom, parentDom, shouldPlace);
oldDom = insert(
childVNode,
oldDom,
parentDom,
shouldPlace,
oldVNode == NULL || oldVNode._original == NULL
);

// When a matched VNode is physically moved via INSERT_VNODE, its old
// _dom pointer becomes a stale positional reference. Clear it so that
Expand Down Expand Up @@ -344,9 +351,10 @@ function constructNewChildrenArray(
* @param {PreactElement} oldDom
* @param {PreactElement} parentDom
* @param {number} shouldPlace
* @param {boolean} isMounting
* @returns {PreactElement}
*/
function insert(parentVNode, oldDom, parentDom, shouldPlace) {
function insert(parentVNode, oldDom, parentDom, shouldPlace, isMounting) {
// Note: VNodes in nested suspended trees may be missing _children.
if (typeof parentVNode.type == 'function') {
let children = parentVNode._children;
Expand All @@ -357,7 +365,7 @@ function insert(parentVNode, oldDom, parentDom, shouldPlace) {
// children's _parent pointer to point to the newVNode (parentVNode
// here).
children[i]._parent = parentVNode;
oldDom = insert(children[i], oldDom, parentDom, shouldPlace);
oldDom = insert(children[i], oldDom, parentDom, shouldPlace, false);
}
}

Expand All @@ -367,7 +375,13 @@ function insert(parentVNode, oldDom, parentDom, shouldPlace) {
if (oldDom && parentVNode.type && !oldDom.parentNode) {
oldDom = getDomSibling(parentVNode);
}
parentDom.insertBefore(parentVNode._dom, oldDom || NULL);

if (HAS_MOVE_BEFORE_SUPPORT && !isMounting) {
// @ts-expect-error This isn't added to TypeScript lib.d.ts yet
parentDom.moveBefore(parentVNode._dom, oldDom);
} else {
parentDom.insertBefore(parentVNode._dom, oldDom || NULL);
}
}
oldDom = parentVNode._dom;
}
Expand Down
8 changes: 8 additions & 0 deletions test/_util/logCall.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ export function logCall(obj, method) {
}
break;
}
case 'moveBefore': {
if (args[1] === null && args.length === 2) {
operation = `${serialize(this)}.appendChild(${serialize(args[0])})`;
} else {
operation = `${serialize(this)}.insertBefore(${c})`;
}
break;
}
default: {
operation = `${serialize(this)}.${String(method)}(${c})`;
break;
Expand Down
4 changes: 4 additions & 0 deletions test/browser/fragments.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,12 @@ describe('Fragment', () => {
let resetAppendChild;
let resetRemove;
let resetRemoveText;
let resetMoveBefore;

beforeAll(() => {
resetInsertBefore = logCall(Element.prototype, 'insertBefore');
// @ts-expect-error
resetMoveBefore = logCall(Element.prototype, 'moveBefore');
resetAppendChild = logCall(Element.prototype, 'appendChild');
resetRemove = logCall(Element.prototype, 'remove');
resetRemoveText = logCall(Text.prototype, 'remove');
Expand All @@ -57,6 +60,7 @@ describe('Fragment', () => {
});

afterAll(() => {
resetMoveBefore();
resetInsertBefore();
resetAppendChild();
resetRemove();
Expand Down
3 changes: 3 additions & 0 deletions test/browser/keys.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,15 @@ describe('keys', () => {
values.splice(to, 0, value);
}

let resetMoveBefore;
let resetAppendChild;
let resetInsertBefore;
let resetRemoveChild;
let resetRemove;
let resetRemoveText;

beforeAll(() => {
resetMoveBefore = logCall(Element.prototype, 'moveBefore');
resetAppendChild = logCall(Element.prototype, 'appendChild');
resetInsertBefore = logCall(Element.prototype, 'insertBefore');
resetRemoveChild = logCall(Element.prototype, 'removeChild');
Expand All @@ -91,6 +93,7 @@ describe('keys', () => {
resetRemoveChild();
resetRemove();
resetRemoveText();
resetMoveBefore();
});

beforeEach(() => {
Expand Down
4 changes: 4 additions & 0 deletions test/browser/lifecycles/shouldComponentUpdate.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@ describe('Lifecycle methods', () => {
// expect(getLog()).to.deep.equal(expectedOperations, message);
// }
let resetInsertBefore;
let resetMoveBefore;
let resetRemoveChild;
let resetRemove;

beforeAll(() => {
// @ts-expect-error
resetMoveBefore = logCall(Element.prototype, 'moveBefore');
resetInsertBefore = logCall(Element.prototype, 'insertBefore');
resetRemoveChild = logCall(Element.prototype, 'appendChild');
resetRemove = logCall(Element.prototype, 'removeChild');
Expand All @@ -28,6 +31,7 @@ describe('Lifecycle methods', () => {
resetInsertBefore();
resetRemoveChild();
resetRemove();
resetMoveBefore();
});

beforeEach(() => {
Expand Down
4 changes: 4 additions & 0 deletions test/browser/render.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ describe('render()', () => {
let resetInsertBefore;
let resetRemoveText;
let resetRemove;
let resetMoveBefore;

beforeEach(() => {
scratch = setupScratch();
Expand All @@ -43,12 +44,15 @@ describe('render()', () => {
beforeAll(() => {
resetAppendChild = logCall(Element.prototype, 'appendChild');
resetInsertBefore = logCall(Element.prototype, 'insertBefore');
// @ts-expect-error
resetMoveBefore = logCall(Element.prototype, 'moveBefore');
resetRemoveText = logCall(Text.prototype, 'remove');
resetRemove = logCall(Element.prototype, 'remove');
});

afterAll(() => {
resetAppendChild();
resetMoveBefore();
resetInsertBefore();
resetRemoveText();
resetRemove();
Expand Down
Loading