@avento-space/ts-ui 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +9 -0
- package/README.md +277 -0
- package/dist/adapters/dom/hydration.d.ts +4 -0
- package/dist/adapters/dom/hydration.d.ts.map +1 -0
- package/dist/adapters/dom/hydration.js +366 -0
- package/dist/adapters/dom/hydration.js.map +1 -0
- package/dist/adapters/dom/index.d.ts +3 -0
- package/dist/adapters/dom/index.d.ts.map +1 -0
- package/dist/adapters/dom/index.js +3 -0
- package/dist/adapters/dom/index.js.map +1 -0
- package/dist/adapters/dom/node-metadata.d.ts +18 -0
- package/dist/adapters/dom/node-metadata.d.ts.map +1 -0
- package/dist/adapters/dom/node-metadata.js +146 -0
- package/dist/adapters/dom/node-metadata.js.map +1 -0
- package/dist/adapters/dom/renderer.d.ts +6 -0
- package/dist/adapters/dom/renderer.d.ts.map +1 -0
- package/dist/adapters/dom/renderer.js +748 -0
- package/dist/adapters/dom/renderer.js.map +1 -0
- package/dist/adapters/ssr/index.d.ts +3 -0
- package/dist/adapters/ssr/index.d.ts.map +1 -0
- package/dist/adapters/ssr/index.js +2 -0
- package/dist/adapters/ssr/index.js.map +1 -0
- package/dist/adapters/ssr/renderer.d.ts +9 -0
- package/dist/adapters/ssr/renderer.d.ts.map +1 -0
- package/dist/adapters/ssr/renderer.js +294 -0
- package/dist/adapters/ssr/renderer.js.map +1 -0
- package/dist/compiler/index.d.ts +2 -0
- package/dist/compiler/index.d.ts.map +1 -0
- package/dist/compiler/index.js +2 -0
- package/dist/compiler/index.js.map +1 -0
- package/dist/compiler/jsx.d.ts +10 -0
- package/dist/compiler/jsx.d.ts.map +1 -0
- package/dist/compiler/jsx.js +48 -0
- package/dist/compiler/jsx.js.map +1 -0
- package/dist/components/button.d.ts +12 -0
- package/dist/components/button.d.ts.map +1 -0
- package/dist/components/button.js +11 -0
- package/dist/components/button.js.map +1 -0
- package/dist/components/index.d.ts +9 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +5 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/input.d.ts +22 -0
- package/dist/components/input.d.ts.map +1 -0
- package/dist/components/input.js +44 -0
- package/dist/components/input.js.map +1 -0
- package/dist/components/list.d.ts +18 -0
- package/dist/components/list.d.ts.map +1 -0
- package/dist/components/list.js +46 -0
- package/dist/components/list.js.map +1 -0
- package/dist/components/portal.d.ts +7 -0
- package/dist/components/portal.d.ts.map +1 -0
- package/dist/components/portal.js +30 -0
- package/dist/components/portal.js.map +1 -0
- package/dist/core/context.d.ts +13 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +46 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/h.d.ts +4 -0
- package/dist/core/h.d.ts.map +1 -0
- package/dist/core/h.js +23 -0
- package/dist/core/h.js.map +1 -0
- package/dist/core/index.d.ts +14 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +10 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/lifecycle.d.ts +11 -0
- package/dist/core/lifecycle.d.ts.map +1 -0
- package/dist/core/lifecycle.js +62 -0
- package/dist/core/lifecycle.js.map +1 -0
- package/dist/core/plugin.d.ts +17 -0
- package/dist/core/plugin.d.ts.map +1 -0
- package/dist/core/plugin.js +117 -0
- package/dist/core/plugin.js.map +1 -0
- package/dist/core/reactive-context.d.ts +20 -0
- package/dist/core/reactive-context.d.ts.map +1 -0
- package/dist/core/reactive-context.js +42 -0
- package/dist/core/reactive-context.js.map +1 -0
- package/dist/core/scheduler.d.ts +13 -0
- package/dist/core/scheduler.d.ts.map +1 -0
- package/dist/core/scheduler.js +80 -0
- package/dist/core/scheduler.js.map +1 -0
- package/dist/core/signal.d.ts +14 -0
- package/dist/core/signal.d.ts.map +1 -0
- package/dist/core/signal.js +397 -0
- package/dist/core/signal.js.map +1 -0
- package/dist/core/store.d.ts +6 -0
- package/dist/core/store.d.ts.map +1 -0
- package/dist/core/store.js +35 -0
- package/dist/core/store.js.map +1 -0
- package/dist/core/types.d.ts +52 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +8 -0
- package/dist/core/types.js.map +1 -0
- package/dist/devtools/index.d.ts +5 -0
- package/dist/devtools/index.d.ts.map +1 -0
- package/dist/devtools/index.js +3 -0
- package/dist/devtools/index.js.map +1 -0
- package/dist/devtools/inspector.d.ts +14 -0
- package/dist/devtools/inspector.d.ts.map +1 -0
- package/dist/devtools/inspector.js +83 -0
- package/dist/devtools/inspector.js.map +1 -0
- package/dist/devtools/logger.d.ts +17 -0
- package/dist/devtools/logger.d.ts.map +1 -0
- package/dist/devtools/logger.js +44 -0
- package/dist/devtools/logger.js.map +1 -0
- package/dist/examples/counter.d.ts +4 -0
- package/dist/examples/counter.d.ts.map +1 -0
- package/dist/examples/counter.js +21 -0
- package/dist/examples/counter.js.map +1 -0
- package/dist/examples/ssr.d.ts +2 -0
- package/dist/examples/ssr.d.ts.map +1 -0
- package/dist/examples/ssr.js +43 -0
- package/dist/examples/ssr.js.map +1 -0
- package/dist/examples/todo.d.ts +4 -0
- package/dist/examples/todo.d.ts.map +1 -0
- package/dist/examples/todo.js +76 -0
- package/dist/examples/todo.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/plugins/index.d.ts +3 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +2 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/router.d.ts +4 -0
- package/dist/plugins/router.d.ts.map +1 -0
- package/dist/plugins/router.js +90 -0
- package/dist/plugins/router.js.map +1 -0
- package/dist/plugins/types.d.ts +17 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +2 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/render/reconciler.d.ts +6 -0
- package/dist/render/reconciler.d.ts.map +1 -0
- package/dist/render/reconciler.js +80 -0
- package/dist/render/reconciler.js.map +1 -0
- package/dist/render/types.d.ts +17 -0
- package/dist/render/types.d.ts.map +1 -0
- package/dist/render/types.js +2 -0
- package/dist/render/types.js.map +1 -0
- package/package.json +99 -0
|
@@ -0,0 +1,748 @@
|
|
|
1
|
+
import { Fragment } from '../../core/types.js';
|
|
2
|
+
import { isSignal, effect } from '../../core/signal.js';
|
|
3
|
+
import { createLifecycleContext, setCurrentLifecycle, } from '../../core/lifecycle.js';
|
|
4
|
+
import { setContextProviders } from '../../core/context.js';
|
|
5
|
+
import { resolveVNode, flattenFragments } from '../../render/reconciler.js';
|
|
6
|
+
import { hydrateVNode } from './hydration.js';
|
|
7
|
+
import { trackEffect, disposeNodeEffects, disposeSubtreeEffects, trackPropEffect as trackPropDispose, disposePropEffect, pushNodeLifecycle, getNodeLifecycle, runNodeUnmountLifecycles, setPortalData, getPortalNodes, getPortalTarget, setResolvedVNode as setNodeResolvedVNode, getResolvedVNode as getNodeResolvedVNode, } from './node-metadata.js';
|
|
8
|
+
function insertNode(parent, node, ref) {
|
|
9
|
+
if (Array.isArray(node)) {
|
|
10
|
+
for (const n of node) {
|
|
11
|
+
parent.insertBefore(n, ref);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
parent.insertBefore(node, ref);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function appendNode(parent, node) {
|
|
19
|
+
if (Array.isArray(node)) {
|
|
20
|
+
for (const n of node) {
|
|
21
|
+
parent.appendChild(n);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
parent.appendChild(node);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function isSignalValue(val) {
|
|
29
|
+
return isSignal(val);
|
|
30
|
+
}
|
|
31
|
+
const DOM_PROP_PROPS = new Set([
|
|
32
|
+
'value', 'checked', 'selected', 'indeterminate',
|
|
33
|
+
]);
|
|
34
|
+
function isDOMProp(el, key) {
|
|
35
|
+
if (!DOM_PROP_PROPS.has(key))
|
|
36
|
+
return false;
|
|
37
|
+
if (key === 'value')
|
|
38
|
+
return el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement;
|
|
39
|
+
if (key === 'checked' || key === 'indeterminate')
|
|
40
|
+
return el instanceof HTMLInputElement;
|
|
41
|
+
if (key === 'selected')
|
|
42
|
+
return el instanceof HTMLOptionElement;
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
function setDOMProp(el, key, value) {
|
|
46
|
+
if (key === 'className' || key === 'class') {
|
|
47
|
+
el.setAttribute('class', String(value ?? ''));
|
|
48
|
+
}
|
|
49
|
+
else if (key === 'style') {
|
|
50
|
+
if (value && typeof value === 'object') {
|
|
51
|
+
Object.assign(el.style, value);
|
|
52
|
+
}
|
|
53
|
+
else if (typeof value === 'string') {
|
|
54
|
+
el.setAttribute('style', value);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else if (key.startsWith('on') && typeof value === 'function') {
|
|
58
|
+
const event = key.slice(2).toLowerCase();
|
|
59
|
+
const handler = value;
|
|
60
|
+
el.addEventListener(event, handler);
|
|
61
|
+
trackPropDispose(el, key, () => {
|
|
62
|
+
el.removeEventListener(event, handler);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
else if (key === 'key') {
|
|
66
|
+
}
|
|
67
|
+
else if (key === 'dangerouslySetInnerHTML') {
|
|
68
|
+
el.innerHTML = value?.__html ?? '';
|
|
69
|
+
}
|
|
70
|
+
else if (isDOMProp(el, key)) {
|
|
71
|
+
if (value != null && value !== false) {
|
|
72
|
+
el[key] = value;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
const empty = key === 'checked' ? false : '';
|
|
76
|
+
el[key] = empty;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else if (value != null && value !== false) {
|
|
80
|
+
el.setAttribute(key, String(value));
|
|
81
|
+
}
|
|
82
|
+
else if (value == null || value === false) {
|
|
83
|
+
el.removeAttribute(key);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function applySignalProp(el, key, signal) {
|
|
87
|
+
disposePropEffect(el, key);
|
|
88
|
+
let prevHandler = null;
|
|
89
|
+
const dispose = effect(() => {
|
|
90
|
+
const val = signal.get();
|
|
91
|
+
if (key.startsWith('on') && typeof val === 'function') {
|
|
92
|
+
const event = key.slice(2).toLowerCase();
|
|
93
|
+
if (prevHandler) {
|
|
94
|
+
el.removeEventListener(event, prevHandler);
|
|
95
|
+
}
|
|
96
|
+
prevHandler = val;
|
|
97
|
+
el.addEventListener(event, prevHandler);
|
|
98
|
+
}
|
|
99
|
+
else if (key === 'className' || key === 'class') {
|
|
100
|
+
el.setAttribute('class', String(val ?? ''));
|
|
101
|
+
}
|
|
102
|
+
else if (key === 'style' && val && typeof val === 'object') {
|
|
103
|
+
Object.assign(el.style, val);
|
|
104
|
+
}
|
|
105
|
+
else if (key === 'style' && typeof val === 'string') {
|
|
106
|
+
el.setAttribute('style', val);
|
|
107
|
+
}
|
|
108
|
+
else if (val != null && val !== false) {
|
|
109
|
+
el.setAttribute(key, String(val));
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
el.removeAttribute(key);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
trackEffect(el, dispose);
|
|
116
|
+
trackPropDispose(el, key, dispose);
|
|
117
|
+
}
|
|
118
|
+
function applyProps(el, props) {
|
|
119
|
+
if (!props)
|
|
120
|
+
return;
|
|
121
|
+
for (const [key, value] of Object.entries(props)) {
|
|
122
|
+
if (key === 'key')
|
|
123
|
+
continue;
|
|
124
|
+
if (isSignalValue(value)) {
|
|
125
|
+
applySignalProp(el, key, value);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
setDOMProp(el, key, value);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function createTextNode(value) {
|
|
133
|
+
const text = document.createTextNode(String(value ?? ''));
|
|
134
|
+
if (isSignalValue(value)) {
|
|
135
|
+
const dispose = effect(() => {
|
|
136
|
+
text.textContent = String(value.get() ?? '');
|
|
137
|
+
});
|
|
138
|
+
trackEffect(text, dispose);
|
|
139
|
+
}
|
|
140
|
+
return text;
|
|
141
|
+
}
|
|
142
|
+
export function createDOMNode(vnode, providers) {
|
|
143
|
+
if (vnode.type === Fragment) {
|
|
144
|
+
const nodes = [];
|
|
145
|
+
try {
|
|
146
|
+
for (const child of vnode.children) {
|
|
147
|
+
const result = createChildNode(child, providers);
|
|
148
|
+
if (result) {
|
|
149
|
+
if (Array.isArray(result))
|
|
150
|
+
nodes.push(...result);
|
|
151
|
+
else
|
|
152
|
+
nodes.push(result);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch (e) {
|
|
157
|
+
for (const n of nodes)
|
|
158
|
+
disposeSubtreeEffects(n);
|
|
159
|
+
throw e;
|
|
160
|
+
}
|
|
161
|
+
return nodes;
|
|
162
|
+
}
|
|
163
|
+
const el = document.createElement(vnode.type);
|
|
164
|
+
applyProps(el, vnode.props);
|
|
165
|
+
if (vnode.props?.ref && typeof vnode.props.ref === 'function') {
|
|
166
|
+
vnode.props.ref(el);
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
for (const child of vnode.children) {
|
|
170
|
+
const result = createChildNode(child, providers);
|
|
171
|
+
if (result) {
|
|
172
|
+
if (Array.isArray(result)) {
|
|
173
|
+
result.forEach((n) => el.appendChild(n));
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
el.appendChild(result);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
catch (e) {
|
|
182
|
+
disposeSubtreeEffects(el);
|
|
183
|
+
if (el.parentNode)
|
|
184
|
+
el.parentNode.removeChild(el);
|
|
185
|
+
throw e;
|
|
186
|
+
}
|
|
187
|
+
return el;
|
|
188
|
+
}
|
|
189
|
+
function mountPortal(vnode, providers) {
|
|
190
|
+
const comp = vnode.type;
|
|
191
|
+
const target = comp.__portalTarget;
|
|
192
|
+
const anchor = document.createComment('portal');
|
|
193
|
+
const lifecycle = createLifecycleContext();
|
|
194
|
+
const prevLifecycle = setCurrentLifecycle(lifecycle);
|
|
195
|
+
const prevProviders = setContextProviders(providers);
|
|
196
|
+
const mountedNodes = [];
|
|
197
|
+
try {
|
|
198
|
+
for (const child of vnode.children) {
|
|
199
|
+
const result = createChildNode(child, providers);
|
|
200
|
+
if (result) {
|
|
201
|
+
if (Array.isArray(result))
|
|
202
|
+
mountedNodes.push(...result);
|
|
203
|
+
else
|
|
204
|
+
mountedNodes.push(result);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
lifecycle.runHook('mount');
|
|
208
|
+
}
|
|
209
|
+
finally {
|
|
210
|
+
setCurrentLifecycle(prevLifecycle);
|
|
211
|
+
setContextProviders(prevProviders);
|
|
212
|
+
}
|
|
213
|
+
if (target && mountedNodes.length > 0) {
|
|
214
|
+
const frag = document.createDocumentFragment();
|
|
215
|
+
for (const n of mountedNodes)
|
|
216
|
+
frag.appendChild(n);
|
|
217
|
+
target.appendChild(frag);
|
|
218
|
+
}
|
|
219
|
+
trackEffect(anchor, () => {
|
|
220
|
+
const nodes = getPortalNodes(anchor) ?? [];
|
|
221
|
+
for (const n of nodes) {
|
|
222
|
+
if (n.parentNode)
|
|
223
|
+
n.parentNode.removeChild(n);
|
|
224
|
+
}
|
|
225
|
+
runNodeUnmountLifecycles(anchor);
|
|
226
|
+
});
|
|
227
|
+
pushNodeLifecycle(anchor, lifecycle);
|
|
228
|
+
setPortalData(anchor, mountedNodes, target);
|
|
229
|
+
return anchor;
|
|
230
|
+
}
|
|
231
|
+
function createChildNode(child, providers) {
|
|
232
|
+
if (child == null || child === false)
|
|
233
|
+
return null;
|
|
234
|
+
if (typeof child === 'string' || typeof child === 'number' || typeof child === 'boolean') {
|
|
235
|
+
return document.createTextNode(String(child));
|
|
236
|
+
}
|
|
237
|
+
if (isSignalValue(child)) {
|
|
238
|
+
const text = document.createTextNode(String(child.get() ?? ''));
|
|
239
|
+
const dispose = effect(() => {
|
|
240
|
+
text.textContent = String(child.get() ?? '');
|
|
241
|
+
});
|
|
242
|
+
trackEffect(text, dispose);
|
|
243
|
+
return text;
|
|
244
|
+
}
|
|
245
|
+
const vnode = child;
|
|
246
|
+
if (typeof vnode.type === 'function') {
|
|
247
|
+
const comp = vnode.type;
|
|
248
|
+
if (comp.__isProvider) {
|
|
249
|
+
const childProviders = (providers ?? []).concat([{
|
|
250
|
+
context: comp.__context,
|
|
251
|
+
value: comp.__value,
|
|
252
|
+
}]);
|
|
253
|
+
const nodes = [];
|
|
254
|
+
for (const childVNode of vnode.children) {
|
|
255
|
+
const result = createChildNode(childVNode, childProviders);
|
|
256
|
+
if (result) {
|
|
257
|
+
if (Array.isArray(result))
|
|
258
|
+
nodes.push(...result);
|
|
259
|
+
else
|
|
260
|
+
nodes.push(result);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return nodes;
|
|
264
|
+
}
|
|
265
|
+
if (comp.__isPortal) {
|
|
266
|
+
return mountPortal(vnode, providers);
|
|
267
|
+
}
|
|
268
|
+
const lifecycle = createLifecycleContext();
|
|
269
|
+
const prevLifecycle = setCurrentLifecycle(lifecycle);
|
|
270
|
+
const prevProviders = setContextProviders(providers);
|
|
271
|
+
try {
|
|
272
|
+
const resolved = resolveVNode(vnode);
|
|
273
|
+
const node = createDOMNode(resolved, providers);
|
|
274
|
+
lifecycle.runHook('mount');
|
|
275
|
+
if (Array.isArray(node)) {
|
|
276
|
+
for (const n of node) {
|
|
277
|
+
pushNodeLifecycle(n, lifecycle);
|
|
278
|
+
setNodeResolvedVNode(n, resolved);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
pushNodeLifecycle(node, lifecycle);
|
|
283
|
+
setNodeResolvedVNode(node, resolved);
|
|
284
|
+
}
|
|
285
|
+
return node;
|
|
286
|
+
}
|
|
287
|
+
finally {
|
|
288
|
+
setCurrentLifecycle(prevLifecycle);
|
|
289
|
+
setContextProviders(prevProviders);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return createDOMNode(vnode, providers);
|
|
293
|
+
}
|
|
294
|
+
function parseVNode(vnode, providers) {
|
|
295
|
+
if (typeof vnode.type === 'function') {
|
|
296
|
+
const comp = vnode.type;
|
|
297
|
+
if (comp.__isProvider) {
|
|
298
|
+
const childProviders = (providers ?? []).concat([{
|
|
299
|
+
context: comp.__context,
|
|
300
|
+
value: comp.__value,
|
|
301
|
+
}]);
|
|
302
|
+
const nodes = [];
|
|
303
|
+
for (const childVNode of vnode.children) {
|
|
304
|
+
const result = createChildNode(childVNode, childProviders);
|
|
305
|
+
if (result) {
|
|
306
|
+
if (Array.isArray(result))
|
|
307
|
+
nodes.push(...result);
|
|
308
|
+
else
|
|
309
|
+
nodes.push(result);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
if (nodes.length === 0)
|
|
313
|
+
return null;
|
|
314
|
+
if (nodes.length === 1)
|
|
315
|
+
return nodes[0];
|
|
316
|
+
const frag = document.createDocumentFragment();
|
|
317
|
+
nodes.forEach((n) => frag.appendChild(n));
|
|
318
|
+
return frag;
|
|
319
|
+
}
|
|
320
|
+
if (comp.__isPortal) {
|
|
321
|
+
return mountPortal(vnode, providers);
|
|
322
|
+
}
|
|
323
|
+
const lifecycle = createLifecycleContext();
|
|
324
|
+
const prevLifecycle = setCurrentLifecycle(lifecycle);
|
|
325
|
+
const prevProviders = setContextProviders(providers);
|
|
326
|
+
try {
|
|
327
|
+
const resolved = resolveVNode(vnode);
|
|
328
|
+
const node = createDOMNode(resolved, providers);
|
|
329
|
+
lifecycle.runHook('mount');
|
|
330
|
+
if (Array.isArray(node)) {
|
|
331
|
+
for (const n of node) {
|
|
332
|
+
pushNodeLifecycle(n, lifecycle);
|
|
333
|
+
setNodeResolvedVNode(n, resolved);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
pushNodeLifecycle(node, lifecycle);
|
|
338
|
+
setNodeResolvedVNode(node, resolved);
|
|
339
|
+
}
|
|
340
|
+
return node;
|
|
341
|
+
}
|
|
342
|
+
finally {
|
|
343
|
+
setCurrentLifecycle(prevLifecycle);
|
|
344
|
+
setContextProviders(prevProviders);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return createDOMNode(vnode, providers);
|
|
348
|
+
}
|
|
349
|
+
function getVNodeKey(child) {
|
|
350
|
+
if (typeof child === 'object' && child !== null && 'key' in child) {
|
|
351
|
+
return child.key;
|
|
352
|
+
}
|
|
353
|
+
return undefined;
|
|
354
|
+
}
|
|
355
|
+
function patchChildInPlace(oldNode, oc, nc, providers) {
|
|
356
|
+
if (typeof oc !== typeof nc) {
|
|
357
|
+
const node = createChildNodeFromVNodeChild(nc, providers);
|
|
358
|
+
if (node && oldNode.parentNode) {
|
|
359
|
+
const parent = oldNode.parentNode;
|
|
360
|
+
const ref = oldNode.nextSibling;
|
|
361
|
+
removeNode(oldNode);
|
|
362
|
+
parent.insertBefore(node, ref);
|
|
363
|
+
}
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
if (typeof nc === 'string' || typeof nc === 'number' || typeof nc === 'boolean') {
|
|
367
|
+
if (String(oc) !== String(nc)) {
|
|
368
|
+
oldNode.textContent = String(nc);
|
|
369
|
+
}
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
if (isSignalValue(oc) && isSignalValue(nc)) {
|
|
373
|
+
disposeNodeEffects(oldNode);
|
|
374
|
+
const dispose = effect(() => {
|
|
375
|
+
oldNode.textContent = String(nc.get() ?? '');
|
|
376
|
+
});
|
|
377
|
+
trackEffect(oldNode, dispose);
|
|
378
|
+
oldNode.textContent = String(nc.get() ?? '');
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
if (isSignalValue(oc) || isSignalValue(nc)) {
|
|
382
|
+
const node = createChildNodeFromVNodeChild(nc, providers);
|
|
383
|
+
if (node && oldNode.parentNode) {
|
|
384
|
+
const parent = oldNode.parentNode;
|
|
385
|
+
const ref = oldNode.nextSibling;
|
|
386
|
+
removeNode(oldNode);
|
|
387
|
+
parent.insertBefore(node, ref);
|
|
388
|
+
}
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
patchNode(oldNode, oc, nc, providers);
|
|
392
|
+
}
|
|
393
|
+
function createNodeInsert(parent, child, ref, providers) {
|
|
394
|
+
const node = createChildNodeFromVNodeChild(child, providers);
|
|
395
|
+
if (!node)
|
|
396
|
+
return null;
|
|
397
|
+
if (Array.isArray(node)) {
|
|
398
|
+
const frag = document.createDocumentFragment();
|
|
399
|
+
node.forEach((n) => frag.appendChild(n));
|
|
400
|
+
parent.insertBefore(frag, ref);
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
parent.insertBefore(node, ref);
|
|
404
|
+
}
|
|
405
|
+
return node instanceof Node ? node : ref;
|
|
406
|
+
}
|
|
407
|
+
function buildOldChildRegistry(parent, oldKids) {
|
|
408
|
+
const keyed = new Map();
|
|
409
|
+
const unkeyed = [];
|
|
410
|
+
let domIdx = 0;
|
|
411
|
+
for (let i = 0; i < oldKids.length; i++) {
|
|
412
|
+
const oc = oldKids[i];
|
|
413
|
+
if (!hasChild(oc))
|
|
414
|
+
continue;
|
|
415
|
+
const node = parent.childNodes[domIdx];
|
|
416
|
+
if (!node)
|
|
417
|
+
continue;
|
|
418
|
+
domIdx++;
|
|
419
|
+
const key = getVNodeKey(oc);
|
|
420
|
+
const entry = { child: oc, node, consumed: false };
|
|
421
|
+
if (key != null) {
|
|
422
|
+
if (keyed.has(key)) {
|
|
423
|
+
console.warn(`[avento] Duplicate key "${key}" found in children. Keys should be unique.`);
|
|
424
|
+
}
|
|
425
|
+
keyed.set(key, entry);
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
unkeyed.push(entry);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return { keyed, unkeyed };
|
|
432
|
+
}
|
|
433
|
+
function reconcileChildren(parent, oldKids, newKids, providers) {
|
|
434
|
+
const { keyed, unkeyed } = buildOldChildRegistry(parent, oldKids);
|
|
435
|
+
let unkeyedIdx = 0;
|
|
436
|
+
let domIdx = 0;
|
|
437
|
+
for (let i = 0; i < newKids.length; i++) {
|
|
438
|
+
const nc = newKids[i];
|
|
439
|
+
if (!hasChild(nc))
|
|
440
|
+
continue;
|
|
441
|
+
const ncKey = getVNodeKey(nc);
|
|
442
|
+
let oldEntry;
|
|
443
|
+
if (ncKey != null) {
|
|
444
|
+
oldEntry = keyed.get(ncKey);
|
|
445
|
+
}
|
|
446
|
+
if (oldEntry && !oldEntry.consumed) {
|
|
447
|
+
oldEntry.consumed = true;
|
|
448
|
+
const currentDomNode = parent.childNodes[domIdx];
|
|
449
|
+
if (oldEntry.node !== currentDomNode) {
|
|
450
|
+
parent.insertBefore(oldEntry.node, currentDomNode ?? null);
|
|
451
|
+
}
|
|
452
|
+
patchChildInPlace(oldEntry.node, oldEntry.child, nc, providers);
|
|
453
|
+
domIdx++;
|
|
454
|
+
}
|
|
455
|
+
else if (!ncKey && unkeyedIdx < unkeyed.length) {
|
|
456
|
+
const entry = unkeyed[unkeyedIdx];
|
|
457
|
+
entry.consumed = true;
|
|
458
|
+
unkeyedIdx++;
|
|
459
|
+
const currentDomNode = parent.childNodes[domIdx];
|
|
460
|
+
if (entry.node !== currentDomNode) {
|
|
461
|
+
parent.insertBefore(entry.node, currentDomNode ?? null);
|
|
462
|
+
}
|
|
463
|
+
patchChildInPlace(entry.node, entry.child, nc, providers);
|
|
464
|
+
domIdx++;
|
|
465
|
+
}
|
|
466
|
+
else {
|
|
467
|
+
const currentDomNode = parent.childNodes[domIdx];
|
|
468
|
+
createNodeInsert(parent, nc, currentDomNode ?? null, providers);
|
|
469
|
+
domIdx++;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
for (const entry of keyed.values()) {
|
|
473
|
+
if (!entry.consumed)
|
|
474
|
+
removeNode(entry.node);
|
|
475
|
+
}
|
|
476
|
+
for (const entry of unkeyed) {
|
|
477
|
+
if (!entry.consumed)
|
|
478
|
+
removeNode(entry.node);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
function hasChild(child) {
|
|
482
|
+
return child != null && child !== false;
|
|
483
|
+
}
|
|
484
|
+
function createChildNodeFromVNodeChild(child, providers) {
|
|
485
|
+
if (child == null || child === false)
|
|
486
|
+
return null;
|
|
487
|
+
if (typeof child === 'string' || typeof child === 'number' || typeof child === 'boolean') {
|
|
488
|
+
return document.createTextNode(String(child));
|
|
489
|
+
}
|
|
490
|
+
if (isSignalValue(child)) {
|
|
491
|
+
const text = document.createTextNode(String(child.get() ?? ''));
|
|
492
|
+
const dispose = effect(() => {
|
|
493
|
+
text.textContent = String(child.get() ?? '');
|
|
494
|
+
});
|
|
495
|
+
trackEffect(text, dispose);
|
|
496
|
+
return text;
|
|
497
|
+
}
|
|
498
|
+
const result = parseVNode(child, providers);
|
|
499
|
+
if (Array.isArray(result)) {
|
|
500
|
+
const frag = document.createDocumentFragment();
|
|
501
|
+
result.forEach((n) => frag.appendChild(n));
|
|
502
|
+
return frag;
|
|
503
|
+
}
|
|
504
|
+
return result;
|
|
505
|
+
}
|
|
506
|
+
function appendChildToParent(parent, child, providers) {
|
|
507
|
+
const node = createChildNodeFromVNodeChild(child, providers);
|
|
508
|
+
if (node)
|
|
509
|
+
parent.appendChild(node);
|
|
510
|
+
}
|
|
511
|
+
function removeNode(node) {
|
|
512
|
+
if (!node?.parentNode)
|
|
513
|
+
return;
|
|
514
|
+
disposeSubtreeEffects(node);
|
|
515
|
+
runNodeUnmountLifecycles(node);
|
|
516
|
+
node.parentNode.removeChild(node);
|
|
517
|
+
}
|
|
518
|
+
function parentNodeForLifecycle(detached, resolved) {
|
|
519
|
+
if (detached.parentNode)
|
|
520
|
+
return detached;
|
|
521
|
+
if (resolved.type === Fragment && resolved.children.length > 0) {
|
|
522
|
+
const first = resolved.children[0];
|
|
523
|
+
if (first && typeof first === 'object' && 'type' in first) {
|
|
524
|
+
return detached;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return detached;
|
|
528
|
+
}
|
|
529
|
+
function patchNode(existingNode, oldVNode, newVNode, providers) {
|
|
530
|
+
if (oldVNode.type !== newVNode.type) {
|
|
531
|
+
const newNode = createChildNodeFromVNodeChild(newVNode, providers);
|
|
532
|
+
if (newNode) {
|
|
533
|
+
const parent = existingNode.parentNode;
|
|
534
|
+
if (parent) {
|
|
535
|
+
const ref = existingNode.nextSibling;
|
|
536
|
+
removeNode(existingNode);
|
|
537
|
+
insertNode(parent, newNode, ref);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
if (newVNode.type === Fragment) {
|
|
543
|
+
reconcileChildren(existingNode.parentNode, flattenFragments(oldVNode.children), flattenFragments(newVNode.children), providers);
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
if (typeof newVNode.type === 'function') {
|
|
547
|
+
const comp = newVNode.type;
|
|
548
|
+
if (comp.__isProvider) {
|
|
549
|
+
const childProviders = (providers ?? []).concat([{
|
|
550
|
+
context: comp.__context,
|
|
551
|
+
value: comp.__value,
|
|
552
|
+
}]);
|
|
553
|
+
if (existingNode.parentNode) {
|
|
554
|
+
reconcileChildren(existingNode.parentNode, [oldVNode], [newVNode], childProviders);
|
|
555
|
+
}
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
if (comp.__isPortal) {
|
|
559
|
+
const oldPortalNodes = getPortalNodes(existingNode);
|
|
560
|
+
const target = getPortalTarget(existingNode) ?? null;
|
|
561
|
+
const lifecycle = createLifecycleContext();
|
|
562
|
+
const prevLifecycle = setCurrentLifecycle(lifecycle);
|
|
563
|
+
const prevProviders = setContextProviders(providers);
|
|
564
|
+
try {
|
|
565
|
+
const newLifecycle = createLifecycleContext();
|
|
566
|
+
const prev2 = setCurrentLifecycle(newLifecycle);
|
|
567
|
+
const newNodes = [];
|
|
568
|
+
for (const child of newVNode.children) {
|
|
569
|
+
const result = createChildNode(child, providers);
|
|
570
|
+
if (result) {
|
|
571
|
+
if (Array.isArray(result))
|
|
572
|
+
newNodes.push(...result);
|
|
573
|
+
else
|
|
574
|
+
newNodes.push(result);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
setCurrentLifecycle(prev2);
|
|
578
|
+
newLifecycle.runHook('update');
|
|
579
|
+
if (oldPortalNodes) {
|
|
580
|
+
for (const n of oldPortalNodes) {
|
|
581
|
+
if (n.parentNode)
|
|
582
|
+
n.parentNode.removeChild(n);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
if (target && newNodes.length > 0) {
|
|
586
|
+
const frag = document.createDocumentFragment();
|
|
587
|
+
for (const n of newNodes)
|
|
588
|
+
frag.appendChild(n);
|
|
589
|
+
target.appendChild(frag);
|
|
590
|
+
}
|
|
591
|
+
runNodeUnmountLifecycles(existingNode);
|
|
592
|
+
pushNodeLifecycle(existingNode, newLifecycle);
|
|
593
|
+
setPortalData(existingNode, newNodes, target);
|
|
594
|
+
}
|
|
595
|
+
finally {
|
|
596
|
+
setCurrentLifecycle(prevLifecycle);
|
|
597
|
+
setContextProviders(prevProviders);
|
|
598
|
+
}
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
const oldLifecycle = getNodeLifecycle(existingNode);
|
|
602
|
+
const prevProviders = setContextProviders(providers);
|
|
603
|
+
try {
|
|
604
|
+
const oldResolved = getNodeResolvedVNode(existingNode);
|
|
605
|
+
const newResolved = resolveVNode(newVNode);
|
|
606
|
+
if (oldResolved &&
|
|
607
|
+
typeof oldResolved.type === 'string' &&
|
|
608
|
+
oldResolved.type === newResolved.type) {
|
|
609
|
+
const prevLifecycle = setCurrentLifecycle(oldLifecycle ?? null);
|
|
610
|
+
try {
|
|
611
|
+
patchNode(existingNode, oldResolved, newResolved, providers);
|
|
612
|
+
const hostNode = existingNode.parentNode ? existingNode : parentNodeForLifecycle(existingNode, newResolved);
|
|
613
|
+
setNodeResolvedVNode(hostNode, newResolved);
|
|
614
|
+
if (oldLifecycle) {
|
|
615
|
+
oldLifecycle.runHook('update');
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
finally {
|
|
619
|
+
setCurrentLifecycle(prevLifecycle);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
else {
|
|
623
|
+
const lifecycle = createLifecycleContext();
|
|
624
|
+
const prevLifecycle = setCurrentLifecycle(lifecycle);
|
|
625
|
+
try {
|
|
626
|
+
const newEl = createDOMNode(newResolved, providers);
|
|
627
|
+
lifecycle.runHook('mount');
|
|
628
|
+
const parent = existingNode.parentNode;
|
|
629
|
+
if (parent) {
|
|
630
|
+
const ref = existingNode.nextSibling;
|
|
631
|
+
removeNode(existingNode);
|
|
632
|
+
insertNode(parent, newEl, ref);
|
|
633
|
+
}
|
|
634
|
+
if (Array.isArray(newEl)) {
|
|
635
|
+
for (const n of newEl) {
|
|
636
|
+
pushNodeLifecycle(n, lifecycle);
|
|
637
|
+
setNodeResolvedVNode(n, newResolved);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
else {
|
|
641
|
+
pushNodeLifecycle(newEl, lifecycle);
|
|
642
|
+
setNodeResolvedVNode(newEl, newResolved);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
finally {
|
|
646
|
+
setCurrentLifecycle(prevLifecycle);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
finally {
|
|
651
|
+
setContextProviders(prevProviders);
|
|
652
|
+
}
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
const el = existingNode;
|
|
656
|
+
if (newVNode.props) {
|
|
657
|
+
const mergedProps = { ...oldVNode.props, ...newVNode.props };
|
|
658
|
+
for (const key of Object.keys(mergedProps)) {
|
|
659
|
+
const oldVal = oldVNode.props?.[key];
|
|
660
|
+
const newVal = newVNode.props?.[key];
|
|
661
|
+
if (Object.is(oldVal, newVal))
|
|
662
|
+
continue;
|
|
663
|
+
if (newVal == null || newVal === false || newVal === undefined) {
|
|
664
|
+
disposePropEffect(el, key);
|
|
665
|
+
if (oldVal != null && oldVal !== false && oldVal !== undefined) {
|
|
666
|
+
if (key.startsWith('on')) {
|
|
667
|
+
const event = key.slice(2).toLowerCase();
|
|
668
|
+
el.removeEventListener(event, oldVal);
|
|
669
|
+
}
|
|
670
|
+
else if (key !== 'key' && key !== 'dangerouslySetInnerHTML') {
|
|
671
|
+
el.removeAttribute(key);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
else if (isSignalValue(newVal)) {
|
|
676
|
+
applySignalProp(el, key, newVal);
|
|
677
|
+
}
|
|
678
|
+
else {
|
|
679
|
+
disposePropEffect(el, key);
|
|
680
|
+
setDOMProp(el, key, newVal);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
reconcileChildren(el, oldVNode.children, newVNode.children, providers);
|
|
685
|
+
const lifecycle = getNodeLifecycle(el);
|
|
686
|
+
if (lifecycle) {
|
|
687
|
+
lifecycle.runHook('update');
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
export function mount(vnode, container) {
|
|
691
|
+
const providers = [];
|
|
692
|
+
let lastVNode = null;
|
|
693
|
+
let rootNodes = [];
|
|
694
|
+
function doFullRender(vnode) {
|
|
695
|
+
disposeSubtreeEffects(container);
|
|
696
|
+
container.innerHTML = '';
|
|
697
|
+
rootNodes = [];
|
|
698
|
+
const result = parseVNode(vnode, providers);
|
|
699
|
+
if (Array.isArray(result)) {
|
|
700
|
+
result.forEach((n) => { container.appendChild(n); rootNodes.push(n); });
|
|
701
|
+
}
|
|
702
|
+
else if (result) {
|
|
703
|
+
container.appendChild(result);
|
|
704
|
+
rootNodes.push(result);
|
|
705
|
+
}
|
|
706
|
+
lastVNode = vnode;
|
|
707
|
+
}
|
|
708
|
+
// Perform the initial render immediately so that container.firstElementChild
|
|
709
|
+
// is available right after mount() returns, before any explicit inst.render() calls.
|
|
710
|
+
doFullRender(vnode);
|
|
711
|
+
const instance = {
|
|
712
|
+
render(vnode) {
|
|
713
|
+
if (!lastVNode || rootNodes.length === 0) {
|
|
714
|
+
doFullRender(vnode);
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
const oldType = lastVNode.type;
|
|
718
|
+
const newType = vnode.type;
|
|
719
|
+
if (oldType !== newType) {
|
|
720
|
+
doFullRender(vnode);
|
|
721
|
+
return;
|
|
722
|
+
}
|
|
723
|
+
if (newType === Fragment) {
|
|
724
|
+
reconcileChildren(container, flattenFragments(lastVNode.children), flattenFragments(vnode.children), providers);
|
|
725
|
+
rootNodes = [...container.childNodes];
|
|
726
|
+
lastVNode = vnode;
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
// Same element type — patch in place
|
|
730
|
+
const root = rootNodes[0];
|
|
731
|
+
if (root && root.parentNode) {
|
|
732
|
+
patchNode(root, lastVNode, vnode, providers);
|
|
733
|
+
}
|
|
734
|
+
lastVNode = vnode;
|
|
735
|
+
},
|
|
736
|
+
hydrate(vnode) {
|
|
737
|
+
hydrateVNode(vnode, container, providers);
|
|
738
|
+
},
|
|
739
|
+
destroy() {
|
|
740
|
+
disposeSubtreeEffects(container);
|
|
741
|
+
container.innerHTML = '';
|
|
742
|
+
lastVNode = null;
|
|
743
|
+
rootNodes = [];
|
|
744
|
+
},
|
|
745
|
+
};
|
|
746
|
+
return instance;
|
|
747
|
+
}
|
|
748
|
+
//# sourceMappingURL=renderer.js.map
|