@simpreact/simpreact 0.0.8 → 0.0.9

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 (75) hide show
  1. package/compat/core.js +101 -15
  2. package/compat/hooks.js +15 -0
  3. package/compat/index.d.ts +10 -1
  4. package/compat/renderRuntime.js +47 -12
  5. package/component/index.js +96 -94
  6. package/context/index.js +27 -17
  7. package/core/createElement.js +14 -17
  8. package/core/flags.js +31 -0
  9. package/core/hostOperations.js +5 -13
  10. package/core/index.d.ts +38 -8
  11. package/core/index.js +3 -2
  12. package/core/internal.d.ts +136 -16
  13. package/core/internal.js +8 -16
  14. package/core/lifecycleEventBus.js +35 -16
  15. package/core/memo.js +4 -1
  16. package/core/mounting.js +70 -150
  17. package/core/mountingChildren.js +11 -29
  18. package/core/patching.js +122 -181
  19. package/core/patchingChildren.js +74 -145
  20. package/core/portal.js +1 -1
  21. package/core/processStack.js +115 -45
  22. package/core/ref.js +1 -0
  23. package/core/rerender.js +20 -22
  24. package/core/runtime.js +10 -2
  25. package/core/unmounting.js +41 -49
  26. package/core/unmountingChildren.js +9 -12
  27. package/core/utils.js +38 -16
  28. package/dom/attach-element-to-dom.js +16 -8
  29. package/dom/events.js +11 -15
  30. package/dom/index.d.ts +2 -0
  31. package/dom/props/attrMaps.js +90 -0
  32. package/dom/props/controlled/select.js +8 -10
  33. package/dom/props/props.js +13 -14
  34. package/hooks/index.d.ts +3 -0
  35. package/hooks/index.js +107 -84
  36. package/package.json +10 -5
  37. package/compat/context.d.ts +0 -7
  38. package/compat/core.d.ts +0 -48
  39. package/compat/dom.d.ts +0 -10
  40. package/compat/hooks.d.ts +0 -26
  41. package/compat/jsx-runtime.d.ts +0 -10
  42. package/compat/renderRuntime.d.ts +0 -6
  43. package/core/createElement.d.ts +0 -39
  44. package/core/fragment.d.ts +0 -5
  45. package/core/hostAdapter.d.ts +0 -23
  46. package/core/hostOperations.d.ts +0 -5
  47. package/core/lifecycleEventBus.d.ts +0 -39
  48. package/core/memo.d.ts +0 -8
  49. package/core/mounting.d.ts +0 -7
  50. package/core/mountingChildren.d.ts +0 -4
  51. package/core/patching.d.ts +0 -8
  52. package/core/patchingChildren.d.ts +0 -6
  53. package/core/portal.d.ts +0 -2
  54. package/core/processStack.d.ts +0 -106
  55. package/core/ref.d.ts +0 -18
  56. package/core/rerender.d.ts +0 -4
  57. package/core/runtime.d.ts +0 -17
  58. package/core/unmounting.d.ts +0 -7
  59. package/core/unmountingChildren.d.ts +0 -4
  60. package/core/utils.d.ts +0 -11
  61. package/dom/attach-element-to-dom.d.ts +0 -5
  62. package/dom/domAdapter.d.ts +0 -3
  63. package/dom/events.d.ts +0 -27
  64. package/dom/namespace.d.ts +0 -2
  65. package/dom/props/controlled/index.d.ts +0 -7
  66. package/dom/props/controlled/input.d.ts +0 -7
  67. package/dom/props/controlled/select.d.ts +0 -6
  68. package/dom/props/controlled/textarea.d.ts +0 -6
  69. package/dom/props/dangerInnerHTML.d.ts +0 -7
  70. package/dom/props/index.d.ts +0 -1
  71. package/dom/props/props.d.ts +0 -5
  72. package/dom/props/style.d.ts +0 -1
  73. package/dom/render.d.ts +0 -8
  74. package/shared/lang.d.ts +0 -3
  75. package/shared/utils.d.ts +0 -5
package/core/patching.js CHANGED
@@ -1,107 +1,63 @@
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';
3
- import { lifecycleEventBus } from './lifecycleEventBus.js';
1
+ import { noop } from '../shared/index.js';
2
+ import { normalizeRoot, SIMP_ELEMENT_CHILD_FLAG_LIST, SIMP_ELEMENT_FLAG_HOST, } from './createElement.js';
3
+ import { pushHostOperationReplaceElement } from './hostOperations.js';
4
+ import { getLifecycleEventBus } from './lifecycleEventBus.js';
4
5
  import { isMemo } from './memo.js';
5
- import { _pushMountEnterFrame } from './mounting.js';
6
- import { _pushPatchChildrenFrame } from './patchingChildren.js';
7
- import { PATCH_ENTER, PATCH_EXIT, processStack } from './processStack.js';
6
+ import { pushMountEnterFrame } from './mounting.js';
7
+ import { patchChildren } from './patchingChildren.js';
8
+ import { acquirePatchFrame, PATCH_ENTER, PATCH_EXIT, processStack } from './processStack.js';
8
9
  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];
10
+ import { pushUnmountEnterFrame } from './unmounting.js';
11
+ import { bitScanForwardIndex, clearElementHostReference, detachElementFromParent } from './utils.js';
12
+ const patchEnterHandlers = [patchHostEnter, patchFCEnter, patchTextElement, patchPortalEnter, patchFragment];
13
+ const patchExitHandlers = [patchHostExit, patchFCExit, noop, patchPortalExit, noop];
13
14
  export function patch(prevElement, nextElement, parentReference, subtreeRightBoundary, context, hostNamespace, renderRuntime) {
14
15
  if (renderRuntime.renderStack.length !== 0) {
15
16
  throw new Error('Cannot patch while rendering.');
16
17
  }
17
- _pushPatchEnterFrame(nextElement, {
18
- prevElement,
19
- parentReference,
20
- renderRuntime,
21
- subtreeRightBoundary,
22
- context,
23
- hostNamespace,
24
- });
18
+ pushPatchEnterFrame(nextElement, renderRuntime, prevElement, parentReference, subtreeRightBoundary, context, hostNamespace);
25
19
  processStack(renderRuntime);
26
20
  }
27
- export function _pushPatchEnterFrame(element, meta) {
28
- meta.renderRuntime.renderStack.push({
29
- node: element,
30
- kind: PATCH_ENTER,
31
- meta,
32
- });
21
+ export function pushPatchEnterFrame(element, renderRuntime, prevElement, parentReference, subtreeRightBoundary, context, hostNamespace) {
22
+ renderRuntime.renderStack.push(acquirePatchFrame(renderRuntime, element, PATCH_ENTER, prevElement, parentReference, subtreeRightBoundary, context, hostNamespace));
33
23
  }
34
- export function _pushPatchExitFrame(element, meta) {
35
- meta.renderRuntime.renderStack.push({
36
- node: element,
37
- kind: PATCH_EXIT,
38
- meta,
39
- });
24
+ function pushPatchExitFrame(element, renderRuntime, prevElement, parentReference, subtreeRightBoundary, context, hostNamespace) {
25
+ renderRuntime.renderStack.push(acquirePatchFrame(renderRuntime, element, PATCH_EXIT, prevElement, parentReference, subtreeRightBoundary, context, hostNamespace));
40
26
  }
41
- export function _patch(frame) {
42
- const nextElement = frame.node;
43
- const { prevElement } = frame.meta;
27
+ export function patchEnter(frame) {
28
+ const { prevElement } = frame;
44
29
  // Early return if the elements are different type or have different keys.
45
- if (prevElement.type !== nextElement.type || prevElement.key !== nextElement.key) {
46
- _replaceWithNewElement(frame);
30
+ if (prevElement.type !== frame.node.type || prevElement.key !== frame.node.key) {
31
+ replaceWithNewElement(frame);
47
32
  return;
48
33
  }
49
- patchHandlers[bitScanForwardIndex(frame.node.flag)](frame);
34
+ patchEnterHandlers[bitScanForwardIndex(frame.node.flag)](frame);
35
+ }
36
+ export function patchExit(frame) {
37
+ patchExitHandlers[bitScanForwardIndex(frame.node.flag)](frame);
50
38
  }
51
- function _replaceWithNewElement(frame) {
39
+ function replaceWithNewElement(frame) {
52
40
  const nextElement = frame.node;
53
- const { prevElement, parentReference, context, hostNamespace, renderRuntime } = frame.meta;
54
- _pushUnmountEnterFrame(prevElement, frame.meta);
41
+ const { prevElement, parentReference, context, hostNamespace, renderRuntime } = frame;
42
+ pushUnmountEnterFrame(prevElement, renderRuntime);
55
43
  nextElement.parent = prevElement.parent;
56
44
  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
- });
45
+ pushHostOperationReplaceElement(nextElement, renderRuntime, parentReference, prevElement);
46
+ pushMountEnterFrame(nextElement, renderRuntime, null, null, context, hostNamespace, null);
69
47
  }
70
48
  else {
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
- });
49
+ clearElementHostReference(prevElement, parentReference, renderRuntime);
50
+ pushMountEnterFrame(nextElement, renderRuntime, parentReference, frame.subtreeRightBoundary, context, hostNamespace, null);
80
51
  }
81
52
  }
82
- function _patchHostElement(frame) {
53
+ function patchHostEnter(frame) {
83
54
  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;
92
- }
55
+ const { prevElement, context, hostNamespace, renderRuntime, subtreeRightBoundary, parentReference } = frame;
93
56
  nextElement.ref = prevElement.ref;
94
57
  nextElement.reference = prevElement.reference;
95
58
  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, {
59
+ pushPatchExitFrame(nextElement, renderRuntime, prevElement, parentReference, subtreeRightBoundary, context, hostNamespace);
60
+ patchChildren(nextElement, {
105
61
  prevParentElement: prevElement,
106
62
  nextChildren: nextElement.children,
107
63
  prevChildren: prevElement.children,
@@ -114,162 +70,140 @@ function _patchHostElement(frame) {
114
70
  renderRuntime,
115
71
  });
116
72
  }
117
- function _patchFunctionalComponent(frame) {
73
+ function patchHostExit(frame) {
118
74
  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;
75
+ const { prevElement, renderRuntime, hostNamespace } = frame;
76
+ renderRuntime.hostAdapter.patchProps(nextElement.reference, prevElement, nextElement, renderRuntime, hostNamespace);
77
+ if (prevElement.className !== nextElement.className) {
78
+ renderRuntime.hostAdapter.setClassname(nextElement.reference, nextElement.className, hostNamespace);
123
79
  }
80
+ applyRef(nextElement);
81
+ }
82
+ function patchFCEnter(frame) {
83
+ const { prevElement, context, renderRuntime, hostNamespace, subtreeRightBoundary, parentReference } = frame;
84
+ const jsxElement = frame.node;
124
85
  if (prevElement.unmounted) {
125
- _pushMountEnterFrame(nextElement, {
126
- subtreeRightBoundary,
127
- renderRuntime,
128
- hostNamespace,
129
- context,
130
- parentReference,
131
- placeHolderElement: null,
132
- });
86
+ pushMountEnterFrame(jsxElement, renderRuntime, parentReference, subtreeRightBoundary, context, hostNamespace, null);
133
87
  return;
134
88
  }
135
- nextElement.store = prevElement.store;
136
- nextElement.store.latestElement = nextElement;
137
89
  if (hostNamespace) {
138
- nextElement.store.hostNamespace = hostNamespace;
90
+ prevElement.hostNamespace = hostNamespace;
91
+ }
92
+ // Replace the short-lived JSX element in the parent's children with the long-lived prevElement.
93
+ if (jsxElement !== prevElement) {
94
+ swapChildInParent(jsxElement, prevElement);
139
95
  }
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;
96
+ // Memo check: compare old props against new props.
97
+ // Self-rerenders (jsxElement === prevElement) always proceed — state may have changed.
98
+ const prevProps = prevElement.props;
99
+ if (jsxElement !== prevElement &&
100
+ isMemo(prevElement.type) &&
101
+ prevElement.type._compare(prevProps, jsxElement.props)) {
146
102
  return;
147
103
  }
148
- nextElement.context = prevElement.context || context;
149
- const prevElementSnapshot = prevElement === nextElement ? { ...prevElement } : prevElement;
104
+ prevElement.props = jsxElement.props;
105
+ prevElement.context = prevElement.context || context;
106
+ const prevChildFlag = prevElement.childFlag;
107
+ const prevChildren = prevElement.children;
108
+ const prevSnapshot = { childFlag: prevChildFlag, children: prevChildren };
150
109
  let nextChildren;
151
- let triedToRerenderUnsubscribe;
152
110
  try {
153
- renderRuntime.renderPhase = UPDATING_PHASE;
154
- renderRuntime.currentRenderingFCElement = nextElement;
155
- let triedToRerender = false;
156
111
  let rerenderCounter = 0;
157
- triedToRerenderUnsubscribe = lifecycleEventBus.subscribe(event => {
158
- if (event.type === 'triedToRerender' && event.element === nextElement) {
159
- triedToRerender = true;
160
- }
161
- });
112
+ renderRuntime.activeRenderElement = prevElement;
113
+ renderRuntime.pendingRerenderFlag = false;
162
114
  do {
163
- triedToRerender = false;
115
+ renderRuntime.pendingRerenderFlag = false;
164
116
  if (++rerenderCounter >= 25) {
165
117
  throw new Error('Too many re-renders.');
166
118
  }
167
- lifecycleEventBus.publish({
119
+ getLifecycleEventBus(renderRuntime).publish({
168
120
  type: 'beforeRender',
169
- element: nextElement,
121
+ element: prevElement,
170
122
  renderRuntime,
171
123
  });
172
- nextChildren = renderRuntime.renderer(nextElement.type, nextElement, renderRuntime);
173
- lifecycleEventBus.publish({
124
+ nextChildren = renderRuntime.renderer(prevElement.type, prevElement, renderRuntime);
125
+ getLifecycleEventBus(renderRuntime).publish({
174
126
  type: 'afterRender',
175
- element: nextElement,
127
+ element: prevElement,
176
128
  renderRuntime,
177
129
  });
178
- } while (triedToRerender);
179
- normalizeRoot(nextElement, nextChildren, false);
180
- nextChildren = nextElement.children;
130
+ } while (renderRuntime.pendingRerenderFlag);
131
+ normalizeRoot(prevElement, nextChildren, false);
132
+ nextChildren = prevElement.children;
181
133
  }
182
134
  catch (error) {
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);
135
+ detachElementFromParent(prevElement);
136
+ clearElementHostReference(prevElement, parentReference, renderRuntime);
137
+ pushUnmountEnterFrame(prevElement, renderRuntime);
203
138
  const event = {
204
139
  type: 'errored',
205
- element: nextElement,
140
+ element: prevElement,
206
141
  error,
207
142
  handled: false,
208
143
  renderRuntime,
209
144
  };
210
- lifecycleEventBus.publish(event);
145
+ getLifecycleEventBus(renderRuntime).publish(event);
211
146
  if (!event.handled) {
212
147
  throw new Error('Error occurred during rendering a component', { cause: event.error });
213
148
  }
214
149
  return;
215
150
  }
216
151
  finally {
217
- triedToRerenderUnsubscribe();
218
- renderRuntime.renderPhase = null;
219
- renderRuntime.currentRenderingFCElement = null;
152
+ renderRuntime.activeRenderElement = null;
220
153
  }
221
- _pushPatchExitFrame(nextElement, {
222
- prevElement,
223
- renderRuntime,
224
- hostNamespace,
154
+ pushPatchExitFrame(prevElement, renderRuntime, prevElement, parentReference, subtreeRightBoundary, context, hostNamespace);
155
+ patchChildren(prevElement, {
225
156
  subtreeRightBoundary,
226
- context,
227
- parentReference,
228
- });
229
- _pushPatchChildrenFrame(nextElement, {
230
- subtreeRightBoundary,
231
- prevParentChildFlag: prevElementSnapshot.childFlag,
232
- nextParentChildFlag: nextElement.childFlag,
233
- prevChildren: prevElementSnapshot.children,
157
+ prevParentChildFlag: prevChildFlag,
158
+ nextParentChildFlag: prevElement.childFlag,
159
+ prevChildren: prevChildren,
234
160
  nextChildren: nextChildren,
235
161
  renderRuntime,
236
162
  hostNamespace,
237
163
  parentReference,
238
- context,
239
- prevParentElement: prevElementSnapshot,
164
+ context: prevElement.context || context,
165
+ prevParentElement: prevSnapshot,
240
166
  });
241
167
  }
242
- function _patchTextElement(frame) {
168
+ function patchFCExit(frame) {
169
+ getLifecycleEventBus(frame.renderRuntime).publish({
170
+ type: 'updated',
171
+ element: frame.node,
172
+ renderRuntime: frame.renderRuntime,
173
+ });
174
+ }
175
+ function swapChildInParent(jsxElement, liveElement) {
176
+ const parent = jsxElement.parent;
177
+ if (!parent)
178
+ return;
179
+ liveElement.parent = parent;
180
+ liveElement.index = jsxElement.index;
181
+ if (parent.childFlag === SIMP_ELEMENT_CHILD_FLAG_LIST) {
182
+ parent.children[jsxElement.index] = liveElement;
183
+ }
184
+ else {
185
+ parent.children = liveElement;
186
+ }
187
+ }
188
+ function patchTextElement(frame) {
243
189
  const nextElement = frame.node;
244
- const { prevElement, renderRuntime } = frame.meta;
190
+ const { prevElement, renderRuntime } = frame;
245
191
  nextElement.reference = prevElement.reference;
246
192
  if (nextElement.children !== prevElement.children) {
247
193
  renderRuntime.hostAdapter.setTextContent(nextElement.reference, nextElement.children);
248
194
  }
249
195
  }
250
- function _patchPortal(frame) {
196
+ function patchPortalEnter(frame) {
251
197
  const nextElement = frame.node;
252
- const { prevElement, renderRuntime, context, subtreeRightBoundary, hostNamespace, parentReference } = frame.meta;
198
+ const { prevElement, renderRuntime, context, subtreeRightBoundary, hostNamespace, parentReference } = frame;
253
199
  const prevContainer = prevElement.ref;
254
200
  const nextContainer = nextElement.ref;
255
201
  const nextChildren = nextElement.children;
256
- if (frame.kind === PATCH_EXIT) {
257
- renderRuntime.hostAdapter.removeChild(prevContainer, nextChildren.reference);
258
- renderRuntime.hostAdapter.insertOrAppend(nextContainer, nextChildren.reference, null);
259
- return;
260
- }
261
202
  nextElement.reference = prevElement.reference;
262
203
  if (prevContainer !== nextContainer && nextChildren != null) {
263
- _pushPatchExitFrame(nextElement, {
264
- prevElement,
265
- renderRuntime,
266
- hostNamespace,
267
- subtreeRightBoundary,
268
- context,
269
- parentReference,
270
- });
204
+ pushPatchExitFrame(nextElement, renderRuntime, prevElement, parentReference, subtreeRightBoundary, context, hostNamespace);
271
205
  }
272
- _pushPatchChildrenFrame(nextElement, {
206
+ patchChildren(nextElement, {
273
207
  prevParentElement: prevElement,
274
208
  context,
275
209
  parentReference: nextContainer,
@@ -282,10 +216,17 @@ function _patchPortal(frame) {
282
216
  subtreeRightBoundary,
283
217
  });
284
218
  }
285
- function _patchFragment(frame) {
219
+ function patchPortalExit(frame) {
220
+ const nextElement = frame.node;
221
+ const { prevElement, renderRuntime } = frame;
222
+ const nextChildren = nextElement.children;
223
+ renderRuntime.hostAdapter.removeChild(prevElement.ref, nextChildren.reference);
224
+ renderRuntime.hostAdapter.insertOrAppend(nextElement.ref, nextChildren.reference, null);
225
+ }
226
+ function patchFragment(frame) {
286
227
  const nextElement = frame.node;
287
- const { prevElement, renderRuntime, context, parentReference, hostNamespace, subtreeRightBoundary } = frame.meta;
288
- _pushPatchChildrenFrame(nextElement, {
228
+ const { prevElement, renderRuntime, context, parentReference, hostNamespace, subtreeRightBoundary } = frame;
229
+ patchChildren(nextElement, {
289
230
  subtreeRightBoundary,
290
231
  context,
291
232
  parentReference,