@bpmn-io/properties-panel 3.12.0 → 3.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/dist/assets/properties-panel.css +0 -4
  2. package/dist/index.esm.js +31 -22
  3. package/dist/index.esm.js.map +1 -1
  4. package/dist/index.js +66 -63
  5. package/dist/index.js.map +1 -1
  6. package/package.json +28 -31
  7. package/preact/README.md +2 -2
  8. package/preact/compat/LICENSE +21 -0
  9. package/preact/compat/dist/compat.js +1 -1
  10. package/preact/compat/dist/compat.js.map +1 -1
  11. package/preact/compat/dist/compat.mjs +1 -1
  12. package/preact/compat/dist/compat.module.js +1 -1
  13. package/preact/compat/dist/compat.module.js.map +1 -1
  14. package/preact/compat/dist/compat.umd.js +1 -1
  15. package/preact/compat/dist/compat.umd.js.map +1 -1
  16. package/preact/compat/server.browser.js +7 -0
  17. package/preact/compat/server.mjs +7 -0
  18. package/preact/compat/src/index.d.ts +22 -8
  19. package/preact/compat/src/index.js +35 -3
  20. package/preact/compat/src/portals.js +26 -35
  21. package/preact/compat/src/suspense.js +9 -6
  22. package/preact/compat/src/util.js +0 -5
  23. package/preact/debug/LICENSE +21 -0
  24. package/preact/debug/dist/debug.js +1 -1
  25. package/preact/debug/dist/debug.js.map +1 -1
  26. package/preact/debug/dist/debug.mjs +1 -1
  27. package/preact/debug/dist/debug.module.js +1 -1
  28. package/preact/debug/dist/debug.module.js.map +1 -1
  29. package/preact/debug/dist/debug.umd.js +1 -1
  30. package/preact/debug/dist/debug.umd.js.map +1 -1
  31. package/preact/debug/src/debug.js +124 -42
  32. package/preact/devtools/LICENSE +21 -0
  33. package/preact/devtools/dist/devtools.js +1 -1
  34. package/preact/devtools/dist/devtools.js.map +1 -1
  35. package/preact/devtools/dist/devtools.mjs +1 -1
  36. package/preact/devtools/dist/devtools.module.js +1 -1
  37. package/preact/devtools/dist/devtools.module.js.map +1 -1
  38. package/preact/devtools/dist/devtools.umd.js +1 -1
  39. package/preact/devtools/dist/devtools.umd.js.map +1 -1
  40. package/preact/devtools/src/devtools.js +1 -1
  41. package/preact/dist/preact.js +1 -1
  42. package/preact/dist/preact.js.map +1 -1
  43. package/preact/dist/preact.min.js +1 -1
  44. package/preact/dist/preact.min.js.map +1 -1
  45. package/preact/dist/preact.min.module.js +1 -1
  46. package/preact/dist/preact.min.module.js.map +1 -1
  47. package/preact/dist/preact.min.umd.js +1 -1
  48. package/preact/dist/preact.min.umd.js.map +1 -1
  49. package/preact/dist/preact.mjs +1 -1
  50. package/preact/dist/preact.module.js +1 -1
  51. package/preact/dist/preact.module.js.map +1 -1
  52. package/preact/dist/preact.umd.js +1 -1
  53. package/preact/dist/preact.umd.js.map +1 -1
  54. package/preact/hooks/LICENSE +21 -0
  55. package/preact/jsx-runtime/LICENSE +21 -0
  56. package/preact/jsx-runtime/dist/jsxRuntime.js +1 -1
  57. package/preact/jsx-runtime/dist/jsxRuntime.js.map +1 -1
  58. package/preact/jsx-runtime/dist/jsxRuntime.mjs +1 -1
  59. package/preact/jsx-runtime/dist/jsxRuntime.module.js +1 -1
  60. package/preact/jsx-runtime/dist/jsxRuntime.module.js.map +1 -1
  61. package/preact/jsx-runtime/dist/jsxRuntime.umd.js +1 -1
  62. package/preact/jsx-runtime/dist/jsxRuntime.umd.js.map +1 -1
  63. package/preact/jsx-runtime/src/index.d.ts +10 -0
  64. package/preact/jsx-runtime/src/index.js +113 -4
  65. package/preact/jsx-runtime/src/utils.js +36 -0
  66. package/preact/package.json +4 -3
  67. package/preact/src/clone-element.js +6 -4
  68. package/preact/src/component.js +34 -28
  69. package/preact/src/constants.js +13 -1
  70. package/preact/src/create-context.js +3 -3
  71. package/preact/src/create-element.js +14 -11
  72. package/preact/src/diff/catch-error.js +11 -7
  73. package/preact/src/diff/children.js +321 -218
  74. package/preact/src/diff/index.js +188 -142
  75. package/preact/src/diff/props.js +31 -38
  76. package/preact/src/index.d.ts +38 -19
  77. package/preact/src/index.js +1 -1
  78. package/preact/src/internal.d.ts +183 -153
  79. package/preact/src/jsx.d.ts +883 -19
  80. package/preact/src/options.js +1 -1
  81. package/preact/src/render.js +11 -11
  82. package/preact/src/util.js +2 -2
  83. package/preact/test-utils/dist/testUtils.js +1 -1
  84. package/preact/test-utils/dist/testUtils.js.map +1 -1
  85. package/preact/test-utils/dist/testUtils.mjs +1 -1
  86. package/preact/test-utils/dist/testUtils.module.js +1 -1
  87. package/preact/test-utils/dist/testUtils.module.js.map +1 -1
  88. package/preact/test-utils/dist/testUtils.umd.js +1 -1
  89. package/preact/test-utils/dist/testUtils.umd.js.map +1 -1
  90. package/preact/test-utils/src/index.js +13 -5
@@ -1,28 +1,30 @@
1
1
  import { diff, unmount, applyRef } from './index';
2
2
  import { createVNode, Fragment } from '../create-element';
3
- import { EMPTY_OBJ, EMPTY_ARR } from '../constants';
4
- import { getDomSibling } from '../component';
3
+ import { EMPTY_OBJ, EMPTY_ARR, INSERT_VNODE, MATCHED } from '../constants';
5
4
  import { isArray } from '../util';
5
+ import { getDomSibling } from '../component';
6
6
 
7
7
  /**
8
8
  * Diff the children of a virtual node
9
- * @param {import('../internal').PreactElement} parentDom The DOM element whose
10
- * children are being diffed
11
- * @param {import('../internal').ComponentChildren[]} renderResult
12
- * @param {import('../internal').VNode} newParentVNode The new virtual
13
- * node whose children should be diff'ed against oldParentVNode
14
- * @param {import('../internal').VNode} oldParentVNode The old virtual
15
- * node whose children should be diff'ed against newParentVNode
16
- * @param {object} globalContext The current context object - modified by getChildContext
9
+ * @param {PreactElement} parentDom The DOM element whose children are being
10
+ * diffed
11
+ * @param {ComponentChildren[]} renderResult
12
+ * @param {VNode} newParentVNode The new virtual node whose children should be
13
+ * diff'ed against oldParentVNode
14
+ * @param {VNode} oldParentVNode The old virtual node whose children should be
15
+ * diff'ed against newParentVNode
16
+ * @param {object} globalContext The current context object - modified by
17
+ * getChildContext
17
18
  * @param {boolean} isSvg Whether or not this DOM node is an SVG node
18
- * @param {Array<import('../internal').PreactElement>} excessDomChildren
19
- * @param {Array<import('../internal').Component>} commitQueue List of components
20
- * which have callbacks to invoke in commitRoot
21
- * @param {import('../internal').PreactElement} oldDom The current attached DOM
22
- * element any new dom elements should be placed around. Likely `null` on first
23
- * render (except when hydrating). Can be a sibling DOM element when diffing
24
- * Fragments that have siblings. In most cases, it starts out as `oldChildren[0]._dom`.
19
+ * @param {Array<PreactElement>} excessDomChildren
20
+ * @param {Array<Component>} commitQueue List of components which have callbacks
21
+ * to invoke in commitRoot
22
+ * @param {PreactElement} oldDom The current attached DOM element any new dom
23
+ * elements should be placed around. Likely `null` on first render (except when
24
+ * hydrating). Can be a sibling DOM element when diffing Fragments that have
25
+ * siblings. In most cases, it starts out as `oldChildren[0]._dom`.
25
26
  * @param {boolean} isHydrating Whether or not we are in hydration
27
+ * @param {any[]} refQueue an array of elements needed to invoke refs
26
28
  */
27
29
  export function diffChildren(
28
30
  parentDom,
@@ -34,18 +36,148 @@ export function diffChildren(
34
36
  excessDomChildren,
35
37
  commitQueue,
36
38
  oldDom,
37
- isHydrating
39
+ isHydrating,
40
+ refQueue
38
41
  ) {
39
- let i, j, oldVNode, childVNode, newDom, firstChildDom, refs;
42
+ let i,
43
+ /** @type {VNode} */
44
+ oldVNode,
45
+ /** @type {VNode} */
46
+ childVNode,
47
+ /** @type {PreactElement} */
48
+ newDom,
49
+ /** @type {PreactElement} */
50
+ firstChildDom;
40
51
 
41
52
  // This is a compression of oldParentVNode!=null && oldParentVNode != EMPTY_OBJ && oldParentVNode._children || EMPTY_ARR
42
53
  // as EMPTY_OBJ._children should be `undefined`.
54
+ /** @type {VNode[]} */
43
55
  let oldChildren = (oldParentVNode && oldParentVNode._children) || EMPTY_ARR;
44
56
 
45
- let oldChildrenLength = oldChildren.length;
57
+ let newChildrenLength = renderResult.length;
58
+
59
+ newParentVNode._nextDom = oldDom;
60
+ constructNewChildrenArray(newParentVNode, renderResult, oldChildren);
61
+ oldDom = newParentVNode._nextDom;
62
+
63
+ for (i = 0; i < newChildrenLength; i++) {
64
+ childVNode = newParentVNode._children[i];
65
+
66
+ if (
67
+ childVNode == null ||
68
+ typeof childVNode == 'boolean' ||
69
+ typeof childVNode == 'function'
70
+ ) {
71
+ continue;
72
+ }
73
+
74
+ // At this point, constructNewChildrenArray has assigned _index to be the
75
+ // matchingIndex for this VNode's oldVNode (or -1 if there is no oldVNode).
76
+ if (childVNode._index === -1) {
77
+ oldVNode = EMPTY_OBJ;
78
+ } else {
79
+ oldVNode = oldChildren[childVNode._index] || EMPTY_OBJ;
80
+ }
81
+
82
+ // Update childVNode._index to its final index
83
+ childVNode._index = i;
84
+
85
+ // Morph the old element into the new one, but don't append it to the dom yet
86
+ diff(
87
+ parentDom,
88
+ childVNode,
89
+ oldVNode,
90
+ globalContext,
91
+ isSvg,
92
+ excessDomChildren,
93
+ commitQueue,
94
+ oldDom,
95
+ isHydrating,
96
+ refQueue
97
+ );
98
+
99
+ // Adjust DOM nodes
100
+ newDom = childVNode._dom;
101
+ if (childVNode.ref && oldVNode.ref != childVNode.ref) {
102
+ if (oldVNode.ref) {
103
+ applyRef(oldVNode.ref, null, childVNode);
104
+ }
105
+ refQueue.push(
106
+ childVNode.ref,
107
+ childVNode._component || newDom,
108
+ childVNode
109
+ );
110
+ }
111
+
112
+ if (firstChildDom == null && newDom != null) {
113
+ firstChildDom = newDom;
114
+ }
115
+
116
+ if (
117
+ childVNode._flags & INSERT_VNODE ||
118
+ oldVNode._children === childVNode._children
119
+ ) {
120
+ oldDom = insert(childVNode, oldDom, parentDom);
121
+ } else if (
122
+ typeof childVNode.type == 'function' &&
123
+ childVNode._nextDom !== undefined
124
+ ) {
125
+ // Since Fragments or components that return Fragment like VNodes can
126
+ // contain multiple DOM nodes as the same level, continue the diff from
127
+ // the sibling of last DOM child of this child VNode
128
+ oldDom = childVNode._nextDom;
129
+ } else if (newDom) {
130
+ oldDom = newDom.nextSibling;
131
+ }
132
+
133
+ // Eagerly cleanup _nextDom. We don't need to persist the value because it
134
+ // is only used by `diffChildren` to determine where to resume the diff
135
+ // after diffing Components and Fragments. Once we store it the nextDOM
136
+ // local var, we can clean up the property. Also prevents us hanging on to
137
+ // DOM nodes that may have been unmounted.
138
+ childVNode._nextDom = undefined;
139
+
140
+ // Unset diffing flags
141
+ childVNode._flags &= ~(INSERT_VNODE | MATCHED);
142
+ }
143
+
144
+ // TODO: With new child diffing algo, consider alt ways to diff Fragments.
145
+ // Such as dropping oldDom and moving fragments in place
146
+ //
147
+ // Because the newParentVNode is Fragment-like, we need to set it's
148
+ // _nextDom property to the nextSibling of its last child DOM node.
149
+ //
150
+ // `oldDom` contains the correct value here because if the last child
151
+ // is a Fragment-like, then oldDom has already been set to that child's _nextDom.
152
+ // If the last child is a DOM VNode, then oldDom will be set to that DOM
153
+ // node's nextSibling.
154
+ newParentVNode._nextDom = oldDom;
155
+ newParentVNode._dom = firstChildDom;
156
+ }
157
+
158
+ /**
159
+ * @param {VNode} newParentVNode
160
+ * @param {ComponentChildren[]} renderResult
161
+ * @param {VNode[]} oldChildren
162
+ */
163
+ function constructNewChildrenArray(newParentVNode, renderResult, oldChildren) {
164
+ /** @type {number} */
165
+ let i;
166
+ /** @type {VNode} */
167
+ let childVNode;
168
+ /** @type {VNode} */
169
+ let oldVNode;
170
+
171
+ const newChildrenLength = renderResult.length;
172
+ let oldChildrenLength = oldChildren.length,
173
+ remainingOldChildren = oldChildrenLength;
174
+
175
+ let skew = 0;
46
176
 
47
177
  newParentVNode._children = [];
48
- for (i = 0; i < renderResult.length; i++) {
178
+ for (i = 0; i < newChildrenLength; i++) {
179
+ // @ts-expect-error We are reusing the childVNode variable to hold both the
180
+ // pre and post normalized childVNode
49
181
  childVNode = renderResult[i];
50
182
 
51
183
  if (
@@ -62,7 +194,8 @@ export function diffChildren(
62
194
  typeof childVNode == 'string' ||
63
195
  typeof childVNode == 'number' ||
64
196
  // eslint-disable-next-line valid-typeof
65
- typeof childVNode == 'bigint'
197
+ typeof childVNode == 'bigint' ||
198
+ childVNode.constructor == String
66
199
  ) {
67
200
  childVNode = newParentVNode._children[i] = createVNode(
68
201
  null,
@@ -79,7 +212,7 @@ export function diffChildren(
79
212
  null,
80
213
  null
81
214
  );
82
- } else if (childVNode._depth > 0) {
215
+ } else if (childVNode.constructor === undefined && childVNode._depth > 0) {
83
216
  // VNode is already in use, clone it. This can happen in the following
84
217
  // scenario:
85
218
  // const reuse = <div />
@@ -95,173 +228,153 @@ export function diffChildren(
95
228
  childVNode = newParentVNode._children[i] = childVNode;
96
229
  }
97
230
 
98
- // Terser removes the `continue` here and wraps the loop body
99
- // in a `if (childVNode) { ... } condition
231
+ // Handle unmounting null placeholders, i.e. VNode => null in unkeyed children
100
232
  if (childVNode == null) {
101
- continue;
102
- }
103
-
104
- childVNode._parent = newParentVNode;
105
- childVNode._depth = newParentVNode._depth + 1;
233
+ oldVNode = oldChildren[i];
234
+ if (oldVNode && oldVNode.key == null && oldVNode._dom) {
235
+ if (oldVNode._dom == newParentVNode._nextDom) {
236
+ newParentVNode._nextDom = getDomSibling(oldVNode);
237
+ }
106
238
 
107
- // Check if we find a corresponding element in oldChildren.
108
- // If found, delete the array item by setting to `undefined`.
109
- // We use `undefined`, as `null` is reserved for empty placeholders
110
- // (holes).
111
- oldVNode = oldChildren[i];
239
+ unmount(oldVNode, oldVNode, false);
112
240
 
113
- if (
114
- oldVNode === null ||
115
- (oldVNode &&
116
- childVNode.key == oldVNode.key &&
117
- childVNode.type === oldVNode.type)
118
- ) {
119
- oldChildren[i] = undefined;
120
- } else {
121
- // Either oldVNode === undefined or oldChildrenLength > 0,
122
- // so after this loop oldVNode == null or oldVNode is a valid value.
123
- for (j = 0; j < oldChildrenLength; j++) {
124
- oldVNode = oldChildren[j];
125
- // If childVNode is unkeyed, we only match similarly unkeyed nodes, otherwise we match by key.
126
- // We always match by type (in either case).
127
- if (
128
- oldVNode &&
129
- childVNode.key == oldVNode.key &&
130
- childVNode.type === oldVNode.type
131
- ) {
132
- oldChildren[j] = undefined;
133
- break;
134
- }
135
- oldVNode = null;
241
+ // Explicitly nullify this position in oldChildren instead of just
242
+ // setting `_match=true` to prevent other routines (e.g.
243
+ // `findMatchingIndex` or `getDomSibling`) from thinking VNodes or DOM
244
+ // nodes in this position are still available to be used in diffing when
245
+ // they have actually already been unmounted. For example, by only
246
+ // setting `_match=true` here, the unmounting loop later would attempt
247
+ // to unmount this VNode again seeing `_match==true`. Further,
248
+ // getDomSibling doesn't know about _match and so would incorrectly
249
+ // assume DOM nodes in this subtree are mounted and usable.
250
+ oldChildren[i] = null;
251
+ remainingOldChildren--;
136
252
  }
253
+
254
+ continue;
137
255
  }
138
256
 
139
- oldVNode = oldVNode || EMPTY_OBJ;
257
+ childVNode._parent = newParentVNode;
258
+ childVNode._depth = newParentVNode._depth + 1;
140
259
 
141
- // Morph the old element into the new one, but don't append it to the dom yet
142
- diff(
143
- parentDom,
260
+ const skewedIndex = i + skew;
261
+ const matchingIndex = findMatchingIndex(
144
262
  childVNode,
145
- oldVNode,
146
- globalContext,
147
- isSvg,
148
- excessDomChildren,
149
- commitQueue,
150
- oldDom,
151
- isHydrating
263
+ oldChildren,
264
+ skewedIndex,
265
+ remainingOldChildren
152
266
  );
153
267
 
154
- newDom = childVNode._dom;
268
+ // Temporarily store the matchingIndex on the _index property so we can pull
269
+ // out the oldVNode in diffChildren. We'll override this to the VNode's
270
+ // final index after using this property to get the oldVNode
271
+ childVNode._index = matchingIndex;
155
272
 
156
- if ((j = childVNode.ref) && oldVNode.ref != j) {
157
- if (!refs) refs = [];
158
- if (oldVNode.ref) refs.push(oldVNode.ref, null, childVNode);
159
- refs.push(j, childVNode._component || newDom, childVNode);
273
+ oldVNode = null;
274
+ if (matchingIndex !== -1) {
275
+ oldVNode = oldChildren[matchingIndex];
276
+ remainingOldChildren--;
277
+ if (oldVNode) {
278
+ oldVNode._flags |= MATCHED;
279
+ }
160
280
  }
161
281
 
162
- if (newDom != null) {
163
- if (firstChildDom == null) {
164
- firstChildDom = newDom;
282
+ // Here, we define isMounting for the purposes of the skew diffing
283
+ // algorithm. Nodes that are unsuspending are considered mounting and we detect
284
+ // this by checking if oldVNode._original === null
285
+ const isMounting = oldVNode == null || oldVNode._original === null;
286
+
287
+ if (isMounting) {
288
+ if (matchingIndex == -1) {
289
+ skew--;
165
290
  }
166
291
 
167
- if (
168
- typeof childVNode.type == 'function' &&
169
- childVNode._children === oldVNode._children
170
- ) {
171
- childVNode._nextDom = oldDom = reorderChildren(
172
- childVNode,
173
- oldDom,
174
- parentDom
175
- );
292
+ // If we are mounting a DOM VNode, mark it for insertion
293
+ if (typeof childVNode.type != 'function') {
294
+ childVNode._flags |= INSERT_VNODE;
295
+ }
296
+ } else if (matchingIndex !== skewedIndex) {
297
+ if (matchingIndex === skewedIndex + 1) {
298
+ skew++;
299
+ } else if (matchingIndex > skewedIndex) {
300
+ if (remainingOldChildren > newChildrenLength - skewedIndex) {
301
+ skew += matchingIndex - skewedIndex;
302
+ } else {
303
+ // ### Change from keyed: I think this was missing from the algo...
304
+ skew--;
305
+ }
306
+ } else if (matchingIndex < skewedIndex) {
307
+ if (matchingIndex == skewedIndex - 1) {
308
+ skew = matchingIndex - skewedIndex;
309
+ } else {
310
+ skew = 0;
311
+ }
176
312
  } else {
177
- oldDom = placeChild(
178
- parentDom,
179
- childVNode,
180
- oldVNode,
181
- oldChildren,
182
- newDom,
183
- oldDom
184
- );
313
+ skew = 0;
185
314
  }
186
315
 
187
- if (typeof newParentVNode.type == 'function') {
188
- // Because the newParentVNode is Fragment-like, we need to set it's
189
- // _nextDom property to the nextSibling of its last child DOM node.
190
- //
191
- // `oldDom` contains the correct value here because if the last child
192
- // is a Fragment-like, then oldDom has already been set to that child's _nextDom.
193
- // If the last child is a DOM VNode, then oldDom will be set to that DOM
194
- // node's nextSibling.
195
- newParentVNode._nextDom = oldDom;
316
+ // Move this VNode's DOM if the original index (matchingIndex) doesn't
317
+ // match the new skew index (i + new skew)
318
+ if (matchingIndex !== i + skew) {
319
+ childVNode._flags |= INSERT_VNODE;
196
320
  }
197
- } else if (
198
- oldDom &&
199
- oldVNode._dom == oldDom &&
200
- oldDom.parentNode != parentDom
201
- ) {
202
- // The above condition is to handle null placeholders. See test in placeholder.test.js:
203
- // `efficiently replace null placeholders in parent rerenders`
204
- oldDom = getDomSibling(oldVNode);
205
321
  }
206
322
  }
207
323
 
208
- newParentVNode._dom = firstChildDom;
324
+ // Remove remaining oldChildren if there are any. Loop forwards so that as we
325
+ // unmount DOM from the beginning of the oldChildren, we can adjust oldDom to
326
+ // point to the next child, which needs to be the first DOM node that won't be
327
+ // unmounted.
328
+ if (remainingOldChildren) {
329
+ for (i = 0; i < oldChildrenLength; i++) {
330
+ oldVNode = oldChildren[i];
331
+ if (oldVNode != null && (oldVNode._flags & MATCHED) === 0) {
332
+ if (oldVNode._dom == newParentVNode._nextDom) {
333
+ newParentVNode._nextDom = getDomSibling(oldVNode);
334
+ }
209
335
 
210
- // Remove remaining oldChildren if there are any.
211
- for (i = oldChildrenLength; i--; ) {
212
- if (oldChildren[i] != null) {
213
- if (
214
- typeof newParentVNode.type == 'function' &&
215
- oldChildren[i]._dom != null &&
216
- oldChildren[i]._dom == newParentVNode._nextDom
217
- ) {
218
- // If the newParentVNode.__nextDom points to a dom node that is about to
219
- // be unmounted, then get the next sibling of that vnode and set
220
- // _nextDom to it
221
- newParentVNode._nextDom = getLastDom(oldParentVNode).nextSibling;
336
+ unmount(oldVNode, oldVNode);
222
337
  }
223
-
224
- unmount(oldChildren[i], oldChildren[i]);
225
- }
226
- }
227
-
228
- // Set refs only after unmount
229
- if (refs) {
230
- for (i = 0; i < refs.length; i++) {
231
- applyRef(refs[i], refs[++i], refs[++i]);
232
338
  }
233
339
  }
234
340
  }
235
341
 
236
- function reorderChildren(childVNode, oldDom, parentDom) {
342
+ /**
343
+ * @param {VNode} parentVNode
344
+ * @param {PreactElement} oldDom
345
+ * @param {PreactElement} parentDom
346
+ * @returns {PreactElement}
347
+ */
348
+ function insert(parentVNode, oldDom, parentDom) {
237
349
  // Note: VNodes in nested suspended trees may be missing _children.
238
- let c = childVNode._children;
239
- let tmp = 0;
240
- for (; c && tmp < c.length; tmp++) {
241
- let vnode = c[tmp];
242
- if (vnode) {
243
- // We typically enter this code path on sCU bailout, where we copy
244
- // oldVNode._children to newVNode._children. If that is the case, we need
245
- // to update the old children's _parent pointer to point to the newVNode
246
- // (childVNode here).
247
- vnode._parent = childVNode;
248
-
249
- if (typeof vnode.type == 'function') {
250
- oldDom = reorderChildren(vnode, oldDom, parentDom);
251
- } else {
252
- oldDom = placeChild(parentDom, vnode, vnode, c, vnode._dom, oldDom);
350
+
351
+ if (typeof parentVNode.type == 'function') {
352
+ let children = parentVNode._children;
353
+ for (let i = 0; children && i < children.length; i++) {
354
+ if (children[i]) {
355
+ // If we enter this code path on sCU bailout, where we copy
356
+ // oldVNode._children to newVNode._children, we need to update the old
357
+ // children's _parent pointer to point to the newVNode (parentVNode
358
+ // here).
359
+ children[i]._parent = parentVNode;
360
+ oldDom = insert(children[i], oldDom, parentDom);
253
361
  }
254
362
  }
363
+
364
+ return oldDom;
365
+ } else if (parentVNode._dom != oldDom) {
366
+ parentDom.insertBefore(parentVNode._dom, oldDom || null);
367
+ oldDom = parentVNode._dom;
255
368
  }
256
369
 
257
- return oldDom;
370
+ return oldDom && oldDom.nextSibling;
258
371
  }
259
372
 
260
373
  /**
261
374
  * Flatten and loop through the children of a virtual node
262
- * @param {import('../index').ComponentChildren} children The unflattened
263
- * children of a virtual node
264
- * @returns {import('../internal').VNode[]}
375
+ * @param {ComponentChildren} children The unflattened children of a virtual
376
+ * node
377
+ * @returns {VNode[]}
265
378
  */
266
379
  export function toChildArray(children, out) {
267
380
  out = out || [];
@@ -276,81 +389,71 @@ export function toChildArray(children, out) {
276
389
  return out;
277
390
  }
278
391
 
279
- function placeChild(
280
- parentDom,
392
+ /**
393
+ * @param {VNode} childVNode
394
+ * @param {VNode[]} oldChildren
395
+ * @param {number} skewedIndex
396
+ * @param {number} remainingOldChildren
397
+ * @returns {number}
398
+ */
399
+ function findMatchingIndex(
281
400
  childVNode,
282
- oldVNode,
283
401
  oldChildren,
284
- newDom,
285
- oldDom
402
+ skewedIndex,
403
+ remainingOldChildren
286
404
  ) {
287
- let nextDom;
288
- if (childVNode._nextDom !== undefined) {
289
- // Only Fragments or components that return Fragment like VNodes will
290
- // have a non-undefined _nextDom. Continue the diff from the sibling
291
- // of last DOM child of this child VNode
292
- nextDom = childVNode._nextDom;
293
-
294
- // Eagerly cleanup _nextDom. We don't need to persist the value because
295
- // it is only used by `diffChildren` to determine where to resume the diff after
296
- // diffing Components and Fragments. Once we store it the nextDOM local var, we
297
- // can clean up the property
298
- childVNode._nextDom = undefined;
299
- } else if (
300
- oldVNode == null ||
301
- newDom != oldDom ||
302
- newDom.parentNode == null
405
+ const key = childVNode.key;
406
+ const type = childVNode.type;
407
+ let x = skewedIndex - 1;
408
+ let y = skewedIndex + 1;
409
+ let oldVNode = oldChildren[skewedIndex];
410
+
411
+ // We only need to perform a search if there are more children
412
+ // (remainingOldChildren) to search. However, if the oldVNode we just looked
413
+ // at skewedIndex was not already used in this diff, then there must be at
414
+ // least 1 other (so greater than 1) remainingOldChildren to attempt to match
415
+ // against. So the following condition checks that ensuring
416
+ // remainingOldChildren > 1 if the oldVNode is not already used/matched. Else
417
+ // if the oldVNode was null or matched, then there could needs to be at least
418
+ // 1 (aka `remainingOldChildren > 0`) children to find and compare against.
419
+ let shouldSearch =
420
+ remainingOldChildren >
421
+ (oldVNode != null && (oldVNode._flags & MATCHED) === 0 ? 1 : 0);
422
+
423
+ if (
424
+ oldVNode === null ||
425
+ (oldVNode && key == oldVNode.key && type === oldVNode.type)
303
426
  ) {
304
- outer: if (oldDom == null || oldDom.parentNode !== parentDom) {
305
- parentDom.appendChild(newDom);
306
- nextDom = null;
307
- } else {
308
- // `j<oldChildrenLength; j+=2` is an alternative to `j++<oldChildrenLength/2`
309
- for (
310
- let sibDom = oldDom, j = 0;
311
- (sibDom = sibDom.nextSibling) && j < oldChildren.length;
312
- j += 1
313
- ) {
314
- if (sibDom == newDom) {
315
- break outer;
427
+ return skewedIndex;
428
+ } else if (shouldSearch) {
429
+ while (x >= 0 || y < oldChildren.length) {
430
+ if (x >= 0) {
431
+ oldVNode = oldChildren[x];
432
+ if (
433
+ oldVNode &&
434
+ (oldVNode._flags & MATCHED) === 0 &&
435
+ key == oldVNode.key &&
436
+ type === oldVNode.type
437
+ ) {
438
+ return x;
316
439
  }
440
+ x--;
317
441
  }
318
- parentDom.insertBefore(newDom, oldDom);
319
- nextDom = oldDom;
320
- }
321
- }
322
-
323
- // If we have pre-calculated the nextDOM node, use it. Else calculate it now
324
- // Strictly check for `undefined` here cuz `null` is a valid value of `nextDom`.
325
- // See more detail in create-element.js:createVNode
326
- if (nextDom !== undefined) {
327
- oldDom = nextDom;
328
- } else {
329
- oldDom = newDom.nextSibling;
330
- }
331
-
332
- return oldDom;
333
- }
334
442
 
335
- /**
336
- * @param {import('../internal').VNode} vnode
337
- */
338
- function getLastDom(vnode) {
339
- if (vnode.type == null || typeof vnode.type === 'string') {
340
- return vnode._dom;
341
- }
342
-
343
- if (vnode._children) {
344
- for (let i = vnode._children.length - 1; i >= 0; i--) {
345
- let child = vnode._children[i];
346
- if (child) {
347
- let lastDom = getLastDom(child);
348
- if (lastDom) {
349
- return lastDom;
443
+ if (y < oldChildren.length) {
444
+ oldVNode = oldChildren[y];
445
+ if (
446
+ oldVNode &&
447
+ (oldVNode._flags & MATCHED) === 0 &&
448
+ key == oldVNode.key &&
449
+ type === oldVNode.type
450
+ ) {
451
+ return y;
350
452
  }
453
+ y++;
351
454
  }
352
455
  }
353
456
  }
354
457
 
355
- return null;
458
+ return -1;
356
459
  }