@simpreact/simpreact 0.0.5 → 0.0.7

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 (83) hide show
  1. package/LICENSE.txt +1 -1
  2. package/compat/context.d.ts +4 -4
  3. package/compat/context.js +3 -2
  4. package/compat/core.d.ts +4 -0
  5. package/compat/core.js +9 -5
  6. package/compat/dom.d.ts +4 -5
  7. package/compat/dom.js +3 -2
  8. package/compat/hooks.d.ts +16 -13
  9. package/compat/hooks.js +19 -15
  10. package/compat/index.d.ts +12 -9
  11. package/compat/index.js +3 -0
  12. package/compat/renderRuntime.d.ts +6 -0
  13. package/compat/renderRuntime.js +17 -0
  14. package/component/index.d.ts +16 -0
  15. package/component/index.js +164 -0
  16. package/context/index.d.ts +12 -5
  17. package/context/index.js +62 -57
  18. package/core/createElement.d.ts +29 -20
  19. package/core/createElement.js +159 -133
  20. package/core/hostAdapter.d.ts +8 -12
  21. package/core/hostAdapter.js +1 -4
  22. package/core/hostOperations.d.ts +5 -0
  23. package/core/hostOperations.js +15 -0
  24. package/core/index.d.ts +20 -6
  25. package/core/internal.d.ts +5 -0
  26. package/core/internal.js +5 -0
  27. package/core/lifecycleEventBus.d.ts +15 -6
  28. package/core/lifecycleEventBus.js +16 -2
  29. package/core/memo.d.ts +0 -2
  30. package/core/memo.js +1 -3
  31. package/core/mounting.d.ts +6 -9
  32. package/core/mounting.js +177 -86
  33. package/core/mountingChildren.d.ts +4 -0
  34. package/core/mountingChildren.js +47 -0
  35. package/core/patching.d.ts +7 -8
  36. package/core/patching.js +245 -252
  37. package/core/patchingChildren.d.ts +6 -0
  38. package/core/patchingChildren.js +343 -0
  39. package/core/portal.d.ts +1 -1
  40. package/core/portal.js +17 -7
  41. package/core/processStack.d.ts +106 -0
  42. package/core/processStack.js +75 -0
  43. package/core/ref.d.ts +4 -3
  44. package/core/rerender.d.ts +4 -14
  45. package/core/rerender.js +67 -112
  46. package/core/runtime.d.ts +17 -0
  47. package/core/runtime.js +2 -0
  48. package/core/unmounting.d.ts +6 -5
  49. package/core/unmounting.js +58 -57
  50. package/core/unmountingChildren.d.ts +4 -0
  51. package/core/unmountingChildren.js +23 -0
  52. package/core/utils.d.ts +11 -0
  53. package/core/utils.js +168 -0
  54. package/dom/attach-element-to-dom.d.ts +4 -3
  55. package/dom/attach-element-to-dom.js +12 -7
  56. package/dom/domAdapter.js +22 -25
  57. package/dom/events.d.ts +5 -5
  58. package/dom/events.js +33 -16
  59. package/dom/index.d.ts +16 -5
  60. package/dom/index.js +4 -3
  61. package/dom/props/controlled/index.d.ts +3 -3
  62. package/dom/props/controlled/index.js +8 -8
  63. package/dom/props/controlled/input.d.ts +3 -3
  64. package/dom/props/controlled/input.js +57 -34
  65. package/dom/props/controlled/select.d.ts +3 -3
  66. package/dom/props/controlled/select.js +39 -26
  67. package/dom/props/controlled/textarea.d.ts +3 -3
  68. package/dom/props/controlled/textarea.js +57 -34
  69. package/dom/props/dangerInnerHTML.d.ts +5 -5
  70. package/dom/props/dangerInnerHTML.js +10 -15
  71. package/dom/props/props.d.ts +4 -4
  72. package/dom/props/props.js +24 -21
  73. package/dom/render.d.ts +4 -5
  74. package/dom/render.js +38 -34
  75. package/hooks/index.d.ts +15 -13
  76. package/hooks/index.js +154 -157
  77. package/jsx-runtime/index.d.ts +2 -1
  78. package/package.json +9 -1
  79. package/shared/index.d.ts +10 -0
  80. package/shared/index.js +4 -7
  81. package/shared/utils.js +4 -4
  82. package/shared/EventBus.d.ts +0 -18
  83. package/shared/EventBus.js +0 -28
package/core/patching.js CHANGED
@@ -1,81 +1,157 @@
1
- import { emptyObject } from '../shared/index.js';
2
- import { normalizeRoot } from './createElement.js';
3
- import { hostAdapter } from './hostAdapter.js';
4
- import { clearElementHostReference, remove, unmount } from './unmounting.js';
5
- import { mount, mountArrayChildren, mountFunctionalElement } from './mounting.js';
6
- import { applyRef } from './ref.js';
1
+ import { normalizeRoot, SIMP_ELEMENT_CHILD_FLAG_ELEMENT, SIMP_ELEMENT_CHILD_FLAG_EMPTY, SIMP_ELEMENT_CHILD_FLAG_LIST, SIMP_ELEMENT_FLAG_HOST, } from './createElement.js';
2
+ import { _pushHostOperationReplaceElement } from './hostOperations.js';
7
3
  import { lifecycleEventBus } from './lifecycleEventBus.js';
8
4
  import { isMemo } from './memo.js';
9
- export function patch(prevElement, nextElement, parentReference, nextReference, context, hostNamespace) {
5
+ import { _pushMountEnterFrame } from './mounting.js';
6
+ import { _pushPatchChildrenFrame } from './patchingChildren.js';
7
+ import { PATCH_ENTER, PATCH_EXIT, processStack } from './processStack.js';
8
+ import { applyRef } from './ref.js';
9
+ import { UPDATING_PHASE } from './runtime.js';
10
+ import { _pushUnmountEnterFrame } from './unmounting.js';
11
+ import { _clearElementHostReference, bitScanForwardIndex } from './utils.js';
12
+ const patchHandlers = [_patchHostElement, _patchFunctionalComponent, _patchTextElement, _patchPortal, _patchFragment];
13
+ export function patch(prevElement, nextElement, parentReference, subtreeRightBoundary, context, hostNamespace, renderRuntime) {
14
+ if (renderRuntime.renderStack.length !== 0) {
15
+ throw new Error('Cannot patch while rendering.');
16
+ }
17
+ _pushPatchEnterFrame(nextElement, {
18
+ prevElement,
19
+ parentReference,
20
+ renderRuntime,
21
+ subtreeRightBoundary,
22
+ context,
23
+ hostNamespace,
24
+ });
25
+ processStack(renderRuntime);
26
+ }
27
+ export function _pushPatchEnterFrame(element, meta) {
28
+ meta.renderRuntime.renderStack.push({
29
+ node: element,
30
+ kind: PATCH_ENTER,
31
+ meta,
32
+ });
33
+ }
34
+ export function _pushPatchExitFrame(element, meta) {
35
+ meta.renderRuntime.renderStack.push({
36
+ node: element,
37
+ kind: PATCH_EXIT,
38
+ meta,
39
+ });
40
+ }
41
+ export function _patch(frame) {
42
+ const nextElement = frame.node;
43
+ const { prevElement } = frame.meta;
44
+ // Early return if the elements are different type or have different keys.
10
45
  if (prevElement.type !== nextElement.type || prevElement.key !== nextElement.key) {
11
- replaceWithNewElement(prevElement, nextElement, parentReference, context, hostNamespace);
12
- }
13
- else if (nextElement.flag === 'HOST') {
14
- patchHostElement(prevElement, nextElement, context, hostNamespace);
15
- }
16
- else if (nextElement.flag === 'FC') {
17
- patchFunctionalComponent(prevElement, nextElement, parentReference, nextReference, context, hostNamespace);
18
- }
19
- else if (nextElement.flag === 'TEXT') {
20
- patchTextElement(prevElement, nextElement);
21
- }
22
- else if (nextElement.flag === 'FRAGMENT') {
23
- patchFragment(prevElement, nextElement, parentReference, context, hostNamespace);
24
- }
25
- else {
26
- patchPortal(prevElement, nextElement, context);
46
+ _replaceWithNewElement(frame);
47
+ return;
27
48
  }
49
+ patchHandlers[bitScanForwardIndex(frame.node.flag)](frame);
28
50
  }
29
- function replaceWithNewElement(prevElement, nextElement, parentReference, context, hostNamespace) {
30
- unmount(prevElement);
51
+ function _replaceWithNewElement(frame) {
52
+ const nextElement = frame.node;
53
+ const { prevElement, parentReference, context, hostNamespace, renderRuntime } = frame.meta;
54
+ _pushUnmountEnterFrame(prevElement, frame.meta);
31
55
  nextElement.parent = prevElement.parent;
32
- if (nextElement.flag === 'HOST' && prevElement.flag === 'HOST') {
33
- mount(nextElement, null, null, context, hostNamespace);
34
- hostAdapter.replaceChild(parentReference, nextElement.reference, prevElement.reference);
56
+ if ((nextElement.flag & SIMP_ELEMENT_FLAG_HOST) !== 0 && (prevElement.flag & SIMP_ELEMENT_FLAG_HOST) !== 0) {
57
+ _pushHostOperationReplaceElement(nextElement, renderRuntime, {
58
+ prevElement,
59
+ parentReference,
60
+ });
61
+ _pushMountEnterFrame(nextElement, {
62
+ context,
63
+ hostNamespace,
64
+ renderRuntime,
65
+ parentReference: null,
66
+ subtreeRightBoundary: null,
67
+ placeHolderElement: null,
68
+ });
35
69
  }
36
70
  else {
37
- mount(nextElement, parentReference, findHostReferenceFromElement(prevElement), context, hostNamespace);
38
- clearElementHostReference(prevElement, parentReference);
71
+ _clearElementHostReference(prevElement, parentReference, renderRuntime);
72
+ _pushMountEnterFrame(nextElement, {
73
+ subtreeRightBoundary: frame.meta.subtreeRightBoundary,
74
+ renderRuntime,
75
+ hostNamespace,
76
+ context,
77
+ parentReference,
78
+ placeHolderElement: null,
79
+ });
39
80
  }
40
81
  }
41
- function patchHostElement(prevElement, nextElement, context, hostNamespace) {
42
- if (prevElement.ref) {
43
- nextElement.ref = prevElement.ref;
82
+ function _patchHostElement(frame) {
83
+ const nextElement = frame.node;
84
+ const { prevElement, context, hostNamespace, renderRuntime, subtreeRightBoundary, parentReference } = frame.meta;
85
+ if (frame.kind === PATCH_EXIT) {
86
+ renderRuntime.hostAdapter.patchProps(nextElement.reference, prevElement, nextElement, renderRuntime, hostNamespace);
87
+ if (prevElement.className !== nextElement.className) {
88
+ renderRuntime.hostAdapter.setClassname(nextElement.reference, nextElement.className, hostNamespace);
89
+ }
90
+ applyRef(nextElement);
91
+ return;
44
92
  }
45
- const hostNamespaces = hostAdapter.getHostNamespaces(nextElement, hostNamespace);
46
- hostNamespace = hostNamespaces?.self;
93
+ nextElement.ref = prevElement.ref;
47
94
  nextElement.reference = prevElement.reference;
48
- hostAdapter.attachElementToReference(nextElement, nextElement.reference);
49
- patchChildren(prevElement.children || prevElement.props?.children, nextElement.children || nextElement.props?.children, nextElement.reference, null, nextElement, context, hostNamespaces?.children);
50
- hostAdapter.patchProps(nextElement.reference, prevElement, nextElement, hostNamespace);
51
- if (prevElement.className !== nextElement.className) {
52
- hostAdapter.setClassname(nextElement.reference, nextElement.className, hostNamespace);
53
- }
54
- applyRef(nextElement);
95
+ renderRuntime.hostAdapter.attachElementToReference(nextElement, nextElement.reference, renderRuntime);
96
+ _pushPatchExitFrame(nextElement, {
97
+ prevElement,
98
+ renderRuntime,
99
+ hostNamespace,
100
+ subtreeRightBoundary,
101
+ context,
102
+ parentReference,
103
+ });
104
+ _pushPatchChildrenFrame(nextElement, {
105
+ prevParentElement: prevElement,
106
+ nextChildren: nextElement.children,
107
+ prevChildren: prevElement.children,
108
+ nextParentChildFlag: nextElement.childFlag,
109
+ prevParentChildFlag: prevElement.childFlag,
110
+ subtreeRightBoundary,
111
+ hostNamespace: renderRuntime.hostAdapter.getHostNamespaces(nextElement, hostNamespace)?.children,
112
+ context,
113
+ parentReference: nextElement.reference,
114
+ renderRuntime,
115
+ });
55
116
  }
56
- function patchFunctionalComponent(prevElement, nextElement, parentReference, nextReference, context, hostNamespace) {
57
- nextElement.store = prevElement.store || {};
58
- nextElement.store.latestElement = nextElement;
59
- if (hostNamespace) {
60
- nextElement.store.hostNamespace = hostNamespace;
61
- }
62
- let forceRender = false;
63
- if (prevElement.store?.forceRender) {
64
- forceRender = true;
65
- prevElement.store.forceRender = false;
117
+ function _patchFunctionalComponent(frame) {
118
+ const nextElement = frame.node;
119
+ const { prevElement, context, renderRuntime, hostNamespace, subtreeRightBoundary, parentReference } = frame.meta;
120
+ if (frame.kind === PATCH_EXIT) {
121
+ lifecycleEventBus.publish({ type: 'updated', element: nextElement, renderRuntime });
122
+ return;
66
123
  }
67
124
  if (prevElement.unmounted) {
68
- mountFunctionalElement(nextElement, parentReference, nextReference, context, hostNamespace);
125
+ _pushMountEnterFrame(nextElement, {
126
+ subtreeRightBoundary,
127
+ renderRuntime,
128
+ hostNamespace,
129
+ context,
130
+ parentReference,
131
+ placeHolderElement: null,
132
+ });
69
133
  return;
70
134
  }
71
- if (!forceRender && isMemo(nextElement.type) && nextElement.type._compare(prevElement.props, nextElement.props)) {
135
+ nextElement.store = prevElement.store;
136
+ nextElement.store.latestElement = nextElement;
137
+ if (hostNamespace) {
138
+ nextElement.store.hostNamespace = hostNamespace;
139
+ }
140
+ if (isMemo(nextElement.type) &&
141
+ !nextElement.store.forceRerender &&
142
+ nextElement.type._compare(prevElement.props, nextElement.props)) {
143
+ nextElement.childFlag = prevElement.childFlag;
144
+ nextElement.children = prevElement.children;
145
+ nextElement.context = prevElement.context;
72
146
  return;
73
147
  }
74
148
  nextElement.context = prevElement.context || context;
75
- // FC element always has Maybe<SimpElement> children due to normalization process.
149
+ const prevElementSnapshot = prevElement === nextElement ? { ...prevElement } : prevElement;
76
150
  let nextChildren;
77
151
  let triedToRerenderUnsubscribe;
78
152
  try {
153
+ renderRuntime.renderPhase = UPDATING_PHASE;
154
+ renderRuntime.currentRenderingFCElement = nextElement;
79
155
  let triedToRerender = false;
80
156
  let rerenderCounter = 0;
81
157
  triedToRerenderUnsubscribe = lifecycleEventBus.subscribe(event => {
@@ -88,220 +164,137 @@ function patchFunctionalComponent(prevElement, nextElement, parentReference, nex
88
164
  if (++rerenderCounter >= 25) {
89
165
  throw new Error('Too many re-renders.');
90
166
  }
91
- lifecycleEventBus.publish({ type: 'beforeRender', element: nextElement, phase: 'updating' });
92
- nextChildren = nextElement.type(nextElement.props || emptyObject);
93
- lifecycleEventBus.publish({ type: 'afterRender', element: nextElement, phase: 'updating' });
167
+ lifecycleEventBus.publish({
168
+ type: 'beforeRender',
169
+ element: nextElement,
170
+ renderRuntime,
171
+ });
172
+ nextChildren = renderRuntime.renderer(nextElement.type, nextElement, renderRuntime);
173
+ lifecycleEventBus.publish({
174
+ type: 'afterRender',
175
+ element: nextElement,
176
+ renderRuntime,
177
+ });
94
178
  } while (triedToRerender);
95
- nextChildren = normalizeRoot(nextChildren, false);
179
+ normalizeRoot(nextElement, nextChildren, false);
180
+ nextChildren = nextElement.children;
96
181
  }
97
182
  catch (error) {
98
- lifecycleEventBus.publish({ type: 'errored', element: nextElement, error, phase: 'updating' });
99
- remove(prevElement, parentReference);
183
+ const parentChildren = prevElement.parent?.children;
184
+ if (prevElement.parent?.childFlag === SIMP_ELEMENT_CHILD_FLAG_LIST) {
185
+ const parentChildrenList = parentChildren;
186
+ parentChildrenList.splice(prevElement.index, 1);
187
+ if (parentChildrenList.length === 1) {
188
+ prevElement.parent.children = parentChildrenList[0];
189
+ prevElement.parent.childFlag = SIMP_ELEMENT_CHILD_FLAG_ELEMENT;
190
+ }
191
+ else {
192
+ for (let i = prevElement.index; i < parentChildrenList.length; i++) {
193
+ parentChildrenList[i].index = i;
194
+ }
195
+ }
196
+ }
197
+ else if (prevElement.parent) {
198
+ prevElement.parent.childFlag = SIMP_ELEMENT_CHILD_FLAG_EMPTY;
199
+ prevElement.parent.children = null;
200
+ }
201
+ _clearElementHostReference(prevElement, parentReference, renderRuntime);
202
+ _pushUnmountEnterFrame(prevElement, frame.meta);
203
+ const event = {
204
+ type: 'errored',
205
+ element: nextElement,
206
+ error,
207
+ handled: false,
208
+ renderRuntime,
209
+ };
210
+ lifecycleEventBus.publish(event);
211
+ if (!event.handled) {
212
+ throw new Error('Error occurred during rendering a component', { cause: event.error });
213
+ }
100
214
  return;
101
215
  }
102
216
  finally {
103
217
  triedToRerenderUnsubscribe();
104
- }
105
- // Keep prevElement's children reference when prev and next elements are identical to avoid reassignment.
106
- const prevChildren = prevElement.children;
107
- if (nextChildren) {
108
- nextElement.children = nextChildren;
109
- }
110
- patchChildren(prevChildren, nextChildren, parentReference, nextReference, nextElement, nextElement.context, hostNamespace);
111
- lifecycleEventBus.publish({ type: 'updated', element: nextElement });
218
+ renderRuntime.renderPhase = null;
219
+ renderRuntime.currentRenderingFCElement = null;
220
+ }
221
+ _pushPatchExitFrame(nextElement, {
222
+ prevElement,
223
+ renderRuntime,
224
+ hostNamespace,
225
+ subtreeRightBoundary,
226
+ context,
227
+ parentReference,
228
+ });
229
+ _pushPatchChildrenFrame(nextElement, {
230
+ subtreeRightBoundary,
231
+ prevParentChildFlag: prevElementSnapshot.childFlag,
232
+ nextParentChildFlag: nextElement.childFlag,
233
+ prevChildren: prevElementSnapshot.children,
234
+ nextChildren: nextChildren,
235
+ renderRuntime,
236
+ hostNamespace,
237
+ parentReference,
238
+ context,
239
+ prevParentElement: prevElementSnapshot,
240
+ });
112
241
  }
113
- function patchTextElement(prevElement, nextElement) {
242
+ function _patchTextElement(frame) {
243
+ const nextElement = frame.node;
244
+ const { prevElement, renderRuntime } = frame.meta;
114
245
  nextElement.reference = prevElement.reference;
115
246
  if (nextElement.children !== prevElement.children) {
116
- hostAdapter.setTextContent(nextElement.reference, nextElement.children);
117
- }
118
- }
119
- function patchFragment(prevElement, nextElement, parentReference, context, hostNamespace) {
120
- let nextReference = null;
121
- if (Array.isArray(prevElement.children) && !Array.isArray(nextElement.children) && nextElement.children) {
122
- nextReference = hostAdapter.findNextSiblingReference(findHostReferenceFromElement(prevElement.children[prevElement.children.length - 1]));
247
+ renderRuntime.hostAdapter.setTextContent(nextElement.reference, nextElement.children);
123
248
  }
124
- patchChildren(prevElement.children, nextElement.children, parentReference, nextReference, nextElement, context, hostNamespace);
125
249
  }
126
- export function patchPortal(prevElement, nextElement, context) {
250
+ function _patchPortal(frame) {
251
+ const nextElement = frame.node;
252
+ const { prevElement, renderRuntime, context, subtreeRightBoundary, hostNamespace, parentReference } = frame.meta;
127
253
  const prevContainer = prevElement.ref;
128
254
  const nextContainer = nextElement.ref;
129
255
  const nextChildren = nextElement.children;
130
- patchChildren(prevElement.children, nextChildren, prevContainer, null, nextElement, context, hostAdapter.getHostNamespaces(nextChildren, undefined)?.self);
256
+ if (frame.kind === PATCH_EXIT) {
257
+ renderRuntime.hostAdapter.removeChild(prevContainer, nextChildren.reference);
258
+ renderRuntime.hostAdapter.insertOrAppend(nextContainer, nextChildren.reference, null);
259
+ return;
260
+ }
131
261
  nextElement.reference = prevElement.reference;
132
262
  if (prevContainer !== nextContainer && nextChildren != null) {
133
- hostAdapter.removeChild(prevContainer, nextChildren.reference);
134
- hostAdapter.appendChild(nextContainer, nextChildren.reference);
135
- }
136
- }
137
- export function updateFunctionalComponent(element, parentReference, nextReference, context, hostNamespace) {
138
- patchFunctionalComponent(element, element, parentReference, nextReference, context, hostNamespace);
139
- }
140
- function patchChildren(prevChildren, nextChildren, parentReference, nextReference, nextElement, context, hostNamespace) {
141
- if (Array.isArray(prevChildren)) {
142
- if (Array.isArray(nextChildren)) {
143
- for (const child of nextChildren) {
144
- child.parent = nextElement;
145
- }
146
- patchKeyedChildren(prevChildren, nextChildren, parentReference, nextReference, context, hostNamespace);
147
- }
148
- else if (typeof nextChildren === 'string') {
149
- unmount(prevChildren);
150
- hostAdapter.setTextContent(parentReference, nextChildren);
151
- }
152
- else if (nextChildren) {
153
- patchKeyedChildren(prevChildren, [nextChildren], parentReference, nextReference, context, hostNamespace);
154
- }
155
- else {
156
- unmount(prevChildren);
157
- hostAdapter.clearNode(parentReference);
158
- }
159
- }
160
- else if (typeof prevChildren === 'string') {
161
- if (Array.isArray(nextChildren)) {
162
- hostAdapter.clearNode(parentReference);
163
- mountArrayChildren(nextChildren, parentReference, nextReference, context, nextElement, hostNamespace);
164
- }
165
- else if (typeof nextChildren === 'string') {
166
- if (prevChildren !== nextChildren) {
167
- hostAdapter.setTextContent(nextElement.reference, nextChildren, true);
168
- }
169
- }
170
- else if (nextChildren) {
171
- hostAdapter.clearNode(parentReference);
172
- nextChildren.parent = nextElement;
173
- mount(nextChildren, parentReference, nextReference, context, hostNamespace);
174
- }
175
- else {
176
- hostAdapter.clearNode(parentReference);
177
- }
178
- }
179
- else if (prevChildren) {
180
- if (Array.isArray(nextChildren)) {
181
- patchKeyedChildren([prevChildren], nextChildren, parentReference, nextReference, context, hostNamespace);
182
- }
183
- else if (typeof nextChildren === 'string') {
184
- unmount(prevChildren);
185
- hostAdapter.setTextContent(parentReference, nextChildren);
186
- }
187
- else if (nextChildren) {
188
- nextChildren.parent = nextElement;
189
- patch(prevChildren, nextChildren, parentReference, nextReference, context, hostNamespace);
190
- }
191
- else {
192
- remove(prevChildren, parentReference);
193
- }
194
- }
195
- else {
196
- if (Array.isArray(nextChildren)) {
197
- mountArrayChildren(nextChildren, parentReference, nextReference, context, nextElement, hostNamespace);
198
- }
199
- else if (typeof nextChildren === 'string') {
200
- hostAdapter.setTextContent(parentReference, nextChildren);
201
- }
202
- else if (nextChildren) {
203
- nextChildren.parent = nextElement;
204
- mount(nextChildren, parentReference, nextReference, context, hostNamespace);
205
- }
206
- }
207
- }
208
- export function patchKeyedChildren(prevChildren, nextChildren, parentReference, nextReference, context, hostNamespace) {
209
- let prevStart = 0;
210
- let nextStart = 0;
211
- let prevEnd = prevChildren.length - 1;
212
- let nextEnd = nextChildren.length - 1;
213
- // Step 1: Sync from start
214
- while (prevStart <= prevEnd &&
215
- nextStart <= nextEnd &&
216
- prevChildren[prevStart].key === nextChildren[nextStart].key) {
217
- patch(prevChildren[prevStart], nextChildren[nextStart], parentReference, null, context, hostNamespace);
218
- prevStart++;
219
- nextStart++;
220
- }
221
- // Step 2: Sync from end
222
- while (prevStart <= prevEnd && nextStart <= nextEnd && prevChildren[prevEnd].key === nextChildren[nextEnd].key) {
223
- patch(prevChildren[prevEnd], nextChildren[nextEnd], parentReference, null, context, hostNamespace);
224
- prevEnd--;
225
- nextEnd--;
226
- }
227
- // Step 3: Mount new nodes if prev list is exhausted
228
- if (prevStart > prevEnd) {
229
- const before = findHostReferenceFromElement(nextChildren[nextEnd + 1]) || nextReference;
230
- for (let i = nextStart; i <= nextEnd; i++) {
231
- mount(nextChildren[i], parentReference, before, context, hostNamespace);
232
- }
233
- // Step 4: Remove prev nodes if next list is exhausted
234
- }
235
- else if (nextStart > nextEnd) {
236
- for (let i = prevStart; i <= prevEnd; i++) {
237
- remove(prevChildren[i], parentReference);
238
- }
239
- }
240
- // Step 5: Full diff with keyed lookup and movement
241
- else {
242
- // Create map of keys to indices for prev children
243
- const keyToPrevIndexMap = new Map();
244
- for (let i = prevStart; i <= prevEnd; i++) {
245
- const key = prevChildren[i].key;
246
- if (key != null) {
247
- keyToPrevIndexMap.set(key, i);
248
- }
249
- }
250
- // Track reused indices and move plan
251
- const toMove = new Array(nextEnd - nextStart + 1);
252
- const usedIndices = new Set();
253
- // Match and patch/mount
254
- for (let i = nextStart; i <= nextEnd; i++) {
255
- const nextChild = nextChildren[i];
256
- const prevIndex = keyToPrevIndexMap.get(nextChild.key);
257
- if (prevIndex != null) {
258
- const prevElement = prevChildren[prevIndex];
259
- patch(prevElement, nextChild, parentReference, null, context, hostNamespace);
260
- toMove[i - nextStart] = prevIndex;
261
- usedIndices.add(prevIndex);
262
- }
263
- else {
264
- mount(nextChild, parentReference, findHostReferenceFromElement(nextChildren[i + 1]) || nextReference, context, hostNamespace);
265
- toMove[i - nextStart] = -1;
266
- }
267
- }
268
- // Remove nodes not matched
269
- for (let i = prevStart; i <= prevEnd; i++) {
270
- if (!usedIndices.has(i)) {
271
- remove(prevChildren[i], parentReference);
272
- }
273
- }
274
- // Insert in correct order
275
- for (let i = nextEnd; i >= nextStart; i--) {
276
- const currentChild = nextChildren[i];
277
- const reference = findHostReferenceFromElement(nextChildren[i + 1]) || nextReference;
278
- if (toMove[i - nextStart] !== -1) {
279
- hostAdapter.insertBefore(parentReference, currentChild.reference, reference);
280
- }
281
- }
282
- }
283
- }
284
- export function findParentReferenceFromElement(element) {
285
- let flag;
286
- let temp = element;
287
- while (temp != null) {
288
- flag = temp.flag;
289
- if (flag === 'HOST') {
290
- return temp.reference;
291
- }
292
- temp = temp.parent;
263
+ _pushPatchExitFrame(nextElement, {
264
+ prevElement,
265
+ renderRuntime,
266
+ hostNamespace,
267
+ subtreeRightBoundary,
268
+ context,
269
+ parentReference,
270
+ });
293
271
  }
294
- return null;
272
+ _pushPatchChildrenFrame(nextElement, {
273
+ prevParentElement: prevElement,
274
+ context,
275
+ parentReference: nextContainer,
276
+ hostNamespace: renderRuntime.hostAdapter.getHostNamespaces(nextChildren, undefined)?.self,
277
+ renderRuntime,
278
+ prevChildren: prevElement.children,
279
+ nextChildren,
280
+ nextParentChildFlag: nextElement.childFlag,
281
+ prevParentChildFlag: prevElement.childFlag,
282
+ subtreeRightBoundary,
283
+ });
295
284
  }
296
- export function findHostReferenceFromElement(element) {
297
- let flag;
298
- let temp = element;
299
- while (temp != null) {
300
- flag = temp.flag;
301
- if (flag === 'HOST' || flag === 'TEXT' || flag === 'PORTAL') {
302
- return temp.reference;
303
- }
304
- temp = (Array.isArray(temp.children) ? temp.children[0] : temp.children);
305
- }
306
- return null;
285
+ function _patchFragment(frame) {
286
+ const nextElement = frame.node;
287
+ const { prevElement, renderRuntime, context, parentReference, hostNamespace, subtreeRightBoundary } = frame.meta;
288
+ _pushPatchChildrenFrame(nextElement, {
289
+ subtreeRightBoundary,
290
+ context,
291
+ parentReference,
292
+ prevParentChildFlag: prevElement.childFlag,
293
+ nextParentChildFlag: nextElement.childFlag,
294
+ nextChildren: nextElement.children,
295
+ prevChildren: prevElement.children,
296
+ renderRuntime,
297
+ hostNamespace,
298
+ prevParentElement: prevElement,
299
+ });
307
300
  }
@@ -0,0 +1,6 @@
1
+ import { type SimpElement } from './createElement.js';
2
+ import { type PatchChildrenFrame, type PatchChildrenFrameMeta } from './processStack.js';
3
+ export declare function _pushPatchChildrenFrame(parent: SimpElement, meta: PatchChildrenFrameMeta): void;
4
+ export declare function _pushPatchKeyedChildrenFrame(element: SimpElement, meta: PatchChildrenFrameMeta): void;
5
+ export declare function _patchChildren(frame: PatchChildrenFrame): void;
6
+ export declare function _patchKeyedChildren(frame: PatchChildrenFrame): void;