@simpreact/simpreact 0.0.1 → 0.0.3
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/compat/core.d.ts +46 -0
- package/compat/core.js +93 -0
- package/compat/dom.d.ts +11 -0
- package/compat/dom.js +10 -0
- package/compat/hooks.d.ts +26 -0
- package/compat/hooks.js +77 -0
- package/compat/index.d.ts +42 -0
- package/compat/index.js +14 -0
- package/compat/jsx-runtime.d.ts +10 -0
- package/compat/jsx-runtime.js +9 -0
- package/compat/utils.d.ts +1 -0
- package/compat/utils.js +3 -0
- package/core/context.d.ts +1 -1
- package/core/createElement.d.ts +4 -4
- package/core/createElement.js +13 -6
- package/core/fragment.d.ts +1 -1
- package/core/hostAdapter.d.ts +3 -3
- package/core/index.d.ts +3 -3
- package/core/index.js +4 -4
- package/core/internal.d.ts +11 -11
- package/core/internal.js +11 -11
- package/core/lifecycleEventBus.d.ts +6 -2
- package/core/lifecycleEventBus.js +1 -1
- package/core/mounting.d.ts +4 -4
- package/core/mounting.js +42 -11
- package/core/patching.d.ts +4 -4
- package/core/patching.js +89 -19
- package/core/portal.d.ts +1 -1
- package/core/portal.js +1 -1
- package/core/ref.d.ts +5 -5
- package/core/rerender.d.ts +5 -5
- package/core/rerender.js +38 -25
- package/core/unmounting.d.ts +3 -3
- package/core/unmounting.js +7 -3
- package/dom/attach-element-to-dom.d.ts +1 -1
- package/dom/attach-element-to-dom.js +1 -1
- package/dom/domAdapter.d.ts +1 -1
- package/dom/domAdapter.js +10 -5
- package/dom/events.d.ts +4 -1
- package/dom/events.js +10 -4
- package/dom/index.d.ts +2 -2
- package/dom/index.js +2 -2
- package/dom/props/controlled/index.d.ts +1 -1
- package/dom/props/controlled/index.js +3 -3
- package/dom/props/controlled/input.d.ts +1 -1
- package/dom/props/controlled/input.js +6 -6
- package/dom/props/controlled/select.d.ts +1 -1
- package/dom/props/controlled/select.js +5 -5
- package/dom/props/controlled/textarea.d.ts +1 -1
- package/dom/props/controlled/textarea.js +6 -6
- package/dom/props/dangerInnerHTML.d.ts +1 -1
- package/dom/props/index.d.ts +1 -1
- package/dom/props/index.js +1 -1
- package/dom/props/props.d.ts +1 -1
- package/dom/props/props.js +6 -6
- package/dom/props/style.js +6 -3
- package/dom/render.d.ts +1 -1
- package/dom/render.js +5 -5
- package/hooks/index.d.ts +7 -1
- package/hooks/index.js +43 -10
- package/jsx-runtime/index.d.ts +3 -3
- package/package.json +8 -1
- package/shared/index.js +3 -3
- package/shared/utils.d.ts +2 -1
- package/shared/utils.js +16 -0
package/core/mounting.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { emptyMap, emptyObject } from '../shared';
|
|
2
|
-
import { hostAdapter } from './hostAdapter';
|
|
3
|
-
import { createTextElement, normalizeRoot } from './createElement';
|
|
4
|
-
import { applyRef } from './ref';
|
|
5
|
-
import { lifecycleEventBus } from './lifecycleEventBus';
|
|
1
|
+
import { emptyMap, emptyObject } from '../shared/index.js';
|
|
2
|
+
import { hostAdapter } from './hostAdapter.js';
|
|
3
|
+
import { createTextElement, normalizeRoot } from './createElement.js';
|
|
4
|
+
import { applyRef } from './ref.js';
|
|
5
|
+
import { lifecycleEventBus } from './lifecycleEventBus.js';
|
|
6
|
+
import { batchingRerenderLocker } from './rerender.js';
|
|
6
7
|
export function mount(element, parentReference, nextReference, contextMap, hostNamespace) {
|
|
7
8
|
if (element.flag === 'TEXT') {
|
|
8
9
|
mountTextElement(element, parentReference, nextReference);
|
|
@@ -37,9 +38,6 @@ export function mountHostElement(element, parentReference, nextReference, contex
|
|
|
37
38
|
hostNamespace = hostNamespaces?.self;
|
|
38
39
|
const hostReference = (element.reference = hostAdapter.createReference(element.type, hostNamespace));
|
|
39
40
|
hostAdapter.attachElementToReference(element, hostReference);
|
|
40
|
-
if (parentReference) {
|
|
41
|
-
hostAdapter.insertOrAppend(parentReference, hostReference, nextReference);
|
|
42
|
-
}
|
|
43
41
|
// HOST element always has Maybe<Many<SimpElement>> children due to normalization process.
|
|
44
42
|
const children = element.children;
|
|
45
43
|
if (Array.isArray(children)) {
|
|
@@ -51,10 +49,17 @@ export function mountHostElement(element, parentReference, nextReference, contex
|
|
|
51
49
|
}
|
|
52
50
|
if (element.props) {
|
|
53
51
|
hostAdapter.mountProps(hostReference, element, hostNamespace);
|
|
52
|
+
// HOST elements can have either children elements or string children in the props due to normalization.
|
|
53
|
+
if (typeof element.props.children === 'string') {
|
|
54
|
+
hostAdapter.setTextContent(hostReference, element.props.children);
|
|
55
|
+
}
|
|
54
56
|
}
|
|
55
57
|
if (element.className) {
|
|
56
58
|
hostAdapter.setClassname(hostReference, element.className, hostNamespace);
|
|
57
59
|
}
|
|
60
|
+
if (parentReference) {
|
|
61
|
+
hostAdapter.insertOrAppend(parentReference, hostReference, nextReference);
|
|
62
|
+
}
|
|
58
63
|
applyRef(element);
|
|
59
64
|
}
|
|
60
65
|
export function mountFunctionalElement(element, parentReference, nextReference, contextMap, hostNamespace) {
|
|
@@ -70,15 +75,41 @@ export function mountFunctionalElement(element, parentReference, nextReference,
|
|
|
70
75
|
}
|
|
71
76
|
// FC element always has Maybe<SimpElement> children due to normalization process.
|
|
72
77
|
let children;
|
|
78
|
+
let triedToRerenderUnsubscribe;
|
|
73
79
|
try {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
lifecycleEventBus.
|
|
80
|
+
let triedToRerender = false;
|
|
81
|
+
let rerenderCounter = 0;
|
|
82
|
+
triedToRerenderUnsubscribe = lifecycleEventBus.subscribe(event => {
|
|
83
|
+
if (event.type === 'triedToRerender' && event.element === element) {
|
|
84
|
+
triedToRerender = true;
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
do {
|
|
88
|
+
triedToRerender = false;
|
|
89
|
+
if (++rerenderCounter >= 25) {
|
|
90
|
+
lifecycleEventBus.publish({
|
|
91
|
+
type: 'errored',
|
|
92
|
+
element,
|
|
93
|
+
error: new Error('Too many re-renders. SimpReact limits the number of renders to prevent an infinite loop.'),
|
|
94
|
+
phase: 'mounting',
|
|
95
|
+
});
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
lifecycleEventBus.publish({ type: 'beforeRender', element, phase: 'mounting' });
|
|
99
|
+
batchingRerenderLocker.lock();
|
|
100
|
+
children = element.type(element.props || emptyObject);
|
|
101
|
+
batchingRerenderLocker.flush();
|
|
102
|
+
lifecycleEventBus.publish({ type: 'afterRender', element, phase: 'mounting' });
|
|
103
|
+
} while (triedToRerender);
|
|
104
|
+
children = normalizeRoot(children, false);
|
|
77
105
|
}
|
|
78
106
|
catch (error) {
|
|
79
107
|
lifecycleEventBus.publish({ type: 'errored', element, error, phase: 'mounting' });
|
|
80
108
|
return;
|
|
81
109
|
}
|
|
110
|
+
finally {
|
|
111
|
+
triedToRerenderUnsubscribe();
|
|
112
|
+
}
|
|
82
113
|
if (children) {
|
|
83
114
|
children.parent = element;
|
|
84
115
|
mount((element.children = children), parentReference, nextReference, contextMap, hostNamespace);
|
package/core/patching.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { Maybe, Nullable } from '../shared';
|
|
2
|
-
import type { SimpElement } from './createElement';
|
|
3
|
-
import type { HostReference } from './hostAdapter';
|
|
4
|
-
import type { SimpContextMap } from './context';
|
|
1
|
+
import type { Maybe, Nullable } from '../shared/index.js';
|
|
2
|
+
import type { SimpElement } from './createElement.js';
|
|
3
|
+
import type { HostReference } from './hostAdapter.js';
|
|
4
|
+
import type { SimpContextMap } from './context.js';
|
|
5
5
|
export declare function patch(prevElement: SimpElement, nextElement: SimpElement, parentReference: HostReference, nextReference: Nullable<HostReference>, contextMap: Nullable<SimpContextMap>, hostNamespace: Maybe<string>): void;
|
|
6
6
|
export declare function patchPortal(prevElement: SimpElement, nextElement: SimpElement, contextMap: Nullable<SimpContextMap>): void;
|
|
7
7
|
export declare function updateFunctionalComponent(element: SimpElement, parentReference: HostReference, nextReference: Nullable<HostReference>, contextMap: Nullable<SimpContextMap>, hostNamespace: Maybe<string>): void;
|
package/core/patching.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { emptyMap, emptyObject } from '../shared';
|
|
2
|
-
import { normalizeRoot } from './createElement';
|
|
3
|
-
import { hostAdapter } from './hostAdapter';
|
|
4
|
-
import { clearElementHostReference, remove, unmount } from './unmounting';
|
|
5
|
-
import { mount, mountArrayChildren } from './mounting';
|
|
6
|
-
import { applyRef } from './ref';
|
|
7
|
-
import { lifecycleEventBus } from './lifecycleEventBus';
|
|
1
|
+
import { emptyMap, 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 } from './mounting.js';
|
|
6
|
+
import { applyRef } from './ref.js';
|
|
7
|
+
import { lifecycleEventBus } from './lifecycleEventBus.js';
|
|
8
|
+
import { batchingRerenderLocker } from './rerender.js';
|
|
8
9
|
export function patch(prevElement, nextElement, parentReference, nextReference, contextMap, hostNamespace) {
|
|
9
10
|
if (prevElement.type !== nextElement.type || prevElement.key !== nextElement.key) {
|
|
10
11
|
replaceWithNewElement(prevElement, nextElement, parentReference, contextMap, hostNamespace);
|
|
@@ -51,7 +52,7 @@ function patchHostElement(prevElement, nextElement, contextMap, hostNamespace) {
|
|
|
51
52
|
hostNamespace = hostNamespaces?.self;
|
|
52
53
|
nextElement.reference = prevElement.reference;
|
|
53
54
|
hostAdapter.attachElementToReference(nextElement, nextElement.reference);
|
|
54
|
-
patchChildren(prevElement.children, nextElement.children, nextElement.reference, null, nextElement, contextMap, hostNamespaces?.children);
|
|
55
|
+
patchChildren(prevElement.children || prevElement.props?.children, nextElement.children || nextElement.props?.children, nextElement.reference, null, nextElement, contextMap, hostNamespaces?.children);
|
|
55
56
|
hostAdapter.patchProps(nextElement.reference, prevElement, nextElement, hostNamespace);
|
|
56
57
|
if (prevElement.className !== nextElement.className) {
|
|
57
58
|
hostAdapter.setClassname(nextElement.reference, nextElement.className, hostNamespace);
|
|
@@ -59,29 +60,69 @@ function patchHostElement(prevElement, nextElement, contextMap, hostNamespace) {
|
|
|
59
60
|
applyRef(nextElement);
|
|
60
61
|
}
|
|
61
62
|
function patchFunctionalComponent(prevElement, nextElement, parentReference, nextReference, contextMap, hostNamespace) {
|
|
62
|
-
|
|
63
|
+
const prevStore = !prevElement.store || prevElement.unmounted
|
|
64
|
+
? { hostNamespace: prevElement.store?.hostNamespace }
|
|
65
|
+
: prevElement.store;
|
|
66
|
+
prevStore.latestElement = nextElement;
|
|
67
|
+
nextElement.store = prevStore;
|
|
63
68
|
if (hostNamespace) {
|
|
64
69
|
nextElement.store.hostNamespace = hostNamespace;
|
|
65
70
|
}
|
|
66
71
|
if (contextMap) {
|
|
67
72
|
nextElement.contextMap = contextMap;
|
|
68
73
|
}
|
|
74
|
+
// FC element always has Maybe<SimpElement> children due to normalization process.
|
|
69
75
|
let nextChildren;
|
|
76
|
+
let triedToRerenderUnsubscribe;
|
|
70
77
|
try {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
lifecycleEventBus.
|
|
78
|
+
let triedToRerender = false;
|
|
79
|
+
let rerenderCounter = 0;
|
|
80
|
+
triedToRerenderUnsubscribe = lifecycleEventBus.subscribe(event => {
|
|
81
|
+
if (event.type === 'triedToRerender' && event.element === nextElement) {
|
|
82
|
+
triedToRerender = true;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
do {
|
|
86
|
+
triedToRerender = false;
|
|
87
|
+
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;
|
|
95
|
+
}
|
|
96
|
+
lifecycleEventBus.publish({ type: 'beforeRender', element: nextElement, phase: 'updating' });
|
|
97
|
+
batchingRerenderLocker.lock();
|
|
98
|
+
nextChildren = nextElement.type(nextElement.props || emptyObject);
|
|
99
|
+
batchingRerenderLocker.flush();
|
|
100
|
+
lifecycleEventBus.publish({ type: 'afterRender', element: nextElement, phase: 'updating' });
|
|
101
|
+
} while (triedToRerender);
|
|
102
|
+
nextChildren = normalizeRoot(nextChildren, false);
|
|
74
103
|
}
|
|
75
104
|
catch (error) {
|
|
76
105
|
lifecycleEventBus.publish({ type: 'errored', element: nextElement, error, phase: 'updating' });
|
|
77
106
|
return;
|
|
78
107
|
}
|
|
108
|
+
finally {
|
|
109
|
+
triedToRerenderUnsubscribe();
|
|
110
|
+
}
|
|
79
111
|
const prevChildren = prevElement.children;
|
|
80
112
|
if (nextChildren) {
|
|
81
113
|
nextElement.children = nextChildren;
|
|
82
114
|
}
|
|
83
|
-
|
|
84
|
-
|
|
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 });
|
|
85
126
|
}
|
|
86
127
|
function patchTextElement(prevElement, nextElement) {
|
|
87
128
|
nextElement.reference = prevElement.reference;
|
|
@@ -134,6 +175,10 @@ function patchChildren(prevChildren, nextChildren, parentReference, nextReferenc
|
|
|
134
175
|
}
|
|
135
176
|
patchKeyedChildren(prevChildren, nextChildren, parentReference, nextReference, contextMap, hostNamespace);
|
|
136
177
|
}
|
|
178
|
+
else if (typeof nextChildren === 'string') {
|
|
179
|
+
unmount(prevChildren);
|
|
180
|
+
hostAdapter.setTextContent(parentReference, nextChildren);
|
|
181
|
+
}
|
|
137
182
|
else if (nextChildren) {
|
|
138
183
|
patchKeyedChildren(prevChildren, [nextChildren], parentReference, nextReference, contextMap, hostNamespace);
|
|
139
184
|
}
|
|
@@ -142,23 +187,48 @@ function patchChildren(prevChildren, nextChildren, parentReference, nextReferenc
|
|
|
142
187
|
hostAdapter.clearNode(parentReference);
|
|
143
188
|
}
|
|
144
189
|
}
|
|
190
|
+
else if (typeof prevChildren === 'string') {
|
|
191
|
+
if (Array.isArray(nextChildren)) {
|
|
192
|
+
hostAdapter.clearNode(parentReference);
|
|
193
|
+
mountArrayChildren(nextChildren, parentReference, nextReference, contextMap, nextElement, hostNamespace);
|
|
194
|
+
}
|
|
195
|
+
else if (typeof nextChildren === 'string') {
|
|
196
|
+
if (prevChildren !== nextChildren) {
|
|
197
|
+
hostAdapter.setTextContent(nextElement.reference, nextChildren, true);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
else if (nextChildren) {
|
|
201
|
+
hostAdapter.clearNode(parentReference);
|
|
202
|
+
nextChildren.parent = nextElement;
|
|
203
|
+
mount(nextChildren, parentReference, nextReference, contextMap, hostNamespace);
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
hostAdapter.clearNode(parentReference);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
145
209
|
else if (prevChildren) {
|
|
146
210
|
if (Array.isArray(nextChildren)) {
|
|
147
211
|
patchKeyedChildren([prevChildren], nextChildren, parentReference, nextReference, contextMap, hostNamespace);
|
|
148
212
|
}
|
|
213
|
+
else if (typeof nextChildren === 'string') {
|
|
214
|
+
unmount(prevChildren);
|
|
215
|
+
hostAdapter.setTextContent(parentReference, nextChildren);
|
|
216
|
+
}
|
|
149
217
|
else if (nextChildren) {
|
|
150
218
|
nextChildren.parent = nextElement;
|
|
151
219
|
patch(prevChildren, nextChildren, parentReference, nextReference, contextMap, hostNamespace);
|
|
152
220
|
}
|
|
153
221
|
else {
|
|
154
|
-
|
|
155
|
-
hostAdapter.clearNode(parentReference);
|
|
222
|
+
remove(prevChildren, parentReference);
|
|
156
223
|
}
|
|
157
224
|
}
|
|
158
225
|
else {
|
|
159
226
|
if (Array.isArray(nextChildren)) {
|
|
160
227
|
mountArrayChildren(nextChildren, parentReference, nextReference, contextMap, nextElement, hostNamespace);
|
|
161
228
|
}
|
|
229
|
+
else if (typeof nextChildren === 'string') {
|
|
230
|
+
hostAdapter.setTextContent(parentReference, nextChildren);
|
|
231
|
+
}
|
|
162
232
|
else if (nextChildren) {
|
|
163
233
|
nextChildren.parent = nextElement;
|
|
164
234
|
mount(nextChildren, parentReference, nextReference, contextMap, hostNamespace);
|
|
@@ -186,7 +256,7 @@ export function patchKeyedChildren(prevChildren, nextChildren, parentReference,
|
|
|
186
256
|
}
|
|
187
257
|
// Step 3: Mount new nodes if prev list is exhausted
|
|
188
258
|
if (prevStart > prevEnd) {
|
|
189
|
-
const before = nextChildren[nextEnd + 1]
|
|
259
|
+
const before = findHostReferenceFromElement(nextChildren[nextEnd + 1]) || nextReference;
|
|
190
260
|
for (let i = nextStart; i <= nextEnd; i++) {
|
|
191
261
|
mount(nextChildren[i], parentReference, before, contextMap, hostNamespace);
|
|
192
262
|
}
|
|
@@ -221,7 +291,7 @@ export function patchKeyedChildren(prevChildren, nextChildren, parentReference,
|
|
|
221
291
|
usedIndices.add(prevIndex);
|
|
222
292
|
}
|
|
223
293
|
else {
|
|
224
|
-
mount(nextChild, parentReference, nextChildren[i + 1]
|
|
294
|
+
mount(nextChild, parentReference, findHostReferenceFromElement(nextChildren[i + 1]) || nextReference, contextMap, hostNamespace);
|
|
225
295
|
toMove[i - nextStart] = -1;
|
|
226
296
|
}
|
|
227
297
|
}
|
|
@@ -234,7 +304,7 @@ export function patchKeyedChildren(prevChildren, nextChildren, parentReference,
|
|
|
234
304
|
// Insert in correct order
|
|
235
305
|
for (let i = nextEnd; i >= nextStart; i--) {
|
|
236
306
|
const currentChild = nextChildren[i];
|
|
237
|
-
const reference = nextChildren[i + 1]
|
|
307
|
+
const reference = findHostReferenceFromElement(nextChildren[i + 1]) || nextReference;
|
|
238
308
|
if (toMove[i - nextStart] !== -1) {
|
|
239
309
|
hostAdapter.insertBefore(parentReference, currentChild.reference, reference);
|
|
240
310
|
}
|
package/core/portal.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { SimpElement, SimpNode } from './createElement';
|
|
1
|
+
import type { SimpElement, SimpNode } from './createElement.js';
|
|
2
2
|
export declare function createPortal(children: SimpNode, container: any): SimpElement;
|
package/core/portal.js
CHANGED
package/core/ref.d.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import type { SimpElement } from './createElement';
|
|
1
|
+
import type { SimpElement } from './createElement.js';
|
|
2
2
|
interface RefSimpElement extends SimpElement {
|
|
3
3
|
ref?: {
|
|
4
4
|
value: NonNullable<Ref<unknown>>;
|
|
5
5
|
cleanup?: () => void;
|
|
6
6
|
};
|
|
7
7
|
}
|
|
8
|
-
export
|
|
8
|
+
export type RefObject<T> = {
|
|
9
9
|
current: T;
|
|
10
|
-
}
|
|
10
|
+
};
|
|
11
11
|
export type RefCallback<T> = {
|
|
12
|
-
bivarianceHack(instance: T
|
|
12
|
+
bivarianceHack(instance: T): (() => void | undefined) | void;
|
|
13
13
|
}['bivarianceHack'];
|
|
14
|
-
export type Ref<T> = RefCallback<T> | RefObject<T> | null;
|
|
14
|
+
export type Ref<T> = RefCallback<T> | RefObject<T | null> | null;
|
|
15
15
|
export declare function unmountRef(element: RefSimpElement): void;
|
|
16
16
|
export declare function applyRef(element: RefSimpElement): void;
|
|
17
17
|
export {};
|
package/core/rerender.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import type { SimpElement } from './createElement';
|
|
1
|
+
import type { SimpElement } from './createElement.js';
|
|
2
2
|
export declare function rerender(element: SimpElement): void;
|
|
3
3
|
interface IRendererLocker {
|
|
4
4
|
_isLocked: boolean;
|
|
5
5
|
_elements: Set<SimpElement>;
|
|
6
|
-
|
|
6
|
+
_track(element: SimpElement): void;
|
|
7
|
+
_untrack(element: SimpElement): void;
|
|
7
8
|
lock(): void;
|
|
8
|
-
track(element: SimpElement): void;
|
|
9
9
|
flush(): void;
|
|
10
10
|
}
|
|
11
|
-
export declare const
|
|
12
|
-
export declare const
|
|
11
|
+
export declare const batchingRerenderLocker: IRendererLocker;
|
|
12
|
+
export declare const renderingRerenderLocker: IRendererLocker;
|
|
13
13
|
export {};
|
package/core/rerender.js
CHANGED
|
@@ -1,61 +1,74 @@
|
|
|
1
|
-
import { findParentReferenceFromElement, updateFunctionalComponent } from './patching';
|
|
1
|
+
import { findParentReferenceFromElement, updateFunctionalComponent } from './patching.js';
|
|
2
|
+
import { lifecycleEventBus } from './lifecycleEventBus.js';
|
|
3
|
+
lifecycleEventBus.subscribe(event => {
|
|
4
|
+
if (event.type === 'afterRender') {
|
|
5
|
+
batchingRerenderLocker._untrack(event.element);
|
|
6
|
+
renderingRerenderLocker._untrack(event.element);
|
|
7
|
+
}
|
|
8
|
+
});
|
|
2
9
|
export function rerender(element) {
|
|
3
10
|
if (element.flag !== 'FC') {
|
|
4
11
|
throw new TypeError('Re-rendering is only supported for FC elements.');
|
|
5
12
|
}
|
|
6
13
|
if (element.unmounted) {
|
|
7
|
-
console.warn('The component unmounted.');
|
|
14
|
+
console.warn('The component is unmounted.');
|
|
8
15
|
}
|
|
9
|
-
|
|
10
|
-
|
|
16
|
+
lifecycleEventBus.publish({ type: 'triedToRerender', element });
|
|
17
|
+
if (batchingRerenderLocker._isLocked) {
|
|
18
|
+
batchingRerenderLocker._track(element);
|
|
11
19
|
return;
|
|
12
20
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
else {
|
|
17
|
-
asyncRerenderLocker.lock();
|
|
18
|
-
updateFunctionalComponent(element, findParentReferenceFromElement(element), null, element.contextMap || null, element.store.hostNamespace);
|
|
19
|
-
asyncRerenderLocker.flush();
|
|
21
|
+
if (renderingRerenderLocker._isLocked) {
|
|
22
|
+
renderingRerenderLocker._track(element);
|
|
23
|
+
return;
|
|
20
24
|
}
|
|
25
|
+
renderingRerenderLocker.lock();
|
|
26
|
+
updateFunctionalComponent(element, findParentReferenceFromElement(element), null, element.contextMap || null, element.store.hostNamespace);
|
|
27
|
+
renderingRerenderLocker.flush();
|
|
21
28
|
}
|
|
22
|
-
export const
|
|
29
|
+
export const batchingRerenderLocker = {
|
|
23
30
|
_isLocked: false,
|
|
24
31
|
_elements: new Set(),
|
|
25
|
-
|
|
26
|
-
|
|
32
|
+
_track(element) {
|
|
33
|
+
this._elements.add(element);
|
|
34
|
+
},
|
|
35
|
+
_untrack(element) {
|
|
36
|
+
this._elements.delete(element);
|
|
27
37
|
},
|
|
28
38
|
lock() {
|
|
29
39
|
this._isLocked = true;
|
|
30
40
|
},
|
|
31
|
-
track(element) {
|
|
32
|
-
this._elements.add(element);
|
|
33
|
-
},
|
|
34
41
|
flush() {
|
|
35
42
|
this._isLocked = false;
|
|
43
|
+
if (this._elements.size === 0) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
36
46
|
for (const element of this._elements) {
|
|
37
|
-
this.
|
|
47
|
+
this._untrack(element);
|
|
38
48
|
rerender(element.store.latestElement);
|
|
39
49
|
}
|
|
40
50
|
},
|
|
41
51
|
};
|
|
42
|
-
export const
|
|
52
|
+
export const renderingRerenderLocker = {
|
|
43
53
|
_isLocked: false,
|
|
44
54
|
_elements: new Set(),
|
|
45
|
-
|
|
46
|
-
|
|
55
|
+
_track(element) {
|
|
56
|
+
this._elements.add(element);
|
|
57
|
+
},
|
|
58
|
+
_untrack(element) {
|
|
59
|
+
this._elements.delete(element);
|
|
47
60
|
},
|
|
48
61
|
lock() {
|
|
49
62
|
this._isLocked = true;
|
|
50
63
|
},
|
|
51
|
-
track(element) {
|
|
52
|
-
this._elements.add(element);
|
|
53
|
-
},
|
|
54
64
|
flush() {
|
|
55
65
|
this._isLocked = false;
|
|
66
|
+
if (this._elements.size === 0) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
56
69
|
queueMicrotask(() => {
|
|
57
70
|
for (const element of this._elements) {
|
|
58
|
-
this.
|
|
71
|
+
this._untrack(element);
|
|
59
72
|
rerender(element.store.latestElement);
|
|
60
73
|
}
|
|
61
74
|
});
|
package/core/unmounting.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { Many, Maybe } from '../shared';
|
|
2
|
-
import type { SimpElement } from './createElement';
|
|
3
|
-
import type { HostReference } from './hostAdapter';
|
|
1
|
+
import type { Many, Maybe } from '../shared/index.js';
|
|
2
|
+
import type { SimpElement } from './createElement.js';
|
|
3
|
+
import type { HostReference } from './hostAdapter.js';
|
|
4
4
|
export declare function unmount(element: Many<SimpElement>): void;
|
|
5
5
|
export declare function clearElementHostReference(element: Maybe<SimpElement>, parentHostReference: HostReference): void;
|
|
6
6
|
export declare function remove(element: SimpElement, parentReference: HostReference): void;
|
package/core/unmounting.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { hostAdapter } from './hostAdapter';
|
|
2
|
-
import { unmountRef } from './ref';
|
|
3
|
-
import { lifecycleEventBus } from './lifecycleEventBus';
|
|
1
|
+
import { hostAdapter } from './hostAdapter.js';
|
|
2
|
+
import { unmountRef } from './ref.js';
|
|
3
|
+
import { lifecycleEventBus } from './lifecycleEventBus.js';
|
|
4
4
|
export function unmount(element) {
|
|
5
5
|
if (Array.isArray(element)) {
|
|
6
6
|
for (const child of element) {
|
|
@@ -9,6 +9,10 @@ export function unmount(element) {
|
|
|
9
9
|
return;
|
|
10
10
|
}
|
|
11
11
|
if (element.flag === 'FC') {
|
|
12
|
+
// Skip — element is already unmounted.
|
|
13
|
+
if (element.unmounted) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
12
16
|
// FC element always has Maybe<SimpElement> due to normalization.
|
|
13
17
|
if (element.children) {
|
|
14
18
|
unmount(element.children);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Nullable } from '../shared';
|
|
1
|
+
import type { Nullable } from '../shared/index.js';
|
|
2
2
|
import type { SimpElement } from '../core/internal.js';
|
|
3
3
|
export declare function attachElementToDom(element: SimpElement, dom: Node): void;
|
|
4
4
|
export declare function getElementFromDom(target: Nullable<EventTarget>): Nullable<SimpElement>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const elementPropertyName = '__SIMP_ELEMENT__';
|
|
2
2
|
export function attachElementToDom(element, dom) {
|
|
3
|
-
if (
|
|
3
|
+
if (element.flag !== 'TEXT') {
|
|
4
4
|
Object.defineProperty(dom, elementPropertyName, { value: element, writable: true });
|
|
5
5
|
}
|
|
6
6
|
}
|
package/dom/domAdapter.d.ts
CHANGED
package/dom/domAdapter.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { attachElementToDom } from './attach-element-to-dom';
|
|
2
|
-
import { mountProps, patchProps, unmountProps } from './props';
|
|
3
|
-
import { defaultNamespace } from './namespace';
|
|
1
|
+
import { attachElementToDom } from './attach-element-to-dom.js';
|
|
2
|
+
import { mountProps, patchProps, unmountProps } from './props/index.js';
|
|
3
|
+
import { defaultNamespace } from './namespace.js';
|
|
4
4
|
export const domAdapter = {
|
|
5
5
|
createReference(type, namespace) {
|
|
6
6
|
if (namespace) {
|
|
@@ -33,8 +33,13 @@ export const domAdapter = {
|
|
|
33
33
|
reference.className = className;
|
|
34
34
|
}
|
|
35
35
|
},
|
|
36
|
-
setTextContent(reference, text) {
|
|
37
|
-
|
|
36
|
+
setTextContent(reference, text, referenceHasOnlyTextElement) {
|
|
37
|
+
if (referenceHasOnlyTextElement) {
|
|
38
|
+
reference.firstChild.nodeValue = text;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
reference.textContent = text;
|
|
42
|
+
}
|
|
38
43
|
},
|
|
39
44
|
appendChild(parent, child) {
|
|
40
45
|
parent.appendChild(child);
|
package/dom/events.d.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import type { Nullable } from '../shared';
|
|
1
|
+
import type { Nullable } from '../shared/index.js';
|
|
2
2
|
type DelegatedEventType = 'click' | 'dblclick' | 'mousedown' | 'mouseup' | 'mousemove' | 'pointerdown' | 'pointerup' | 'pointermove' | 'touchstart' | 'touchmove' | 'touchend' | 'keydown' | 'keyup' | 'focusin' | 'focusout';
|
|
3
3
|
export declare class SyntheticEvent {
|
|
4
4
|
nativeEvent: Event;
|
|
5
5
|
currentTarget: Nullable<EventTarget>;
|
|
6
6
|
isPropagationStopped: boolean;
|
|
7
7
|
isDefaultPrevented: boolean;
|
|
8
|
+
button?: number;
|
|
9
|
+
buttons?: number;
|
|
10
|
+
pointerId?: number;
|
|
8
11
|
constructor(event: Event);
|
|
9
12
|
get target(): EventTarget | null;
|
|
10
13
|
get type(): string;
|
package/dom/events.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getElementFromDom } from './attach-element-to-dom';
|
|
1
|
+
import { batchingRerenderLocker } from '../core/internal.js';
|
|
2
|
+
import { getElementFromDom } from './attach-element-to-dom.js';
|
|
3
3
|
const eventNameByTypes = {
|
|
4
4
|
click: 'onClick',
|
|
5
5
|
dblclick: 'onDblClick',
|
|
@@ -40,8 +40,14 @@ export class SyntheticEvent {
|
|
|
40
40
|
currentTarget = null;
|
|
41
41
|
isPropagationStopped = false;
|
|
42
42
|
isDefaultPrevented = false;
|
|
43
|
+
button;
|
|
44
|
+
buttons;
|
|
45
|
+
pointerId;
|
|
43
46
|
constructor(event) {
|
|
44
47
|
this.nativeEvent = event;
|
|
48
|
+
this.button = event.button;
|
|
49
|
+
this.buttons = event.buttons;
|
|
50
|
+
this.pointerId = event.pointerId;
|
|
45
51
|
}
|
|
46
52
|
get target() {
|
|
47
53
|
return this.nativeEvent.target;
|
|
@@ -59,7 +65,7 @@ export class SyntheticEvent {
|
|
|
59
65
|
}
|
|
60
66
|
}
|
|
61
67
|
export function dispatchDelegatedEvent(event) {
|
|
62
|
-
|
|
68
|
+
batchingRerenderLocker.lock();
|
|
63
69
|
const syntheticEvent = new SyntheticEvent(event);
|
|
64
70
|
const captureHandlers = [];
|
|
65
71
|
const bubbleHandlers = [];
|
|
@@ -91,7 +97,7 @@ export function dispatchDelegatedEvent(event) {
|
|
|
91
97
|
return;
|
|
92
98
|
}
|
|
93
99
|
}
|
|
94
|
-
|
|
100
|
+
batchingRerenderLocker.flush();
|
|
95
101
|
}
|
|
96
102
|
const captureRegex = /Capture/;
|
|
97
103
|
export function patchEvent(name, prevValue, nextValue, dom) {
|
package/dom/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { RefAttributes, SimpElement, SimpNode } from '../core';
|
|
2
|
-
import type { Nullable } from '../shared';
|
|
1
|
+
import type { RefAttributes, SimpElement, SimpNode } from '../core/index.js';
|
|
2
|
+
import type { Nullable } from '../shared/index.js';
|
|
3
3
|
|
|
4
4
|
import type { PropertiesHyphen } from 'csstype';
|
|
5
5
|
|
package/dom/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { createRoot, render } from './render';
|
|
2
|
-
export { createRoot, render } from './render';
|
|
1
|
+
import { createRoot, render } from './render.js';
|
|
2
|
+
export { createRoot, render } from './render.js';
|
|
3
3
|
export default { createRoot, render };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SimpElement } from '../../../core/internal.js';
|
|
2
|
-
import type { Dict } from '../../../shared';
|
|
2
|
+
import type { Dict } from '../../../shared/index.js';
|
|
3
3
|
export declare function isEventNameIgnored(element: SimpElement, eventName: string): boolean;
|
|
4
4
|
export declare function isFormElementControlled(props: Dict): boolean;
|
|
5
5
|
export declare function addControlledFormElementEventHandlers(element: SimpElement): void;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { addControlledInputEventHandlers, isEventNameIgnored as isEventNameIgnoredInput, removeControlledInputEventHandlers, syncControlledInputProps, } from './input';
|
|
2
|
-
import { addControlledSelectEventHandlers, isEventNameIgnored as isEventNameIgnoredSelect, removeControlledSelectEventHandlers, syncControlledSelectProps, } from './select';
|
|
3
|
-
import { addControlledTextareaEventHandlers, isEventNameIgnored as isEventNameIgnoredTextarea, removeControlledTextareaEventHandlers, syncControlledTextareaProps, } from './textarea';
|
|
1
|
+
import { addControlledInputEventHandlers, isEventNameIgnored as isEventNameIgnoredInput, removeControlledInputEventHandlers, syncControlledInputProps, } from './input.js';
|
|
2
|
+
import { addControlledSelectEventHandlers, isEventNameIgnored as isEventNameIgnoredSelect, removeControlledSelectEventHandlers, syncControlledSelectProps, } from './select.js';
|
|
3
|
+
import { addControlledTextareaEventHandlers, isEventNameIgnored as isEventNameIgnoredTextarea, removeControlledTextareaEventHandlers, syncControlledTextareaProps, } from './textarea.js';
|
|
4
4
|
export function isEventNameIgnored(element, eventName) {
|
|
5
5
|
if (element.type === 'input') {
|
|
6
6
|
return isEventNameIgnoredInput(element.props, eventName);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SimpElement } from '../../../core/internal.js';
|
|
2
|
-
import type { Dict } from '../../../shared';
|
|
2
|
+
import type { Dict } from '../../../shared/index.js';
|
|
3
3
|
export declare function isCheckedType(type: string): boolean;
|
|
4
4
|
export declare function isEventNameIgnored(props: Dict, eventName: string): boolean;
|
|
5
5
|
export declare function addControlledInputEventHandlers(dom: HTMLInputElement): void;
|