@bpmn-io/properties-panel 3.13.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 +27 -30
  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,26 +1,33 @@
1
- import { EMPTY_OBJ } from '../constants';
2
- import { Component, getDomSibling } from '../component';
1
+ import {
2
+ EMPTY_OBJ,
3
+ MODE_HYDRATE,
4
+ MODE_SUSPENDED,
5
+ RESET_MODE
6
+ } from '../constants';
7
+ import { BaseComponent, getDomSibling } from '../component';
3
8
  import { Fragment } from '../create-element';
4
9
  import { diffChildren } from './children';
5
- import { diffProps, setProperty } from './props';
10
+ import { setProperty } from './props';
6
11
  import { assign, isArray, removeNode, slice } from '../util';
7
12
  import options from '../options';
8
13
 
9
14
  /**
10
15
  * Diff two virtual nodes and apply proper changes to the DOM
11
- * @param {import('../internal').PreactElement} parentDom The parent of the DOM element
12
- * @param {import('../internal').VNode} newVNode The new virtual node
13
- * @param {import('../internal').VNode} oldVNode The old virtual node
14
- * @param {object} globalContext The current context object. Modified by getChildContext
16
+ * @param {PreactElement} parentDom The parent of the DOM element
17
+ * @param {VNode} newVNode The new virtual node
18
+ * @param {VNode} oldVNode The old virtual node
19
+ * @param {object} globalContext The current context object. Modified by
20
+ * getChildContext
15
21
  * @param {boolean} isSvg Whether or not this element is an SVG node
16
- * @param {Array<import('../internal').PreactElement>} excessDomChildren
17
- * @param {Array<import('../internal').Component>} commitQueue List of components
18
- * which have callbacks to invoke in commitRoot
19
- * @param {import('../internal').PreactElement} oldDom The current attached DOM
20
- * element any new dom elements should be placed around. Likely `null` on first
21
- * render (except when hydrating). Can be a sibling DOM element when diffing
22
- * Fragments that have siblings. In most cases, it starts out as `oldChildren[0]._dom`.
23
- * @param {boolean} [isHydrating] Whether or not we are in hydration
22
+ * @param {Array<PreactElement>} excessDomChildren
23
+ * @param {Array<Component>} commitQueue List of components which have callbacks
24
+ * to invoke in commitRoot
25
+ * @param {PreactElement} oldDom The current attached DOM element any new dom
26
+ * elements should be placed around. Likely `null` on first render (except when
27
+ * hydrating). Can be a sibling DOM element when diffing Fragments that have
28
+ * siblings. In most cases, it starts out as `oldChildren[0]._dom`.
29
+ * @param {boolean} isHydrating Whether or not we are in hydration
30
+ * @param {any[]} refQueue an array of elements needed to invoke refs
24
31
  */
25
32
  export function diff(
26
33
  parentDom,
@@ -31,8 +38,10 @@ export function diff(
31
38
  excessDomChildren,
32
39
  commitQueue,
33
40
  oldDom,
34
- isHydrating
41
+ isHydrating,
42
+ refQueue
35
43
  ) {
44
+ /** @type {any} */
36
45
  let tmp,
37
46
  newType = newVNode.type;
38
47
 
@@ -41,18 +50,16 @@ export function diff(
41
50
  if (newVNode.constructor !== undefined) return null;
42
51
 
43
52
  // If the previous diff bailed out, resume creating/hydrating.
44
- if (oldVNode._hydrating != null) {
45
- isHydrating = oldVNode._hydrating;
53
+ if (oldVNode._flags & MODE_SUSPENDED) {
54
+ isHydrating = !!(oldVNode._flags & MODE_HYDRATE);
46
55
  oldDom = newVNode._dom = oldVNode._dom;
47
- // if we resume, we want the tree to be "unlocked"
48
- newVNode._hydrating = null;
49
56
  excessDomChildren = [oldDom];
50
57
  }
51
58
 
52
59
  if ((tmp = options._diff)) tmp(newVNode);
53
60
 
54
- try {
55
- outer: if (typeof newType == 'function') {
61
+ outer: if (typeof newType == 'function') {
62
+ try {
56
63
  let c, isNew, oldProps, oldState, snapshot, clearProcessingException;
57
64
  let newProps = newVNode.props;
58
65
 
@@ -73,11 +80,14 @@ export function diff(
73
80
  } else {
74
81
  // Instantiate the new component
75
82
  if ('prototype' in newType && newType.prototype.render) {
76
- // @ts-ignore The check above verifies that newType is suppose to be constructed
83
+ // @ts-expect-error The check above verifies that newType is suppose to be constructed
77
84
  newVNode._component = c = new newType(newProps, componentContext); // eslint-disable-line new-cap
78
85
  } else {
79
- // @ts-ignore Trust me, Component implements the interface we want
80
- newVNode._component = c = new Component(newProps, componentContext);
86
+ // @ts-expect-error Trust me, Component implements the interface we want
87
+ newVNode._component = c = new BaseComponent(
88
+ newProps,
89
+ componentContext
90
+ );
81
91
  c.constructor = newType;
82
92
  c.render = doRender;
83
93
  }
@@ -134,14 +144,14 @@ export function diff(
134
144
  }
135
145
 
136
146
  if (
137
- (!c._force &&
138
- c.shouldComponentUpdate != null &&
147
+ !c._force &&
148
+ ((c.shouldComponentUpdate != null &&
139
149
  c.shouldComponentUpdate(
140
150
  newProps,
141
151
  c._nextState,
142
152
  componentContext
143
153
  ) === false) ||
144
- newVNode._original === oldVNode._original
154
+ newVNode._original === oldVNode._original)
145
155
  ) {
146
156
  // More info about this here: https://gist.github.com/JoviDeCroock/bec5f2ce93544d2e6070ef8e0036e4e8
147
157
  if (newVNode._original !== oldVNode._original) {
@@ -154,8 +164,6 @@ export function diff(
154
164
  c._dirty = false;
155
165
  }
156
166
 
157
- // In cases of bailing due to strict-equality we have to reset force as well
158
- c._force = false;
159
167
  newVNode._dom = oldVNode._dom;
160
168
  newVNode._children = oldVNode._children;
161
169
  newVNode._children.forEach(vnode => {
@@ -188,6 +196,7 @@ export function diff(
188
196
  c.context = componentContext;
189
197
  c.props = newProps;
190
198
  c._parentDom = parentDom;
199
+ c._force = false;
191
200
 
192
201
  let renderHook = options._render,
193
202
  count = 0;
@@ -240,13 +249,14 @@ export function diff(
240
249
  excessDomChildren,
241
250
  commitQueue,
242
251
  oldDom,
243
- isHydrating
252
+ isHydrating,
253
+ refQueue
244
254
  );
245
255
 
246
256
  c.base = newVNode._dom;
247
257
 
248
258
  // We successfully rendered this VNode, unset any stored hydration/bailout state:
249
- newVNode._hydrating = null;
259
+ newVNode._flags &= RESET_MODE;
250
260
 
251
261
  if (c._renderCallbacks.length) {
252
262
  commitQueue.push(c);
@@ -255,57 +265,67 @@ export function diff(
255
265
  if (clearProcessingException) {
256
266
  c._pendingError = c._processingException = null;
257
267
  }
258
-
259
- c._force = false;
260
- } else if (
261
- excessDomChildren == null &&
262
- newVNode._original === oldVNode._original
263
- ) {
264
- newVNode._children = oldVNode._children;
265
- newVNode._dom = oldVNode._dom;
266
- } else {
267
- newVNode._dom = diffElementNodes(
268
- oldVNode._dom,
269
- newVNode,
270
- oldVNode,
271
- globalContext,
272
- isSvg,
273
- excessDomChildren,
274
- commitQueue,
275
- isHydrating
276
- );
277
- }
278
-
279
- if ((tmp = options.diffed)) tmp(newVNode);
280
- } catch (e) {
281
- newVNode._original = null;
282
- // if hydrating or creating initial tree, bailout preserves DOM:
283
- if (isHydrating || excessDomChildren != null) {
284
- newVNode._dom = oldDom;
285
- newVNode._hydrating = !!isHydrating;
286
- excessDomChildren[excessDomChildren.indexOf(oldDom)] = null;
287
- // ^ could possibly be simplified to:
288
- // excessDomChildren.length = 0;
268
+ } catch (e) {
269
+ newVNode._original = null;
270
+ // if hydrating or creating initial tree, bailout preserves DOM:
271
+ if (isHydrating || excessDomChildren != null) {
272
+ newVNode._dom = oldDom;
273
+ newVNode._flags |= isHydrating
274
+ ? MODE_HYDRATE | MODE_SUSPENDED
275
+ : MODE_HYDRATE;
276
+ excessDomChildren[excessDomChildren.indexOf(oldDom)] = null;
277
+ // ^ could possibly be simplified to:
278
+ // excessDomChildren.length = 0;
279
+ } else {
280
+ newVNode._dom = oldVNode._dom;
281
+ newVNode._children = oldVNode._children;
282
+ }
283
+ options._catchError(e, newVNode, oldVNode);
289
284
  }
290
- options._catchError(e, newVNode, oldVNode);
285
+ } else if (
286
+ excessDomChildren == null &&
287
+ newVNode._original === oldVNode._original
288
+ ) {
289
+ newVNode._children = oldVNode._children;
290
+ newVNode._dom = oldVNode._dom;
291
+ } else {
292
+ newVNode._dom = diffElementNodes(
293
+ oldVNode._dom,
294
+ newVNode,
295
+ oldVNode,
296
+ globalContext,
297
+ isSvg,
298
+ excessDomChildren,
299
+ commitQueue,
300
+ isHydrating,
301
+ refQueue
302
+ );
291
303
  }
304
+
305
+ if ((tmp = options.diffed)) tmp(newVNode);
292
306
  }
293
307
 
294
308
  /**
295
- * @param {Array<import('../internal').Component>} commitQueue List of components
309
+ * @param {Array<Component>} commitQueue List of components
296
310
  * which have callbacks to invoke in commitRoot
297
- * @param {import('../internal').VNode} root
311
+ * @param {VNode} root
298
312
  */
299
- export function commitRoot(commitQueue, root) {
313
+ export function commitRoot(commitQueue, root, refQueue) {
314
+ root._nextDom = undefined;
315
+
316
+ for (let i = 0; i < refQueue.length; i++) {
317
+ applyRef(refQueue[i], refQueue[++i], refQueue[++i]);
318
+ }
319
+
300
320
  if (options._commit) options._commit(root, commitQueue);
301
321
 
302
322
  commitQueue.some(c => {
303
323
  try {
304
- // @ts-ignore Reuse the commitQueue variable here so the type changes
324
+ // @ts-expect-error Reuse the commitQueue variable here so the type changes
305
325
  commitQueue = c._renderCallbacks;
306
326
  c._renderCallbacks = [];
307
327
  commitQueue.some(cb => {
308
- // @ts-ignore See above ts-ignore on commitQueue
328
+ // @ts-expect-error See above comment on commitQueue
309
329
  cb.call(c);
310
330
  });
311
331
  } catch (e) {
@@ -316,17 +336,18 @@ export function commitRoot(commitQueue, root) {
316
336
 
317
337
  /**
318
338
  * Diff two virtual nodes representing DOM element
319
- * @param {import('../internal').PreactElement} dom The DOM element representing
320
- * the virtual nodes being diffed
321
- * @param {import('../internal').VNode} newVNode The new virtual node
322
- * @param {import('../internal').VNode} oldVNode The old virtual node
339
+ * @param {PreactElement} dom The DOM element representing the virtual nodes
340
+ * being diffed
341
+ * @param {VNode} newVNode The new virtual node
342
+ * @param {VNode} oldVNode The old virtual node
323
343
  * @param {object} globalContext The current context object
324
344
  * @param {boolean} isSvg Whether or not this DOM node is an SVG node
325
- * @param {*} excessDomChildren
326
- * @param {Array<import('../internal').Component>} commitQueue List of components
327
- * which have callbacks to invoke in commitRoot
345
+ * @param {Array<PreactElement>} excessDomChildren
346
+ * @param {Array<Component>} commitQueue List of components which have callbacks
347
+ * to invoke in commitRoot
328
348
  * @param {boolean} isHydrating Whether or not we are in hydration
329
- * @returns {import('../internal').PreactElement}
349
+ * @param {any[]} refQueue an array of elements needed to invoke refs
350
+ * @returns {PreactElement}
330
351
  */
331
352
  function diffElementNodes(
332
353
  dom,
@@ -336,29 +357,40 @@ function diffElementNodes(
336
357
  isSvg,
337
358
  excessDomChildren,
338
359
  commitQueue,
339
- isHydrating
360
+ isHydrating,
361
+ refQueue
340
362
  ) {
341
363
  let oldProps = oldVNode.props;
342
364
  let newProps = newVNode.props;
343
- let nodeType = newVNode.type;
344
- let i = 0;
365
+ let nodeType = /** @type {string} */ (newVNode.type);
366
+ /** @type {any} */
367
+ let i;
368
+ /** @type {{ __html?: string }} */
369
+ let newHtml;
370
+ /** @type {{ __html?: string }} */
371
+ let oldHtml;
372
+ /** @type {ComponentChildren} */
373
+ let newChildren;
374
+ let value;
375
+ let inputValue;
376
+ let checked;
345
377
 
346
378
  // Tracks entering and exiting SVG namespace when descending through the tree.
347
379
  if (nodeType === 'svg') isSvg = true;
348
380
 
349
381
  if (excessDomChildren != null) {
350
- for (; i < excessDomChildren.length; i++) {
351
- const child = excessDomChildren[i];
382
+ for (i = 0; i < excessDomChildren.length; i++) {
383
+ value = excessDomChildren[i];
352
384
 
353
385
  // if newVNode matches an element in excessDomChildren or the `dom`
354
386
  // argument matches an element in excessDomChildren, remove it from
355
387
  // excessDomChildren so it isn't later removed in diffChildren
356
388
  if (
357
- child &&
358
- 'setAttribute' in child === !!nodeType &&
359
- (nodeType ? child.localName === nodeType : child.nodeType === 3)
389
+ value &&
390
+ 'setAttribute' in value === !!nodeType &&
391
+ (nodeType ? value.localName === nodeType : value.nodeType === 3)
360
392
  ) {
361
- dom = child;
393
+ dom = value;
362
394
  excessDomChildren[i] = null;
363
395
  break;
364
396
  }
@@ -367,27 +399,19 @@ function diffElementNodes(
367
399
 
368
400
  if (dom == null) {
369
401
  if (nodeType === null) {
370
- // @ts-ignore createTextNode returns Text, we expect PreactElement
371
402
  return document.createTextNode(newProps);
372
403
  }
373
404
 
374
405
  if (isSvg) {
375
- dom = document.createElementNS(
376
- 'http://www.w3.org/2000/svg',
377
- // @ts-ignore We know `newVNode.type` is a string
378
- nodeType
379
- );
406
+ dom = document.createElementNS('http://www.w3.org/2000/svg', nodeType);
380
407
  } else {
381
- dom = document.createElement(
382
- // @ts-ignore We know `newVNode.type` is a string
383
- nodeType,
384
- newProps.is && newProps
385
- );
408
+ dom = document.createElement(nodeType, newProps.is && newProps);
386
409
  }
387
410
 
388
411
  // we created a new parent, so none of the previously attached children can be reused:
389
412
  excessDomChildren = null;
390
- // we are creating a new node, so we can assume this is a new subtree (in case we are hydrating), this deopts the hydrate
413
+ // we are creating a new node, so we can assume this is a new subtree (in
414
+ // case we are hydrating), this deopts the hydrate
391
415
  isHydrating = false;
392
416
  }
393
417
 
@@ -402,43 +426,67 @@ function diffElementNodes(
402
426
 
403
427
  oldProps = oldVNode.props || EMPTY_OBJ;
404
428
 
405
- let oldHtml = oldProps.dangerouslySetInnerHTML;
406
- let newHtml = newProps.dangerouslySetInnerHTML;
407
-
408
- // During hydration, props are not diffed at all (including dangerouslySetInnerHTML)
409
- // @TODO we should warn in debug mode when props don't match here.
410
- if (!isHydrating) {
411
- // But, if we are in a situation where we are using existing DOM (e.g. replaceNode)
412
- // we should read the existing DOM attributes to diff them
413
- if (excessDomChildren != null) {
414
- oldProps = {};
415
- for (i = 0; i < dom.attributes.length; i++) {
416
- oldProps[dom.attributes[i].name] = dom.attributes[i].value;
417
- }
429
+ // If we are in a situation where we are not hydrating but are using
430
+ // existing DOM (e.g. replaceNode) we should read the existing DOM
431
+ // attributes to diff them
432
+ if (!isHydrating && excessDomChildren != null) {
433
+ oldProps = {};
434
+ for (i = 0; i < dom.attributes.length; i++) {
435
+ value = dom.attributes[i];
436
+ oldProps[value.name] = value.value;
418
437
  }
438
+ }
419
439
 
420
- if (newHtml || oldHtml) {
421
- // Avoid re-applying the same '__html' if it did not changed between re-render
422
- if (
423
- !newHtml ||
424
- ((!oldHtml || newHtml.__html != oldHtml.__html) &&
425
- newHtml.__html !== dom.innerHTML)
426
- ) {
427
- dom.innerHTML = (newHtml && newHtml.__html) || '';
428
- }
440
+ for (i in oldProps) {
441
+ value = oldProps[i];
442
+ if (i == 'children') {
443
+ } else if (i == 'dangerouslySetInnerHTML') {
444
+ oldHtml = value;
445
+ } else if (i !== 'key' && !(i in newProps)) {
446
+ setProperty(dom, i, null, value, isSvg);
429
447
  }
430
448
  }
431
449
 
432
- diffProps(dom, newProps, oldProps, isSvg, isHydrating);
450
+ // During hydration, props are not diffed at all (including dangerouslySetInnerHTML)
451
+ // @TODO we should warn in debug mode when props don't match here.
452
+ for (i in newProps) {
453
+ value = newProps[i];
454
+ if (i == 'children') {
455
+ newChildren = value;
456
+ } else if (i == 'dangerouslySetInnerHTML') {
457
+ newHtml = value;
458
+ } else if (i == 'value') {
459
+ inputValue = value;
460
+ } else if (i == 'checked') {
461
+ checked = value;
462
+ } else if (
463
+ i !== 'key' &&
464
+ (!isHydrating || typeof value == 'function') &&
465
+ oldProps[i] !== value
466
+ ) {
467
+ setProperty(dom, i, value, oldProps[i], isSvg);
468
+ }
469
+ }
433
470
 
434
471
  // If the new vnode didn't have dangerouslySetInnerHTML, diff its children
435
472
  if (newHtml) {
473
+ // Avoid re-applying the same '__html' if it did not changed between re-render
474
+ if (
475
+ !isHydrating &&
476
+ (!oldHtml ||
477
+ (newHtml.__html !== oldHtml.__html &&
478
+ newHtml.__html !== dom.innerHTML))
479
+ ) {
480
+ dom.innerHTML = newHtml.__html;
481
+ }
482
+
436
483
  newVNode._children = [];
437
484
  } else {
438
- i = newVNode.props.children;
485
+ if (oldHtml) dom.innerHTML = '';
486
+
439
487
  diffChildren(
440
488
  dom,
441
- isArray(i) ? i : [i],
489
+ isArray(newChildren) ? newChildren : [newChildren],
442
490
  newVNode,
443
491
  oldVNode,
444
492
  globalContext,
@@ -448,7 +496,8 @@ function diffElementNodes(
448
496
  excessDomChildren
449
497
  ? excessDomChildren[0]
450
498
  : oldVNode._children && getDomSibling(oldVNode, 0),
451
- isHydrating
499
+ isHydrating,
500
+ refQueue
452
501
  );
453
502
 
454
503
  // Remove children that are not part of any vnode.
@@ -459,30 +508,28 @@ function diffElementNodes(
459
508
  }
460
509
  }
461
510
 
462
- // (as above, don't diff props during hydration)
511
+ // As above, don't diff props during hydration
463
512
  if (!isHydrating) {
513
+ i = 'value';
464
514
  if (
465
- 'value' in newProps &&
466
- (i = newProps.value) !== undefined &&
515
+ inputValue !== undefined &&
467
516
  // #2756 For the <progress>-element the initial value is 0,
468
517
  // despite the attribute not being present. When the attribute
469
518
  // is missing the progress bar is treated as indeterminate.
470
519
  // To fix that we'll always update it when it is 0 for progress elements
471
- (i !== dom.value ||
472
- (nodeType === 'progress' && !i) ||
520
+ (inputValue !== dom[i] ||
521
+ (nodeType === 'progress' && !inputValue) ||
473
522
  // This is only for IE 11 to fix <select> value not being updated.
474
523
  // To avoid a stale select value we need to set the option.value
475
524
  // again, which triggers IE11 to re-evaluate the select value
476
- (nodeType === 'option' && i !== oldProps.value))
525
+ (nodeType === 'option' && inputValue !== oldProps[i]))
477
526
  ) {
478
- setProperty(dom, 'value', i, oldProps.value, false);
527
+ setProperty(dom, i, inputValue, oldProps[i], false);
479
528
  }
480
- if (
481
- 'checked' in newProps &&
482
- (i = newProps.checked) !== undefined &&
483
- i !== dom.checked
484
- ) {
485
- setProperty(dom, 'checked', i, oldProps.checked, false);
529
+
530
+ i = 'checked';
531
+ if (checked !== undefined && checked !== dom[i]) {
532
+ setProperty(dom, i, checked, oldProps[i], false);
486
533
  }
487
534
  }
488
535
  }
@@ -492,9 +539,9 @@ function diffElementNodes(
492
539
 
493
540
  /**
494
541
  * Invoke or update a ref, depending on whether it is a function or object ref.
495
- * @param {object|function} ref
542
+ * @param {Ref<any>} ref
496
543
  * @param {any} value
497
- * @param {import('../internal').VNode} vnode
544
+ * @param {VNode} vnode
498
545
  */
499
546
  export function applyRef(ref, value, vnode) {
500
547
  try {
@@ -507,9 +554,8 @@ export function applyRef(ref, value, vnode) {
507
554
 
508
555
  /**
509
556
  * Unmount a virtual node from the tree and apply DOM changes
510
- * @param {import('../internal').VNode} vnode The virtual node to unmount
511
- * @param {import('../internal').VNode} parentVNode The parent of the VNode that
512
- * initiated the unmount
557
+ * @param {VNode} vnode The virtual node to unmount
558
+ * @param {VNode} parentVNode The parent of the VNode that initiated the unmount
513
559
  * @param {boolean} [skipRemove] Flag that indicates that a parent node of the
514
560
  * current element is already detached from the DOM.
515
561
  */
@@ -1,38 +1,6 @@
1
1
  import { IS_NON_DIMENSIONAL } from '../constants';
2
2
  import options from '../options';
3
3
 
4
- /**
5
- * Diff the old and new properties of a VNode and apply changes to the DOM node
6
- * @param {import('../internal').PreactElement} dom The DOM node to apply
7
- * changes to
8
- * @param {object} newProps The new props
9
- * @param {object} oldProps The old props
10
- * @param {boolean} isSvg Whether or not this node is an SVG node
11
- * @param {boolean} hydrate Whether or not we are in hydration mode
12
- */
13
- export function diffProps(dom, newProps, oldProps, isSvg, hydrate) {
14
- let i;
15
-
16
- for (i in oldProps) {
17
- if (i !== 'children' && i !== 'key' && !(i in newProps)) {
18
- setProperty(dom, i, null, oldProps[i], isSvg);
19
- }
20
- }
21
-
22
- for (i in newProps) {
23
- if (
24
- (!hydrate || typeof newProps[i] == 'function') &&
25
- i !== 'children' &&
26
- i !== 'key' &&
27
- i !== 'value' &&
28
- i !== 'checked' &&
29
- oldProps[i] !== newProps[i]
30
- ) {
31
- setProperty(dom, i, newProps[i], oldProps[i], isSvg);
32
- }
33
- }
34
- }
35
-
36
4
  function setStyle(style, key, value) {
37
5
  if (key[0] === '-') {
38
6
  style.setProperty(key, value == null ? '' : value);
@@ -47,7 +15,7 @@ function setStyle(style, key, value) {
47
15
 
48
16
  /**
49
17
  * Set a property value on a DOM node
50
- * @param {import('../internal').PreactElement} dom The DOM node to modify
18
+ * @param {PreactElement} dom The DOM node to modify
51
19
  * @param {string} name The name of the property to set
52
20
  * @param {*} value The value to set the property to
53
21
  * @param {*} oldValue The old value the property had
@@ -83,7 +51,8 @@ export function setProperty(dom, name, value, oldValue, isSvg) {
83
51
  }
84
52
  // Benchmark for comparison: https://esbench.com/bench/574c954bdb965b9a00965ac6
85
53
  else if (name[0] === 'o' && name[1] === 'n') {
86
- useCapture = name !== (name = name.replace(/Capture$/, ''));
54
+ useCapture =
55
+ name !== (name = name.replace(/(PointerCapture)$|Capture$/, '$1'));
87
56
 
88
57
  // Infer correct casing for DOM built-in events:
89
58
  if (name.toLowerCase() in dom) name = name.toLowerCase().slice(2);
@@ -94,14 +63,17 @@ export function setProperty(dom, name, value, oldValue, isSvg) {
94
63
 
95
64
  if (value) {
96
65
  if (!oldValue) {
66
+ value._attached = Date.now();
97
67
  const handler = useCapture ? eventProxyCapture : eventProxy;
98
68
  dom.addEventListener(name, handler, useCapture);
69
+ } else {
70
+ value._attached = oldValue._attached;
99
71
  }
100
72
  } else {
101
73
  const handler = useCapture ? eventProxyCapture : eventProxy;
102
74
  dom.removeEventListener(name, handler, useCapture);
103
75
  }
104
- } else if (name !== 'dangerouslySetInnerHTML') {
76
+ } else {
105
77
  if (isSvg) {
106
78
  // Normalize incorrect prop usage for SVG:
107
79
  // - xlink:href / xlinkHref --> href (xlink:href was removed from SVG and isn't needed)
@@ -119,6 +91,7 @@ export function setProperty(dom, name, value, oldValue, isSvg) {
119
91
  name !== 'download' &&
120
92
  name !== 'rowSpan' &&
121
93
  name !== 'colSpan' &&
94
+ name !== 'role' &&
122
95
  name in dom
123
96
  ) {
124
97
  try {
@@ -135,7 +108,7 @@ export function setProperty(dom, name, value, oldValue, isSvg) {
135
108
  // amount of exceptions would cost too many bytes. On top of
136
109
  // that other frameworks generally stringify `false`.
137
110
 
138
- if (typeof value === 'function') {
111
+ if (typeof value == 'function') {
139
112
  // never serialize functions as attribute values
140
113
  } else if (value != null && (value !== false || name[4] === '-')) {
141
114
  dom.setAttribute(name, value);
@@ -147,13 +120,33 @@ export function setProperty(dom, name, value, oldValue, isSvg) {
147
120
 
148
121
  /**
149
122
  * Proxy an event to hooked event handlers
150
- * @param {Event} e The event object from the browser
123
+ * @param {PreactEvent} e The event object from the browser
151
124
  * @private
152
125
  */
153
126
  function eventProxy(e) {
154
- return this._listeners[e.type + false](options.event ? options.event(e) : e);
127
+ const eventHandler = this._listeners[e.type + false];
128
+ /**
129
+ * This trick is inspired by Vue https://github.com/vuejs/core/blob/main/packages/runtime-dom/src/modules/events.ts#L90-L101
130
+ * when the dom performs an event it leaves micro-ticks in between bubbling up which means that an event can trigger on a newly
131
+ * created DOM-node while the event bubbles up, this can cause quirky behavior as seen in https://github.com/preactjs/preact/issues/3927
132
+ */
133
+ if (!e._dispatched) {
134
+ // When an event has no _dispatched we know this is the first event-target in the chain
135
+ // so we set the initial dispatched time.
136
+ e._dispatched = Date.now();
137
+ // When the _dispatched is smaller than the time when the targetted event handler was attached
138
+ // we know we have bubbled up to an element that was added during patching the dom.
139
+ } else if (e._dispatched <= eventHandler._attached) {
140
+ return;
141
+ }
142
+ return eventHandler(options.event ? options.event(e) : e);
155
143
  }
156
144
 
145
+ /**
146
+ * Proxy an event to hooked event handlers
147
+ * @param {PreactEvent} e The event object from the browser
148
+ * @private
149
+ */
157
150
  function eventProxyCapture(e) {
158
151
  return this._listeners[e.type + true](options.event ? options.event(e) : e);
159
152
  }