@simpreact/simpreact 0.0.3 → 0.0.4

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.
package/core/patching.js CHANGED
@@ -1,50 +1,45 @@
1
- import { emptyMap, emptyObject } from '../shared/index.js';
1
+ import { emptyObject } from '../shared/index.js';
2
2
  import { normalizeRoot } from './createElement.js';
3
3
  import { hostAdapter } from './hostAdapter.js';
4
4
  import { clearElementHostReference, remove, unmount } from './unmounting.js';
5
- import { mount, mountArrayChildren } from './mounting.js';
5
+ import { mount, mountArrayChildren, mountFunctionalElement } from './mounting.js';
6
6
  import { applyRef } from './ref.js';
7
7
  import { lifecycleEventBus } from './lifecycleEventBus.js';
8
8
  import { batchingRerenderLocker } from './rerender.js';
9
- export function patch(prevElement, nextElement, parentReference, nextReference, contextMap, hostNamespace) {
9
+ import { isMemo } from './memo.js';
10
+ export function patch(prevElement, nextElement, parentReference, nextReference, context, hostNamespace) {
10
11
  if (prevElement.type !== nextElement.type || prevElement.key !== nextElement.key) {
11
- replaceWithNewElement(prevElement, nextElement, parentReference, contextMap, hostNamespace);
12
+ replaceWithNewElement(prevElement, nextElement, parentReference, context, hostNamespace);
12
13
  }
13
14
  else if (nextElement.flag === 'HOST') {
14
- patchHostElement(prevElement, nextElement, contextMap, hostNamespace);
15
+ patchHostElement(prevElement, nextElement, context, hostNamespace);
15
16
  }
16
17
  else if (nextElement.flag === 'FC') {
17
- patchFunctionalComponent(prevElement, nextElement, parentReference, nextReference, contextMap, hostNamespace);
18
+ patchFunctionalComponent(prevElement, nextElement, parentReference, nextReference, context, hostNamespace);
18
19
  }
19
20
  else if (nextElement.flag === 'TEXT') {
20
21
  patchTextElement(prevElement, nextElement);
21
22
  }
22
23
  else if (nextElement.flag === 'FRAGMENT') {
23
- patchFragment(prevElement, nextElement, parentReference, contextMap, hostNamespace);
24
- }
25
- else if (nextElement.flag === 'PROVIDER') {
26
- patchProvider(prevElement, nextElement, parentReference, contextMap, hostNamespace);
27
- }
28
- else if (nextElement.flag === 'PORTAL') {
29
- patchPortal(prevElement, nextElement, contextMap);
24
+ patchFragment(prevElement, nextElement, parentReference, context, hostNamespace);
30
25
  }
31
26
  else {
32
- patchConsumer(prevElement, nextElement, parentReference, nextReference, contextMap, hostNamespace);
27
+ patchPortal(prevElement, nextElement, context);
33
28
  }
34
29
  }
35
- function replaceWithNewElement(prevElement, nextElement, parentReference, contextMap, hostNamespace) {
30
+ function replaceWithNewElement(prevElement, nextElement, parentReference, context, hostNamespace) {
36
31
  unmount(prevElement);
37
32
  nextElement.parent = prevElement.parent;
38
33
  if (nextElement.flag === 'HOST' && prevElement.flag === 'HOST') {
39
- mount(nextElement, null, null, contextMap, hostNamespace);
34
+ mount(nextElement, null, null, context, hostNamespace);
40
35
  hostAdapter.replaceChild(parentReference, nextElement.reference, prevElement.reference);
41
36
  }
42
37
  else {
43
- mount(nextElement, parentReference, findHostReferenceFromElement(prevElement), contextMap, hostNamespace);
38
+ mount(nextElement, parentReference, findHostReferenceFromElement(prevElement), context, hostNamespace);
44
39
  clearElementHostReference(prevElement, parentReference);
45
40
  }
46
41
  }
47
- function patchHostElement(prevElement, nextElement, contextMap, hostNamespace) {
42
+ function patchHostElement(prevElement, nextElement, context, hostNamespace) {
48
43
  if (prevElement.ref) {
49
44
  nextElement.ref = prevElement.ref;
50
45
  }
@@ -52,25 +47,32 @@ function patchHostElement(prevElement, nextElement, contextMap, hostNamespace) {
52
47
  hostNamespace = hostNamespaces?.self;
53
48
  nextElement.reference = prevElement.reference;
54
49
  hostAdapter.attachElementToReference(nextElement, nextElement.reference);
55
- patchChildren(prevElement.children || prevElement.props?.children, nextElement.children || nextElement.props?.children, nextElement.reference, null, nextElement, contextMap, hostNamespaces?.children);
50
+ patchChildren(prevElement.children || prevElement.props?.children, nextElement.children || nextElement.props?.children, nextElement.reference, null, nextElement, context, hostNamespaces?.children);
56
51
  hostAdapter.patchProps(nextElement.reference, prevElement, nextElement, hostNamespace);
57
52
  if (prevElement.className !== nextElement.className) {
58
53
  hostAdapter.setClassname(nextElement.reference, nextElement.className, hostNamespace);
59
54
  }
60
55
  applyRef(nextElement);
61
56
  }
62
- function patchFunctionalComponent(prevElement, nextElement, parentReference, nextReference, contextMap, hostNamespace) {
63
- const prevStore = !prevElement.store || prevElement.unmounted
64
- ? { hostNamespace: prevElement.store?.hostNamespace }
65
- : prevElement.store;
66
- prevStore.latestElement = nextElement;
67
- nextElement.store = prevStore;
57
+ function patchFunctionalComponent(prevElement, nextElement, parentReference, nextReference, context, hostNamespace) {
58
+ nextElement.store = prevElement.store || {};
59
+ nextElement.store.latestElement = nextElement;
68
60
  if (hostNamespace) {
69
61
  nextElement.store.hostNamespace = hostNamespace;
70
62
  }
71
- if (contextMap) {
72
- nextElement.contextMap = contextMap;
63
+ let forceRender = false;
64
+ if (prevElement.store?.forceRender) {
65
+ forceRender = true;
66
+ prevElement.store.forceRender = false;
73
67
  }
68
+ if (prevElement.unmounted) {
69
+ mountFunctionalElement(nextElement, parentReference, nextReference, context, hostNamespace);
70
+ return;
71
+ }
72
+ if (!forceRender && isMemo(nextElement.type) && nextElement.type._compare(prevElement.props, nextElement.props)) {
73
+ return;
74
+ }
75
+ nextElement.context = prevElement.context || context;
74
76
  // FC element always has Maybe<SimpElement> children due to normalization process.
75
77
  let nextChildren;
76
78
  let triedToRerenderUnsubscribe;
@@ -85,13 +87,7 @@ function patchFunctionalComponent(prevElement, nextElement, parentReference, nex
85
87
  do {
86
88
  triedToRerender = false;
87
89
  if (++rerenderCounter >= 25) {
88
- lifecycleEventBus.publish({
89
- type: 'errored',
90
- element: nextElement,
91
- error: new Error('Too many re-renders. SimpReact limits the number of renders to prevent an infinite loop.'),
92
- phase: 'updating',
93
- });
94
- return;
90
+ throw new Error('Too many re-renders.');
95
91
  }
96
92
  lifecycleEventBus.publish({ type: 'beforeRender', element: nextElement, phase: 'updating' });
97
93
  batchingRerenderLocker.lock();
@@ -103,26 +99,19 @@ function patchFunctionalComponent(prevElement, nextElement, parentReference, nex
103
99
  }
104
100
  catch (error) {
105
101
  lifecycleEventBus.publish({ type: 'errored', element: nextElement, error, phase: 'updating' });
102
+ remove(prevElement, parentReference);
106
103
  return;
107
104
  }
108
105
  finally {
109
106
  triedToRerenderUnsubscribe();
110
107
  }
108
+ // Keep prevElement's children reference when prev and next elements are identical to avoid reassignment.
111
109
  const prevChildren = prevElement.children;
112
110
  if (nextChildren) {
113
111
  nextElement.children = nextChildren;
114
112
  }
115
- if (!prevElement.unmounted) {
116
- patchChildren(prevChildren, nextChildren, parentReference, nextReference, nextElement, contextMap, hostNamespace);
117
- lifecycleEventBus.publish({ type: 'updated', element: nextElement });
118
- return;
119
- }
120
- prevElement.unmounted = false;
121
- if (nextChildren) {
122
- nextChildren.parent = nextElement;
123
- mount(nextChildren, parentReference, nextReference, contextMap, hostNamespace);
124
- }
125
- lifecycleEventBus.publish({ type: 'mounted', element: nextElement });
113
+ patchChildren(prevChildren, nextChildren, parentReference, nextReference, nextElement, nextElement.context, hostNamespace);
114
+ lifecycleEventBus.publish({ type: 'updated', element: nextElement });
126
115
  }
127
116
  function patchTextElement(prevElement, nextElement) {
128
117
  nextElement.reference = prevElement.reference;
@@ -130,57 +119,41 @@ function patchTextElement(prevElement, nextElement) {
130
119
  hostAdapter.setTextContent(nextElement.reference, nextElement.children);
131
120
  }
132
121
  }
133
- function patchFragment(prevElement, nextElement, parentReference, contextMap, hostNamespace) {
134
- let nextReference = null;
135
- if (Array.isArray(prevElement.children) && !Array.isArray(nextElement.children) && nextElement.children) {
136
- nextReference = hostAdapter.findNextSiblingReference(findHostReferenceFromElement(prevElement.children[prevElement.children.length - 1]));
137
- }
138
- patchChildren(prevElement.children, nextElement.children, parentReference, nextReference, nextElement, contextMap, hostNamespace);
139
- }
140
- function patchProvider(prevElement, nextElement, parentReference, contextMap, hostNamespace) {
122
+ function patchFragment(prevElement, nextElement, parentReference, context, hostNamespace) {
141
123
  let nextReference = null;
142
124
  if (Array.isArray(prevElement.children) && !Array.isArray(nextElement.children) && nextElement.children) {
143
125
  nextReference = hostAdapter.findNextSiblingReference(findHostReferenceFromElement(prevElement.children[prevElement.children.length - 1]));
144
126
  }
145
- contextMap = new Map(contextMap);
146
- contextMap.set(nextElement.type.context, nextElement.props.value);
147
- patchChildren(prevElement.children, nextElement.children, parentReference, nextReference, nextElement, contextMap, hostNamespace);
148
- }
149
- function patchConsumer(prevElement, nextElement, parentReference, nextReference, contextMap, hostNamespace) {
150
- const children = normalizeRoot(nextElement.type(nextElement.props || emptyObject, contextMap || emptyMap), false);
151
- if (children) {
152
- nextElement.children = children;
153
- }
154
- patchChildren(prevElement.children, nextElement.children, parentReference, nextReference, nextElement, contextMap, hostNamespace);
127
+ patchChildren(prevElement.children, nextElement.children, parentReference, nextReference, nextElement, context, hostNamespace);
155
128
  }
156
- export function patchPortal(prevElement, nextElement, contextMap) {
129
+ export function patchPortal(prevElement, nextElement, context) {
157
130
  const prevContainer = prevElement.ref;
158
131
  const nextContainer = nextElement.ref;
159
132
  const nextChildren = nextElement.children;
160
- patchChildren(prevElement.children, nextChildren, prevContainer, null, nextElement, contextMap, hostAdapter.getHostNamespaces(nextChildren, undefined)?.self);
133
+ patchChildren(prevElement.children, nextChildren, prevContainer, null, nextElement, context, hostAdapter.getHostNamespaces(nextChildren, undefined)?.self);
161
134
  nextElement.reference = prevElement.reference;
162
135
  if (prevContainer !== nextContainer && nextChildren != null) {
163
136
  hostAdapter.removeChild(prevContainer, nextChildren.reference);
164
137
  hostAdapter.appendChild(nextContainer, nextChildren.reference);
165
138
  }
166
139
  }
167
- export function updateFunctionalComponent(element, parentReference, nextReference, contextMap, hostNamespace) {
168
- patchFunctionalComponent(element, element, parentReference, nextReference, contextMap, hostNamespace);
140
+ export function updateFunctionalComponent(element, parentReference, nextReference, context, hostNamespace) {
141
+ patchFunctionalComponent(element, element, parentReference, nextReference, context, hostNamespace);
169
142
  }
170
- function patchChildren(prevChildren, nextChildren, parentReference, nextReference, nextElement, contextMap, hostNamespace) {
143
+ function patchChildren(prevChildren, nextChildren, parentReference, nextReference, nextElement, context, hostNamespace) {
171
144
  if (Array.isArray(prevChildren)) {
172
145
  if (Array.isArray(nextChildren)) {
173
146
  for (const child of nextChildren) {
174
147
  child.parent = nextElement;
175
148
  }
176
- patchKeyedChildren(prevChildren, nextChildren, parentReference, nextReference, contextMap, hostNamespace);
149
+ patchKeyedChildren(prevChildren, nextChildren, parentReference, nextReference, context, hostNamespace);
177
150
  }
178
151
  else if (typeof nextChildren === 'string') {
179
152
  unmount(prevChildren);
180
153
  hostAdapter.setTextContent(parentReference, nextChildren);
181
154
  }
182
155
  else if (nextChildren) {
183
- patchKeyedChildren(prevChildren, [nextChildren], parentReference, nextReference, contextMap, hostNamespace);
156
+ patchKeyedChildren(prevChildren, [nextChildren], parentReference, nextReference, context, hostNamespace);
184
157
  }
185
158
  else {
186
159
  unmount(prevChildren);
@@ -190,7 +163,7 @@ function patchChildren(prevChildren, nextChildren, parentReference, nextReferenc
190
163
  else if (typeof prevChildren === 'string') {
191
164
  if (Array.isArray(nextChildren)) {
192
165
  hostAdapter.clearNode(parentReference);
193
- mountArrayChildren(nextChildren, parentReference, nextReference, contextMap, nextElement, hostNamespace);
166
+ mountArrayChildren(nextChildren, parentReference, nextReference, context, nextElement, hostNamespace);
194
167
  }
195
168
  else if (typeof nextChildren === 'string') {
196
169
  if (prevChildren !== nextChildren) {
@@ -200,7 +173,7 @@ function patchChildren(prevChildren, nextChildren, parentReference, nextReferenc
200
173
  else if (nextChildren) {
201
174
  hostAdapter.clearNode(parentReference);
202
175
  nextChildren.parent = nextElement;
203
- mount(nextChildren, parentReference, nextReference, contextMap, hostNamespace);
176
+ mount(nextChildren, parentReference, nextReference, context, hostNamespace);
204
177
  }
205
178
  else {
206
179
  hostAdapter.clearNode(parentReference);
@@ -208,7 +181,7 @@ function patchChildren(prevChildren, nextChildren, parentReference, nextReferenc
208
181
  }
209
182
  else if (prevChildren) {
210
183
  if (Array.isArray(nextChildren)) {
211
- patchKeyedChildren([prevChildren], nextChildren, parentReference, nextReference, contextMap, hostNamespace);
184
+ patchKeyedChildren([prevChildren], nextChildren, parentReference, nextReference, context, hostNamespace);
212
185
  }
213
186
  else if (typeof nextChildren === 'string') {
214
187
  unmount(prevChildren);
@@ -216,7 +189,7 @@ function patchChildren(prevChildren, nextChildren, parentReference, nextReferenc
216
189
  }
217
190
  else if (nextChildren) {
218
191
  nextChildren.parent = nextElement;
219
- patch(prevChildren, nextChildren, parentReference, nextReference, contextMap, hostNamespace);
192
+ patch(prevChildren, nextChildren, parentReference, nextReference, context, hostNamespace);
220
193
  }
221
194
  else {
222
195
  remove(prevChildren, parentReference);
@@ -224,18 +197,18 @@ function patchChildren(prevChildren, nextChildren, parentReference, nextReferenc
224
197
  }
225
198
  else {
226
199
  if (Array.isArray(nextChildren)) {
227
- mountArrayChildren(nextChildren, parentReference, nextReference, contextMap, nextElement, hostNamespace);
200
+ mountArrayChildren(nextChildren, parentReference, nextReference, context, nextElement, hostNamespace);
228
201
  }
229
202
  else if (typeof nextChildren === 'string') {
230
203
  hostAdapter.setTextContent(parentReference, nextChildren);
231
204
  }
232
205
  else if (nextChildren) {
233
206
  nextChildren.parent = nextElement;
234
- mount(nextChildren, parentReference, nextReference, contextMap, hostNamespace);
207
+ mount(nextChildren, parentReference, nextReference, context, hostNamespace);
235
208
  }
236
209
  }
237
210
  }
238
- export function patchKeyedChildren(prevChildren, nextChildren, parentReference, nextReference, contextMap, hostNamespace) {
211
+ export function patchKeyedChildren(prevChildren, nextChildren, parentReference, nextReference, context, hostNamespace) {
239
212
  let prevStart = 0;
240
213
  let nextStart = 0;
241
214
  let prevEnd = prevChildren.length - 1;
@@ -244,13 +217,13 @@ export function patchKeyedChildren(prevChildren, nextChildren, parentReference,
244
217
  while (prevStart <= prevEnd &&
245
218
  nextStart <= nextEnd &&
246
219
  prevChildren[prevStart].key === nextChildren[nextStart].key) {
247
- patch(prevChildren[prevStart], nextChildren[nextStart], parentReference, null, contextMap, hostNamespace);
220
+ patch(prevChildren[prevStart], nextChildren[nextStart], parentReference, null, context, hostNamespace);
248
221
  prevStart++;
249
222
  nextStart++;
250
223
  }
251
224
  // Step 2: Sync from end
252
225
  while (prevStart <= prevEnd && nextStart <= nextEnd && prevChildren[prevEnd].key === nextChildren[nextEnd].key) {
253
- patch(prevChildren[prevEnd], nextChildren[nextEnd], parentReference, null, contextMap, hostNamespace);
226
+ patch(prevChildren[prevEnd], nextChildren[nextEnd], parentReference, null, context, hostNamespace);
254
227
  prevEnd--;
255
228
  nextEnd--;
256
229
  }
@@ -258,7 +231,7 @@ export function patchKeyedChildren(prevChildren, nextChildren, parentReference,
258
231
  if (prevStart > prevEnd) {
259
232
  const before = findHostReferenceFromElement(nextChildren[nextEnd + 1]) || nextReference;
260
233
  for (let i = nextStart; i <= nextEnd; i++) {
261
- mount(nextChildren[i], parentReference, before, contextMap, hostNamespace);
234
+ mount(nextChildren[i], parentReference, before, context, hostNamespace);
262
235
  }
263
236
  // Step 4: Remove prev nodes if next list is exhausted
264
237
  }
@@ -286,12 +259,12 @@ export function patchKeyedChildren(prevChildren, nextChildren, parentReference,
286
259
  const prevIndex = keyToPrevIndexMap.get(nextChild.key);
287
260
  if (prevIndex != null) {
288
261
  const prevElement = prevChildren[prevIndex];
289
- patch(prevElement, nextChild, parentReference, null, contextMap, hostNamespace);
262
+ patch(prevElement, nextChild, parentReference, null, context, hostNamespace);
290
263
  toMove[i - nextStart] = prevIndex;
291
264
  usedIndices.add(prevIndex);
292
265
  }
293
266
  else {
294
- mount(nextChild, parentReference, findHostReferenceFromElement(nextChildren[i + 1]) || nextReference, contextMap, hostNamespace);
267
+ mount(nextChild, parentReference, findHostReferenceFromElement(nextChildren[i + 1]) || nextReference, context, hostNamespace);
295
268
  toMove[i - nextStart] = -1;
296
269
  }
297
270
  }
@@ -1,10 +1,11 @@
1
- import type { SimpElement } from './createElement.js';
1
+ import type { SimpElement, SimpElementStore } from './createElement.js';
2
2
  export declare function rerender(element: SimpElement): void;
3
3
  interface IRendererLocker {
4
4
  _isLocked: boolean;
5
- _elements: Set<SimpElement>;
6
- _track(element: SimpElement): void;
7
- _untrack(element: SimpElement): void;
5
+ _elementStores: Set<SimpElementStore>;
6
+ _last: SimpElementStore | undefined;
7
+ _track(element: SimpElementStore): void;
8
+ _untrack(element: SimpElementStore): void;
8
9
  lock(): void;
9
10
  flush(): void;
10
11
  }
package/core/rerender.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { findParentReferenceFromElement, updateFunctionalComponent } from './patching.js';
2
2
  import { lifecycleEventBus } from './lifecycleEventBus.js';
3
3
  lifecycleEventBus.subscribe(event => {
4
- if (event.type === 'afterRender') {
5
- batchingRerenderLocker._untrack(event.element);
6
- renderingRerenderLocker._untrack(event.element);
4
+ if (event.type === 'afterRender' || event.type === 'errored' || event.type === 'unmounted') {
5
+ batchingRerenderLocker._untrack(event.element.store);
6
+ renderingRerenderLocker._untrack(event.element.store);
7
7
  }
8
8
  });
9
9
  export function rerender(element) {
@@ -15,62 +15,114 @@ export function rerender(element) {
15
15
  }
16
16
  lifecycleEventBus.publish({ type: 'triedToRerender', element });
17
17
  if (batchingRerenderLocker._isLocked) {
18
- batchingRerenderLocker._track(element);
18
+ batchingRerenderLocker._track(element.store);
19
19
  return;
20
20
  }
21
21
  if (renderingRerenderLocker._isLocked) {
22
- renderingRerenderLocker._track(element);
22
+ renderingRerenderLocker._track(element.store);
23
23
  return;
24
24
  }
25
25
  renderingRerenderLocker.lock();
26
- updateFunctionalComponent(element, findParentReferenceFromElement(element), null, element.contextMap || null, element.store.hostNamespace);
26
+ updateFunctionalComponent(element, findParentReferenceFromElement(element), null, element.context || null, element.store.hostNamespace);
27
27
  renderingRerenderLocker.flush();
28
28
  }
29
29
  export const batchingRerenderLocker = {
30
30
  _isLocked: false,
31
- _elements: new Set(),
32
- _track(element) {
33
- this._elements.add(element);
31
+ _elementStores: new Set(),
32
+ _last: undefined,
33
+ _track(store) {
34
+ if (this._elementStores.has(store)) {
35
+ return;
36
+ }
37
+ if (this._elementStores.size === 0 || store.forceRender) {
38
+ this._elementStores.add(store);
39
+ this._last = store;
40
+ return;
41
+ }
42
+ if (isParentOf(store.latestElement, this._last.latestElement)) {
43
+ return;
44
+ }
45
+ if (isParentOf(this._last.latestElement, store.latestElement)) {
46
+ this._elementStores.clear();
47
+ this._elementStores.add(store);
48
+ this._last = store;
49
+ }
34
50
  },
35
- _untrack(element) {
36
- this._elements.delete(element);
51
+ _untrack(store) {
52
+ if (this._elementStores.delete(store) && store === this._last) {
53
+ this._last = undefined;
54
+ for (const val of this._elementStores) {
55
+ this._last = val;
56
+ }
57
+ }
37
58
  },
38
59
  lock() {
39
60
  this._isLocked = true;
40
61
  },
41
62
  flush() {
42
63
  this._isLocked = false;
43
- if (this._elements.size === 0) {
64
+ if (this._elementStores.size === 0) {
44
65
  return;
45
66
  }
46
- for (const element of this._elements) {
47
- this._untrack(element);
48
- rerender(element.store.latestElement);
67
+ for (const store of this._elementStores) {
68
+ this._untrack(store);
69
+ rerender(store.latestElement);
49
70
  }
50
71
  },
51
72
  };
52
73
  export const renderingRerenderLocker = {
53
74
  _isLocked: false,
54
- _elements: new Set(),
55
- _track(element) {
56
- this._elements.add(element);
75
+ _elementStores: new Set(),
76
+ _last: undefined,
77
+ _track(store) {
78
+ if (this._elementStores.has(store)) {
79
+ return;
80
+ }
81
+ if (this._elementStores.size === 0 || store.forceRender) {
82
+ this._elementStores.add(store);
83
+ this._last = store;
84
+ return;
85
+ }
86
+ if (isParentOf(store.latestElement, this._last.latestElement)) {
87
+ return;
88
+ }
89
+ if (isParentOf(this._last.latestElement, store.latestElement)) {
90
+ this._elementStores.clear();
91
+ this._elementStores.add(store);
92
+ this._last = store;
93
+ }
57
94
  },
58
- _untrack(element) {
59
- this._elements.delete(element);
95
+ _untrack(store) {
96
+ if (this._elementStores.delete(store) && store === this._last) {
97
+ this._last = undefined;
98
+ for (const val of this._elementStores) {
99
+ this._last = val;
100
+ }
101
+ }
60
102
  },
61
103
  lock() {
62
104
  this._isLocked = true;
63
105
  },
64
106
  flush() {
65
107
  this._isLocked = false;
66
- if (this._elements.size === 0) {
108
+ if (this._elementStores.size === 0) {
67
109
  return;
68
110
  }
69
111
  queueMicrotask(() => {
70
- for (const element of this._elements) {
71
- this._untrack(element);
72
- rerender(element.store.latestElement);
112
+ for (const store of this._elementStores) {
113
+ this._untrack(store);
114
+ rerender(store.latestElement);
73
115
  }
74
116
  });
75
117
  },
76
118
  };
119
+ function isParentOf(element, parent) {
120
+ let current = element.parent;
121
+ while (current) {
122
+ if (current.store === parent.store) {
123
+ return true;
124
+ }
125
+ current = current.parent;
126
+ }
127
+ return false;
128
+ }
@@ -28,7 +28,7 @@ export function unmount(element) {
28
28
  remove(element.children, element.ref);
29
29
  return;
30
30
  }
31
- // Only FRAGMENT, PROVIDER, CONSUMER, and HOST elements remain,
31
+ // Only FRAGMENT and HOST elements remain,
32
32
  // with Maybe<Many<SimpElement>> children due to normalization.
33
33
  if (element.children) {
34
34
  unmount(element.children);
@@ -45,11 +45,11 @@ export function clearElementHostReference(element, parentHostReference) {
45
45
  return;
46
46
  }
47
47
  const children = element.children;
48
- if (element.flag === 'FC' || element.flag === 'CONSUMER') {
48
+ if (element.flag === 'FC') {
49
49
  element = children;
50
50
  continue;
51
51
  }
52
- if (element.flag === 'FRAGMENT' || element.flag === 'PROVIDER') {
52
+ if (element.flag === 'FRAGMENT') {
53
53
  if (Array.isArray(children)) {
54
54
  for (let i = 0, len = children.length; i < len; ++i) {
55
55
  clearElementHostReference(children[i], parentHostReference);
@@ -5,5 +5,14 @@ export function attachElementToDom(element, dom) {
5
5
  }
6
6
  }
7
7
  export function getElementFromDom(target) {
8
- return target?.[elementPropertyName] ?? null;
8
+ if (!target) {
9
+ return null;
10
+ }
11
+ while (target && !(elementPropertyName in target)) {
12
+ target = target.parentElement;
13
+ }
14
+ if (!target) {
15
+ return null;
16
+ }
17
+ return target[elementPropertyName];
9
18
  }
package/dom/events.d.ts CHANGED
@@ -4,15 +4,20 @@ export declare class SyntheticEvent {
4
4
  nativeEvent: Event;
5
5
  currentTarget: Nullable<EventTarget>;
6
6
  isPropagationStopped: boolean;
7
- isDefaultPrevented: boolean;
7
+ _isDefaultPrevented: boolean;
8
8
  button?: number;
9
9
  buttons?: number;
10
10
  pointerId?: number;
11
+ altKey?: boolean;
12
+ ctrlKey?: boolean;
13
+ shiftKey?: boolean;
14
+ metaKey?: boolean;
11
15
  constructor(event: Event);
12
16
  get target(): EventTarget | null;
13
17
  get type(): string;
14
18
  stopPropagation(): void;
15
19
  preventDefault(): void;
20
+ isDefaultPrevented(): boolean;
16
21
  }
17
22
  export declare function dispatchDelegatedEvent(event: Event): void;
18
23
  export declare function patchEvent(name: string, prevValue: any, nextValue: any, dom: Element): void;
package/dom/events.js CHANGED
@@ -39,15 +39,22 @@ export class SyntheticEvent {
39
39
  nativeEvent;
40
40
  currentTarget = null;
41
41
  isPropagationStopped = false;
42
- isDefaultPrevented = false;
42
+ _isDefaultPrevented = false;
43
43
  button;
44
44
  buttons;
45
45
  pointerId;
46
+ altKey;
47
+ ctrlKey;
48
+ shiftKey;
49
+ metaKey;
46
50
  constructor(event) {
47
51
  this.nativeEvent = event;
48
52
  this.button = event.button;
49
53
  this.buttons = event.buttons;
50
54
  this.pointerId = event.pointerId;
55
+ this.altKey = event.altKey;
56
+ this.ctrlKey = event.ctrlKey;
57
+ this.metaKey = event.metaKey;
51
58
  }
52
59
  get target() {
53
60
  return this.nativeEvent.target;
@@ -60,9 +67,12 @@ export class SyntheticEvent {
60
67
  this.nativeEvent.stopPropagation();
61
68
  }
62
69
  preventDefault() {
63
- this.isDefaultPrevented = true;
70
+ this._isDefaultPrevented = true;
64
71
  this.nativeEvent.preventDefault();
65
72
  }
73
+ isDefaultPrevented() {
74
+ return this._isDefaultPrevented;
75
+ }
66
76
  }
67
77
  export function dispatchDelegatedEvent(event) {
68
78
  batchingRerenderLocker.lock();
package/hooks/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { RefObject, SimpContext } from '../core/index.js';
1
+ import type { RefObject } from '../core/index.js';
2
2
 
3
3
  export type Cleanup = () => void;
4
4
  export type Effect = () => void | Cleanup;
@@ -22,8 +22,6 @@ declare function useMounted(effect: Effect): void;
22
22
 
23
23
  declare function useUnmounted(cleanup: Cleanup): void;
24
24
 
25
- declare function useContext<T>(context: SimpContext<T>): T;
26
-
27
25
  declare function useCatch(cb: (error: any) => void): void;
28
26
 
29
27
  declare function areDepsEqual(nextDeps: DependencyList | undefined, prevDeps: DependencyList | undefined): boolean;
package/hooks/index.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import { batchingRerenderLocker, lifecycleEventBus, rerender as _rerender } from '../core/internal.js';
2
- import { noop } from '../shared/index.js';
3
- import { callOrGet } from '../shared/utils.js';
2
+ import { callOrGet, noop } from '../shared/index.js';
4
3
  let currentIndex = 0;
5
4
  // In runtime this is a nullable variable.
6
5
  let currentElement;
@@ -48,7 +47,9 @@ lifecycleEventBus.subscribe(event => {
48
47
  if (event.type === 'unmounted') {
49
48
  const element = event.element;
50
49
  if (element.store?.hookStates) {
51
- for (const state of element.store.hookStates) {
50
+ const hookStates = element.store.hookStates;
51
+ element.store.hookStates = undefined;
52
+ for (const state of hookStates) {
52
53
  if (state && 'cleanup' in state && typeof state.cleanup === 'function') {
53
54
  state.cleanup();
54
55
  }
@@ -91,6 +92,7 @@ export function useRerender() {
91
92
  if (!hookStates[currentIndex]) {
92
93
  const elementStore = currentElement.store;
93
94
  hookStates[currentIndex] = function rerender() {
95
+ elementStore.forceRender = true;
94
96
  _rerender(elementStore.latestElement);
95
97
  };
96
98
  }
@@ -108,6 +110,7 @@ export function useState(initialState) {
108
110
  return;
109
111
  }
110
112
  state[0] = nextValue;
113
+ elementStore.forceRender = true;
111
114
  _rerender(elementStore.latestElement);
112
115
  };
113
116
  }
@@ -141,9 +144,6 @@ export function useUnmounted(cleanup) {
141
144
  }
142
145
  currentIndex++;
143
146
  }
144
- export function useContext(context) {
145
- return currentElement.contextMap?.get(context) ?? context.defaultValue;
146
- }
147
147
  export function useCatch(cb) {
148
148
  if (!currentElement.store) {
149
149
  currentElement.store = {};
@@ -189,7 +189,6 @@ export default {
189
189
  useEffect,
190
190
  useMounted,
191
191
  useUnmounted,
192
- useContext,
193
192
  useCatch,
194
193
  areDepsEqual,
195
194
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simpreact/simpreact",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "",
5
5
  "homepage": "https://github.com/dPaskhin/simpreact#readme",
6
6
  "main": "./core/index.js",