what-core 0.5.6 → 0.6.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/README.md +8 -6
- package/dist/components.js +1 -1
- package/dist/dom.js +127 -451
- package/dist/h.js +1 -1
- package/dist/hooks.js +4 -0
- package/dist/index.js +5919 -123
- package/dist/index.js.map +7 -0
- package/dist/index.min.js +123 -0
- package/dist/index.min.js.map +7 -0
- package/dist/jsx-dev-runtime.js +51 -0
- package/dist/jsx-dev-runtime.js.map +7 -0
- package/dist/jsx-dev-runtime.min.js +2 -0
- package/dist/jsx-dev-runtime.min.js.map +7 -0
- package/dist/jsx-runtime.js +49 -0
- package/dist/jsx-runtime.js.map +7 -0
- package/dist/jsx-runtime.min.js +2 -0
- package/dist/jsx-runtime.min.js.map +7 -0
- package/dist/reactive.js +175 -11
- package/dist/render.js +1502 -273
- package/dist/render.js.map +7 -0
- package/dist/render.min.js +2 -0
- package/dist/render.min.js.map +7 -0
- package/dist/testing.js +1204 -144
- package/dist/testing.js.map +7 -0
- package/dist/testing.min.js +2 -0
- package/dist/testing.min.js.map +7 -0
- package/dist/what.js +3 -2
- package/package.json +9 -4
- package/src/agent-context.js +126 -0
- package/src/components.js +10 -34
- package/src/dom.js +225 -745
- package/src/errors.js +253 -0
- package/src/guardrails.js +224 -0
- package/src/h.js +3 -3
- package/src/hooks.js +121 -52
- package/src/index.js +38 -4
- package/src/reactive.js +389 -41
- package/src/render.js +445 -14
- package/src/testing.js +169 -1
- package/src/warnings.js +110 -0
package/dist/dom.js
CHANGED
|
@@ -1,13 +1,6 @@
|
|
|
1
|
-
import { effect, batch, untrack, signal } from './reactive.js';
|
|
2
|
-
import { reportError, _injectGetCurrentComponent } from './components.js';
|
|
1
|
+
import { effect, batch, untrack, signal, __DEV__, __devtools } from './reactive.js';
|
|
2
|
+
import { reportError, _injectGetCurrentComponent, shallowEqual } from './components.js';
|
|
3
3
|
import { _setComponentRef } from './helpers.js';
|
|
4
|
-
if (typeof customElements !== 'undefined' && !customElements.get('what-c')) {
|
|
5
|
-
customElements.define('what-c', class extends HTMLElement {
|
|
6
|
-
connectedCallback() {
|
|
7
|
-
this.style.display = 'contents';
|
|
8
|
-
}
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
4
|
const SVG_ELEMENTS = new Set([
|
|
12
5
|
'svg', 'path', 'circle', 'rect', 'line', 'polyline', 'polygon', 'ellipse',
|
|
13
6
|
'g', 'defs', 'use', 'symbol', 'clipPath', 'mask', 'pattern', 'image',
|
|
@@ -31,9 +24,21 @@ return !!value && typeof value === 'object' && (value._vnode === true || 'tag' i
|
|
|
31
24
|
function disposeComponent(ctx) {
|
|
32
25
|
if (ctx.disposed) return;
|
|
33
26
|
ctx.disposed = true;
|
|
27
|
+
if (ctx.cleanups) {
|
|
28
|
+
for (const cleanup of ctx.cleanups) {
|
|
29
|
+
try { cleanup(); } catch (e) { console.error('[what] cleanup error:', e); }
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (ctx.effects) {
|
|
33
|
+
for (const dispose of ctx.effects) {
|
|
34
|
+
try { dispose(); } catch (e) { }
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (ctx.hooks) {
|
|
34
38
|
for (const hook of ctx.hooks) {
|
|
35
|
-
if (hook && typeof hook === '
|
|
36
|
-
try { hook.cleanup(); } catch (e) { console.error('[what] cleanup error:', e); }
|
|
39
|
+
if (hook && typeof hook.cleanup === 'function') {
|
|
40
|
+
try { hook.cleanup(); } catch (e) { console.error('[what] hook cleanup error:', e); }
|
|
41
|
+
}
|
|
37
42
|
}
|
|
38
43
|
}
|
|
39
44
|
if (ctx._cleanupCallbacks) {
|
|
@@ -41,9 +46,7 @@ for (const fn of ctx._cleanupCallbacks) {
|
|
|
41
46
|
try { fn(); } catch (e) { console.error('[what] onCleanup error:', e); }
|
|
42
47
|
}
|
|
43
48
|
}
|
|
44
|
-
|
|
45
|
-
try { dispose(); } catch (e) { }
|
|
46
|
-
}
|
|
49
|
+
if (__DEV__ && __devtools?.onComponentUnmount) __devtools.onComponentUnmount(ctx);
|
|
47
50
|
mountedComponents.delete(ctx);
|
|
48
51
|
}
|
|
49
52
|
export function disposeTree(node) {
|
|
@@ -54,6 +57,11 @@ disposeComponent(node._componentCtx);
|
|
|
54
57
|
if (node._dispose) {
|
|
55
58
|
try { node._dispose(); } catch (e) { }
|
|
56
59
|
}
|
|
60
|
+
if (node._propEffects) {
|
|
61
|
+
for (const key in node._propEffects) {
|
|
62
|
+
try { node._propEffects[key](); } catch (e) { }
|
|
63
|
+
}
|
|
64
|
+
}
|
|
57
65
|
if (node.childNodes) {
|
|
58
66
|
for (const child of node.childNodes) {
|
|
59
67
|
disposeTree(child);
|
|
@@ -84,25 +92,29 @@ if (isDomNode(vnode)) {
|
|
|
84
92
|
return vnode;
|
|
85
93
|
}
|
|
86
94
|
if (typeof vnode === 'function') {
|
|
87
|
-
const
|
|
88
|
-
|
|
95
|
+
const container = document.createDocumentFragment ? document.createElement('span') : document.createElement('span');
|
|
96
|
+
container.style.display = 'contents';
|
|
97
|
+
let currentNodes = [];
|
|
89
98
|
const dispose = effect(() => {
|
|
90
99
|
const val = vnode();
|
|
91
100
|
const vnodes = (val == null || val === false || val === true)
|
|
92
101
|
? []
|
|
93
102
|
: Array.isArray(val) ? val : [val];
|
|
94
|
-
|
|
95
|
-
|
|
103
|
+
for (const old of currentNodes) {
|
|
104
|
+
disposeTree(old);
|
|
105
|
+
if (old.parentNode === container) container.removeChild(old);
|
|
106
|
+
}
|
|
107
|
+
currentNodes = [];
|
|
96
108
|
for (const v of vnodes) {
|
|
97
|
-
const node = createDOM(v,
|
|
98
|
-
if (node)
|
|
109
|
+
const node = createDOM(v, container, parent?._isSvg);
|
|
110
|
+
if (node) {
|
|
111
|
+
container.appendChild(node);
|
|
112
|
+
currentNodes.push(node);
|
|
99
113
|
}
|
|
100
|
-
} else {
|
|
101
|
-
reconcileChildren(wrapper, vnodes);
|
|
102
114
|
}
|
|
103
115
|
});
|
|
104
|
-
|
|
105
|
-
return
|
|
116
|
+
container._dispose = dispose;
|
|
117
|
+
return container;
|
|
106
118
|
}
|
|
107
119
|
if (Array.isArray(vnode)) {
|
|
108
120
|
const frag = document.createDocumentFragment();
|
|
@@ -112,29 +124,13 @@ if (node) frag.appendChild(node);
|
|
|
112
124
|
}
|
|
113
125
|
return frag;
|
|
114
126
|
}
|
|
115
|
-
if (
|
|
116
|
-
return document.createTextNode(String(vnode));
|
|
117
|
-
}
|
|
118
|
-
if (typeof vnode.tag === 'function') {
|
|
127
|
+
if (isVNode(vnode) && typeof vnode.tag === 'function') {
|
|
119
128
|
return createComponent(vnode, parent, isSvg);
|
|
120
129
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
? document.createElementNS(SVG_NS, vnode.tag)
|
|
124
|
-
: document.createElement(vnode.tag);
|
|
125
|
-
applyProps(el, vnode.props, {}, svgContext);
|
|
126
|
-
const hasRawHtml = vnode.props && (
|
|
127
|
-
Object.prototype.hasOwnProperty.call(vnode.props, 'dangerouslySetInnerHTML') ||
|
|
128
|
-
Object.prototype.hasOwnProperty.call(vnode.props, 'innerHTML')
|
|
129
|
-
);
|
|
130
|
-
if (!hasRawHtml) {
|
|
131
|
-
for (const child of vnode.children) {
|
|
132
|
-
const node = createDOM(child, el, svgContext && vnode.tag !== 'foreignObject');
|
|
133
|
-
if (node) el.appendChild(node);
|
|
134
|
-
}
|
|
130
|
+
if (isVNode(vnode)) {
|
|
131
|
+
return createElementFromVNode(vnode, parent, isSvg);
|
|
135
132
|
}
|
|
136
|
-
|
|
137
|
-
return el;
|
|
133
|
+
return document.createTextNode(String(vnode));
|
|
138
134
|
}
|
|
139
135
|
const componentStack = [];
|
|
140
136
|
export function getCurrentComponent() {
|
|
@@ -146,7 +142,16 @@ export function getComponentStack() {
|
|
|
146
142
|
return componentStack;
|
|
147
143
|
}
|
|
148
144
|
function createComponent(vnode, parent, isSvg) {
|
|
149
|
-
|
|
145
|
+
let { tag: Component, props, children } = vnode;
|
|
146
|
+
if (typeof Component === 'function' &&
|
|
147
|
+
(Component.prototype?.isReactComponent || Component.prototype?.render)) {
|
|
148
|
+
const ClassComp = Component;
|
|
149
|
+
Component = function ClassComponentBridge(props) {
|
|
150
|
+
const instance = new ClassComp(props);
|
|
151
|
+
return instance.render();
|
|
152
|
+
};
|
|
153
|
+
Component.displayName = ClassComp.displayName || ClassComp.name || 'ClassComponent';
|
|
154
|
+
}
|
|
150
155
|
if (Component === '__errorBoundary' || vnode.tag === '__errorBoundary') {
|
|
151
156
|
return createErrorBoundary(vnode, parent);
|
|
152
157
|
}
|
|
@@ -154,7 +159,7 @@ if (Component === '__suspense' || vnode.tag === '__suspense') {
|
|
|
154
159
|
return createSuspenseBoundary(vnode, parent);
|
|
155
160
|
}
|
|
156
161
|
if (Component === '__portal' || vnode.tag === '__portal') {
|
|
157
|
-
return
|
|
162
|
+
return createPortalDOM(vnode, parent);
|
|
158
163
|
}
|
|
159
164
|
const ctx = {
|
|
160
165
|
hooks: [],
|
|
@@ -163,7 +168,7 @@ effects: [],
|
|
|
163
168
|
cleanups: [],
|
|
164
169
|
mounted: false,
|
|
165
170
|
disposed: false,
|
|
166
|
-
Component,
|
|
171
|
+
Component,
|
|
167
172
|
_parentCtx: componentStack[componentStack.length - 1] || null,
|
|
168
173
|
_errorBoundary: (() => {
|
|
169
174
|
let p = componentStack[componentStack.length - 1];
|
|
@@ -174,21 +179,16 @@ p = p._parentCtx;
|
|
|
174
179
|
return null;
|
|
175
180
|
})()
|
|
176
181
|
};
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
183
|
-
wrapper._componentCtx = ctx;
|
|
184
|
-
wrapper._isSvg = !!isSvg;
|
|
185
|
-
ctx._wrapper = wrapper;
|
|
182
|
+
const container = document.createElement('span');
|
|
183
|
+
container.style.display = 'contents';
|
|
184
|
+
container._componentCtx = ctx;
|
|
185
|
+
container._isSvg = !!isSvg;
|
|
186
|
+
ctx._wrapper = container;
|
|
186
187
|
mountedComponents.add(ctx);
|
|
187
|
-
|
|
188
|
+
if (__DEV__ && __devtools?.onComponentMount) __devtools.onComponentMount(ctx);
|
|
189
|
+
const propsChildren = children.length === 0 ? undefined : children.length === 1 ? children[0] : children;
|
|
190
|
+
const propsSignal = signal({ ...props, children: propsChildren });
|
|
188
191
|
ctx._propsSignal = propsSignal;
|
|
189
|
-
const dispose = effect(() => {
|
|
190
|
-
if (ctx.disposed) return;
|
|
191
|
-
ctx.hookIndex = 0;
|
|
192
192
|
componentStack.push(ctx);
|
|
193
193
|
let result;
|
|
194
194
|
try {
|
|
@@ -199,11 +199,9 @@ if (!reportError(error, ctx)) {
|
|
|
199
199
|
console.error('[what] Uncaught error in component:', Component.name || 'Anonymous', error);
|
|
200
200
|
throw error;
|
|
201
201
|
}
|
|
202
|
-
return;
|
|
202
|
+
return container;
|
|
203
203
|
}
|
|
204
204
|
componentStack.pop();
|
|
205
|
-
const vnodes = Array.isArray(result) ? result : [result];
|
|
206
|
-
if (!ctx.mounted) {
|
|
207
205
|
ctx.mounted = true;
|
|
208
206
|
if (ctx._mountCallbacks) {
|
|
209
207
|
queueMicrotask(() => {
|
|
@@ -213,22 +211,18 @@ try { fn(); } catch (e) { console.error('[what] onMount error:', e); }
|
|
|
213
211
|
}
|
|
214
212
|
});
|
|
215
213
|
}
|
|
214
|
+
const vnodes = Array.isArray(result) ? result : [result];
|
|
216
215
|
for (const v of vnodes) {
|
|
217
|
-
const node = createDOM(v,
|
|
218
|
-
if (node)
|
|
219
|
-
}
|
|
220
|
-
} else {
|
|
221
|
-
reconcileChildren(wrapper, vnodes);
|
|
216
|
+
const node = createDOM(v, container, isSvg);
|
|
217
|
+
if (node) container.appendChild(node);
|
|
222
218
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
wrapper._vnode = vnode;
|
|
226
|
-
return wrapper;
|
|
219
|
+
container._vnode = vnode;
|
|
220
|
+
return container;
|
|
227
221
|
}
|
|
228
222
|
function createErrorBoundary(vnode, parent) {
|
|
229
223
|
const { errorState, handleError, fallback, reset } = vnode.props;
|
|
230
224
|
const children = vnode.children;
|
|
231
|
-
const wrapper = document.createElement('
|
|
225
|
+
const wrapper = document.createElement('span');
|
|
232
226
|
wrapper.style.display = 'contents';
|
|
233
227
|
const boundaryCtx = {
|
|
234
228
|
hooks: [], hookIndex: 0, effects: [], cleanups: [],
|
|
@@ -240,22 +234,22 @@ wrapper._componentCtx = boundaryCtx;
|
|
|
240
234
|
const dispose = effect(() => {
|
|
241
235
|
const error = errorState();
|
|
242
236
|
componentStack.push(boundaryCtx);
|
|
237
|
+
while (wrapper.firstChild) {
|
|
238
|
+
disposeTree(wrapper.firstChild);
|
|
239
|
+
wrapper.removeChild(wrapper.firstChild);
|
|
240
|
+
}
|
|
243
241
|
let vnodes;
|
|
244
242
|
if (error) {
|
|
245
243
|
vnodes = typeof fallback === 'function' ? [fallback({ error, reset })] : [fallback];
|
|
246
244
|
} else {
|
|
247
245
|
vnodes = children;
|
|
248
246
|
}
|
|
249
|
-
componentStack.pop();
|
|
250
247
|
vnodes = Array.isArray(vnodes) ? vnodes : [vnodes];
|
|
251
|
-
if (wrapper.childNodes.length === 0) {
|
|
252
248
|
for (const v of vnodes) {
|
|
253
249
|
const node = createDOM(v, wrapper);
|
|
254
250
|
if (node) wrapper.appendChild(node);
|
|
255
251
|
}
|
|
256
|
-
|
|
257
|
-
reconcileChildren(wrapper, vnodes);
|
|
258
|
-
}
|
|
252
|
+
componentStack.pop();
|
|
259
253
|
});
|
|
260
254
|
boundaryCtx.effects.push(dispose);
|
|
261
255
|
return wrapper;
|
|
@@ -263,7 +257,7 @@ return wrapper;
|
|
|
263
257
|
function createSuspenseBoundary(vnode, parent) {
|
|
264
258
|
const { boundary, fallback, loading } = vnode.props;
|
|
265
259
|
const children = vnode.children;
|
|
266
|
-
const wrapper = document.createElement('
|
|
260
|
+
const wrapper = document.createElement('span');
|
|
267
261
|
wrapper.style.display = 'contents';
|
|
268
262
|
const boundaryCtx = {
|
|
269
263
|
hooks: [], hookIndex: 0, effects: [], cleanups: [],
|
|
@@ -275,19 +269,21 @@ const dispose = effect(() => {
|
|
|
275
269
|
const isLoading = loading();
|
|
276
270
|
const vnodes = isLoading ? [fallback] : children;
|
|
277
271
|
const normalized = Array.isArray(vnodes) ? vnodes : [vnodes];
|
|
278
|
-
|
|
272
|
+
componentStack.push(boundaryCtx);
|
|
273
|
+
while (wrapper.firstChild) {
|
|
274
|
+
disposeTree(wrapper.firstChild);
|
|
275
|
+
wrapper.removeChild(wrapper.firstChild);
|
|
276
|
+
}
|
|
279
277
|
for (const v of normalized) {
|
|
280
278
|
const node = createDOM(v, wrapper);
|
|
281
279
|
if (node) wrapper.appendChild(node);
|
|
282
280
|
}
|
|
283
|
-
|
|
284
|
-
reconcileChildren(wrapper, normalized);
|
|
285
|
-
}
|
|
281
|
+
componentStack.pop();
|
|
286
282
|
});
|
|
287
283
|
boundaryCtx.effects.push(dispose);
|
|
288
284
|
return wrapper;
|
|
289
285
|
}
|
|
290
|
-
function
|
|
286
|
+
function createPortalDOM(vnode, parent) {
|
|
291
287
|
const { container } = vnode.props;
|
|
292
288
|
const children = vnode.children;
|
|
293
289
|
if (!container) {
|
|
@@ -317,365 +313,69 @@ if (node.parentNode) node.parentNode.removeChild(node);
|
|
|
317
313
|
}];
|
|
318
314
|
return placeholder;
|
|
319
315
|
}
|
|
320
|
-
function
|
|
321
|
-
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
function reconcileUnkeyed(parent, oldNodes, newVNodes, beforeMarker) {
|
|
330
|
-
const maxLen = Math.max(oldNodes.length, newVNodes.length);
|
|
331
|
-
const newNodes = [];
|
|
332
|
-
for (let i = 0; i < maxLen; i++) {
|
|
333
|
-
const oldNode = oldNodes[i];
|
|
334
|
-
const newVNode = newVNodes[i];
|
|
335
|
-
if (i >= newVNodes.length) {
|
|
336
|
-
if (oldNode && oldNode.parentNode) {
|
|
337
|
-
disposeTree(oldNode);
|
|
338
|
-
oldNode.parentNode.removeChild(oldNode);
|
|
339
|
-
}
|
|
340
|
-
continue;
|
|
341
|
-
}
|
|
342
|
-
if (i >= oldNodes.length) {
|
|
343
|
-
const node = createDOM(newVNode, parent);
|
|
344
|
-
if (node) {
|
|
345
|
-
const ref = getInsertionRef(oldNodes, beforeMarker);
|
|
346
|
-
parent.insertBefore(node, ref);
|
|
347
|
-
newNodes.push(node);
|
|
348
|
-
}
|
|
349
|
-
continue;
|
|
350
|
-
}
|
|
351
|
-
const patched = patchNode(parent, oldNode, newVNode);
|
|
352
|
-
newNodes.push(patched);
|
|
353
|
-
}
|
|
354
|
-
oldNodes.length = 0;
|
|
355
|
-
oldNodes.push(...newNodes);
|
|
356
|
-
}
|
|
357
|
-
function reconcileKeyed(parent, oldNodes, newVNodes, beforeMarker) {
|
|
358
|
-
const oldKeyMap = new Map();
|
|
359
|
-
for (let i = 0; i < oldNodes.length; i++) {
|
|
360
|
-
const node = oldNodes[i];
|
|
361
|
-
const key = node._vnode?.key;
|
|
362
|
-
if (key != null) {
|
|
363
|
-
oldKeyMap.set(key, { node, index: i });
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
const newNodes = [];
|
|
367
|
-
const newLen = newVNodes.length;
|
|
368
|
-
const sources = new Array(newLen).fill(-1);
|
|
369
|
-
const reused = new Set();
|
|
370
|
-
for (let i = 0; i < newLen; i++) {
|
|
371
|
-
const vnode = newVNodes[i];
|
|
372
|
-
const key = vnode?.key;
|
|
373
|
-
if (key != null && oldKeyMap.has(key)) {
|
|
374
|
-
const { node: oldNode, index: oldIndex } = oldKeyMap.get(key);
|
|
375
|
-
sources[i] = oldIndex;
|
|
376
|
-
reused.add(oldIndex);
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
for (let i = 0; i < oldNodes.length; i++) {
|
|
380
|
-
if (!reused.has(i) && oldNodes[i]?.parentNode) {
|
|
381
|
-
disposeTree(oldNodes[i]);
|
|
382
|
-
oldNodes[i].parentNode.removeChild(oldNodes[i]);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
const filtered = [];
|
|
386
|
-
const filteredToOriginal = [];
|
|
387
|
-
for (let j = 0; j < sources.length; j++) {
|
|
388
|
-
if (sources[j] !== -1) {
|
|
389
|
-
filteredToOriginal.push(j);
|
|
390
|
-
filtered.push(sources[j]);
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
const lis = longestIncreasingSubsequence(filtered);
|
|
394
|
-
const lisSet = new Set(lis.map(i => filteredToOriginal[i]));
|
|
395
|
-
let lastInserted = beforeMarker?.nextSibling || null;
|
|
396
|
-
for (let i = newLen - 1; i >= 0; i--) {
|
|
397
|
-
const vnode = newVNodes[i];
|
|
398
|
-
const key = vnode?.key;
|
|
399
|
-
const oldEntry = key != null ? oldKeyMap.get(key) : null;
|
|
400
|
-
if (oldEntry && sources[i] !== -1) {
|
|
401
|
-
const oldNode = oldEntry.node;
|
|
402
|
-
const patched = patchNode(parent, oldNode, vnode);
|
|
403
|
-
newNodes[i] = patched;
|
|
404
|
-
if (!lisSet.has(i) && patched.parentNode) {
|
|
405
|
-
parent.insertBefore(patched, lastInserted);
|
|
406
|
-
}
|
|
407
|
-
lastInserted = patched;
|
|
408
|
-
} else {
|
|
409
|
-
const node = createDOM(vnode, parent);
|
|
410
|
-
if (node) {
|
|
411
|
-
parent.insertBefore(node, lastInserted);
|
|
412
|
-
lastInserted = node;
|
|
413
|
-
}
|
|
414
|
-
newNodes[i] = node;
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
oldNodes.length = 0;
|
|
418
|
-
oldNodes.push(...newNodes.filter(Boolean));
|
|
419
|
-
}
|
|
420
|
-
function longestIncreasingSubsequence(arr) {
|
|
421
|
-
if (arr.length === 0) return [];
|
|
422
|
-
const n = arr.length;
|
|
423
|
-
const dp = new Array(n).fill(1);
|
|
424
|
-
const parent = new Array(n).fill(-1);
|
|
425
|
-
const tails = [0];
|
|
426
|
-
for (let i = 1; i < n; i++) {
|
|
427
|
-
if (arr[i] > arr[tails[tails.length - 1]]) {
|
|
428
|
-
parent[i] = tails[tails.length - 1];
|
|
429
|
-
tails.push(i);
|
|
430
|
-
} else {
|
|
431
|
-
let lo = 0, hi = tails.length - 1;
|
|
432
|
-
while (lo < hi) {
|
|
433
|
-
const mid = (lo + hi) >> 1;
|
|
434
|
-
if (arr[tails[mid]] < arr[i]) lo = mid + 1;
|
|
435
|
-
else hi = mid;
|
|
436
|
-
}
|
|
437
|
-
if (arr[i] < arr[tails[lo]]) {
|
|
438
|
-
if (lo > 0) parent[i] = tails[lo - 1];
|
|
439
|
-
tails[lo] = i;
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
const result = [];
|
|
444
|
-
let k = tails[tails.length - 1];
|
|
445
|
-
while (k !== -1) {
|
|
446
|
-
result.push(k);
|
|
447
|
-
k = parent[k];
|
|
448
|
-
}
|
|
449
|
-
return result.reverse();
|
|
450
|
-
}
|
|
451
|
-
function getInsertionRef(nodes, marker) {
|
|
452
|
-
if (nodes.length > 0) {
|
|
453
|
-
const last = nodes[nodes.length - 1];
|
|
454
|
-
return last.nextSibling;
|
|
455
|
-
}
|
|
456
|
-
return marker ? marker.nextSibling : null;
|
|
457
|
-
}
|
|
458
|
-
function cleanupArrayMarkers(parent, startMarker) {
|
|
459
|
-
const endMarker = startMarker._arrayEnd;
|
|
460
|
-
if (!endMarker) return null;
|
|
461
|
-
let node = startMarker.nextSibling;
|
|
462
|
-
while (node && node !== endMarker) {
|
|
463
|
-
const next = node.nextSibling;
|
|
464
|
-
disposeTree(node);
|
|
465
|
-
parent.removeChild(node);
|
|
466
|
-
node = next;
|
|
467
|
-
}
|
|
468
|
-
if (endMarker.parentNode) parent.removeChild(endMarker);
|
|
469
|
-
return startMarker;
|
|
470
|
-
}
|
|
471
|
-
function patchNode(parent, domNode, vnode) {
|
|
472
|
-
if (vnode == null || vnode === false || vnode === true) {
|
|
473
|
-
if (domNode && domNode.nodeType === 8 && domNode._arrayEnd) {
|
|
474
|
-
cleanupArrayMarkers(parent, domNode);
|
|
475
|
-
const placeholder = document.createComment('');
|
|
476
|
-
parent.replaceChild(placeholder, domNode);
|
|
477
|
-
return placeholder;
|
|
478
|
-
}
|
|
479
|
-
if (domNode && domNode.nodeType === 8 && !domNode._componentCtx) {
|
|
480
|
-
return domNode;
|
|
481
|
-
}
|
|
482
|
-
const placeholder = document.createComment('');
|
|
483
|
-
if (domNode && domNode.parentNode) {
|
|
484
|
-
disposeTree(domNode);
|
|
485
|
-
parent.replaceChild(placeholder, domNode);
|
|
486
|
-
}
|
|
487
|
-
return placeholder;
|
|
488
|
-
}
|
|
489
|
-
if (typeof vnode === 'function') {
|
|
490
|
-
const wrapper = document.createElement('what-c');
|
|
491
|
-
let mounted = false;
|
|
492
|
-
const dispose = effect(() => {
|
|
493
|
-
const val = vnode();
|
|
494
|
-
const vnodes = (val == null || val === false || val === true)
|
|
495
|
-
? []
|
|
496
|
-
: Array.isArray(val) ? val : [val];
|
|
497
|
-
if (!mounted) {
|
|
498
|
-
mounted = true;
|
|
499
|
-
for (const v of vnodes) {
|
|
500
|
-
const node = createDOM(v, wrapper);
|
|
501
|
-
if (node) wrapper.appendChild(node);
|
|
502
|
-
}
|
|
503
|
-
} else {
|
|
504
|
-
reconcileChildren(wrapper, vnodes);
|
|
505
|
-
}
|
|
506
|
-
});
|
|
507
|
-
wrapper._dispose = dispose;
|
|
508
|
-
if (domNode && domNode.parentNode) {
|
|
509
|
-
disposeTree(domNode);
|
|
510
|
-
parent.replaceChild(wrapper, domNode);
|
|
511
|
-
}
|
|
512
|
-
return wrapper;
|
|
513
|
-
}
|
|
514
|
-
if (isDomNode(vnode)) {
|
|
515
|
-
if (domNode === vnode) return domNode;
|
|
516
|
-
if (domNode && domNode.parentNode) {
|
|
517
|
-
disposeTree(domNode);
|
|
518
|
-
parent.replaceChild(vnode, domNode);
|
|
519
|
-
}
|
|
520
|
-
return vnode;
|
|
521
|
-
}
|
|
522
|
-
if (typeof vnode === 'string' || typeof vnode === 'number') {
|
|
523
|
-
const text = String(vnode);
|
|
524
|
-
if (domNode && domNode.nodeType === 8 && domNode._arrayEnd) {
|
|
525
|
-
cleanupArrayMarkers(parent, domNode);
|
|
526
|
-
const newNode = document.createTextNode(text);
|
|
527
|
-
parent.replaceChild(newNode, domNode);
|
|
528
|
-
return newNode;
|
|
529
|
-
}
|
|
530
|
-
if (domNode.nodeType === 3) {
|
|
531
|
-
if (domNode.textContent !== text) domNode.textContent = text;
|
|
532
|
-
return domNode;
|
|
533
|
-
}
|
|
534
|
-
const newNode = document.createTextNode(text);
|
|
535
|
-
disposeTree(domNode);
|
|
536
|
-
parent.replaceChild(newNode, domNode);
|
|
537
|
-
return newNode;
|
|
538
|
-
}
|
|
539
|
-
if (Array.isArray(vnode)) {
|
|
540
|
-
if (domNode && domNode.nodeType === 8 && domNode._arrayEnd) {
|
|
541
|
-
const endMarker = domNode._arrayEnd;
|
|
542
|
-
const oldChildren = [];
|
|
543
|
-
let node = domNode.nextSibling;
|
|
544
|
-
while (node && node !== endMarker) {
|
|
545
|
-
oldChildren.push(node);
|
|
546
|
-
node = node.nextSibling;
|
|
547
|
-
}
|
|
548
|
-
const maxLen = Math.max(oldChildren.length, vnode.length);
|
|
549
|
-
for (let i = 0; i < maxLen; i++) {
|
|
550
|
-
if (i >= vnode.length) {
|
|
551
|
-
if (oldChildren[i]?.parentNode) {
|
|
552
|
-
disposeTree(oldChildren[i]);
|
|
553
|
-
parent.removeChild(oldChildren[i]);
|
|
554
|
-
}
|
|
555
|
-
} else if (i >= oldChildren.length) {
|
|
556
|
-
const newNode = createDOM(vnode[i], parent);
|
|
557
|
-
if (newNode) parent.insertBefore(newNode, endMarker);
|
|
558
|
-
} else {
|
|
559
|
-
patchNode(parent, oldChildren[i], vnode[i]);
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
return domNode;
|
|
563
|
-
}
|
|
564
|
-
const startMarker = document.createComment('[');
|
|
565
|
-
const endMarker = document.createComment(']');
|
|
566
|
-
disposeTree(domNode);
|
|
567
|
-
parent.replaceChild(endMarker, domNode);
|
|
568
|
-
parent.insertBefore(startMarker, endMarker);
|
|
569
|
-
for (const v of vnode) {
|
|
570
|
-
const node = createDOM(v, parent);
|
|
571
|
-
if (node) parent.insertBefore(node, endMarker);
|
|
572
|
-
}
|
|
573
|
-
startMarker._arrayEnd = endMarker;
|
|
574
|
-
return startMarker;
|
|
575
|
-
}
|
|
576
|
-
if (!isVNode(vnode)) {
|
|
577
|
-
const text = String(vnode);
|
|
578
|
-
if (domNode.nodeType === 3) {
|
|
579
|
-
if (domNode.textContent !== text) domNode.textContent = text;
|
|
580
|
-
return domNode;
|
|
581
|
-
}
|
|
582
|
-
const newNode = document.createTextNode(text);
|
|
583
|
-
disposeTree(domNode);
|
|
584
|
-
parent.replaceChild(newNode, domNode);
|
|
585
|
-
return newNode;
|
|
586
|
-
}
|
|
587
|
-
if (typeof vnode.tag === 'function') {
|
|
588
|
-
if (domNode._componentCtx && !domNode._componentCtx.disposed
|
|
589
|
-
&& domNode._componentCtx.Component === vnode.tag) {
|
|
590
|
-
domNode._componentCtx._propsSignal.set({ ...vnode.props, children: vnode.children });
|
|
591
|
-
domNode._vnode = vnode;
|
|
592
|
-
return domNode;
|
|
593
|
-
}
|
|
594
|
-
disposeTree(domNode);
|
|
595
|
-
const node = createComponent(vnode, parent);
|
|
596
|
-
parent.replaceChild(node, domNode);
|
|
597
|
-
return node;
|
|
598
|
-
}
|
|
599
|
-
if (domNode.nodeType === 1 && domNode.tagName.toLowerCase() === vnode.tag) {
|
|
600
|
-
const oldProps = domNode._vnode?.props || {};
|
|
601
|
-
const nextProps = vnode.props || {};
|
|
602
|
-
const hadRawHtml = Object.prototype.hasOwnProperty.call(oldProps, 'dangerouslySetInnerHTML')
|
|
603
|
-
|| Object.prototype.hasOwnProperty.call(oldProps, 'innerHTML');
|
|
604
|
-
const hasRawHtml = Object.prototype.hasOwnProperty.call(nextProps, 'dangerouslySetInnerHTML')
|
|
605
|
-
|| Object.prototype.hasOwnProperty.call(nextProps, 'innerHTML');
|
|
606
|
-
if (hasRawHtml && !hadRawHtml) {
|
|
607
|
-
for (const child of Array.from(domNode.childNodes)) {
|
|
608
|
-
disposeTree(child);
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
applyProps(domNode, nextProps, oldProps);
|
|
612
|
-
if (!hasRawHtml) {
|
|
613
|
-
reconcileChildren(domNode, vnode.children);
|
|
614
|
-
}
|
|
615
|
-
domNode._vnode = vnode;
|
|
616
|
-
return domNode;
|
|
617
|
-
}
|
|
618
|
-
const newNode = createDOM(vnode, parent);
|
|
619
|
-
disposeTree(domNode);
|
|
620
|
-
parent.replaceChild(newNode, domNode);
|
|
621
|
-
return newNode;
|
|
622
|
-
}
|
|
623
|
-
function reconcileChildren(parent, newChildVNodes) {
|
|
624
|
-
const oldChildren = Array.from(parent.childNodes);
|
|
625
|
-
const hasKeys = newChildVNodes.some(v => v && typeof v === 'object' && v.key != null);
|
|
626
|
-
if (hasKeys) {
|
|
627
|
-
reconcileKeyed(parent, oldChildren, newChildVNodes, null);
|
|
628
|
-
} else {
|
|
629
|
-
const maxLen = Math.max(oldChildren.length, newChildVNodes.length);
|
|
630
|
-
for (let i = 0; i < maxLen; i++) {
|
|
631
|
-
if (i >= newChildVNodes.length) {
|
|
632
|
-
if (oldChildren[i]?.parentNode) {
|
|
633
|
-
disposeTree(oldChildren[i]);
|
|
634
|
-
parent.removeChild(oldChildren[i]);
|
|
635
|
-
}
|
|
636
|
-
continue;
|
|
637
|
-
}
|
|
638
|
-
if (i >= oldChildren.length) {
|
|
639
|
-
const node = createDOM(newChildVNodes[i], parent);
|
|
640
|
-
if (node) parent.appendChild(node);
|
|
641
|
-
continue;
|
|
642
|
-
}
|
|
643
|
-
patchNode(parent, oldChildren[i], newChildVNodes[i]);
|
|
316
|
+
function createElementFromVNode(vnode, parent, isSvg) {
|
|
317
|
+
const { tag, props, children } = vnode;
|
|
318
|
+
const svgContext = isSvg || SVG_ELEMENTS.has(tag);
|
|
319
|
+
const el = svgContext
|
|
320
|
+
? document.createElementNS(SVG_NS, tag)
|
|
321
|
+
: document.createElement(tag);
|
|
322
|
+
if (props) {
|
|
323
|
+
applyProps(el, props, {}, svgContext);
|
|
644
324
|
}
|
|
325
|
+
for (const child of children) {
|
|
326
|
+
const node = createDOM(child, el, svgContext && tag !== 'foreignObject');
|
|
327
|
+
if (node) el.appendChild(node);
|
|
645
328
|
}
|
|
329
|
+
el._vnode = vnode;
|
|
330
|
+
return el;
|
|
646
331
|
}
|
|
647
332
|
function applyProps(el, newProps, oldProps, isSvg) {
|
|
648
333
|
newProps = newProps || {};
|
|
649
334
|
oldProps = oldProps || {};
|
|
650
|
-
for (const key in oldProps) {
|
|
651
|
-
if (key === 'key' || key === 'ref' || key === 'children') continue;
|
|
652
|
-
if (!(key in newProps)) {
|
|
653
|
-
removeProp(el, key, oldProps[key]);
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
335
|
for (const key in newProps) {
|
|
657
|
-
if (key === 'key' || key === '
|
|
658
|
-
if (
|
|
659
|
-
setProp(el, key, newProps[key], isSvg);
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
if (newProps.ref && newProps.ref !== oldProps.ref) {
|
|
336
|
+
if (key === 'key' || key === 'children') continue;
|
|
337
|
+
if (key === 'ref') {
|
|
663
338
|
if (typeof newProps.ref === 'function') newProps.ref(el);
|
|
664
|
-
else newProps.ref.current = el;
|
|
339
|
+
else if (newProps.ref) newProps.ref.current = el;
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
setProp(el, key, newProps[key], isSvg);
|
|
665
343
|
}
|
|
666
344
|
}
|
|
667
345
|
function setProp(el, key, value, isSvg) {
|
|
346
|
+
if (typeof value === 'function' && !(key.startsWith('on') && key.length > 2) && key !== 'ref') {
|
|
347
|
+
if (!el._propEffects) el._propEffects = {};
|
|
348
|
+
if (el._propEffects[key]) {
|
|
349
|
+
try { el._propEffects[key](); } catch (e) { }
|
|
350
|
+
}
|
|
351
|
+
el._propEffects[key] = effect(() => {
|
|
352
|
+
const resolved = value();
|
|
353
|
+
setProp(el, key, resolved, isSvg);
|
|
354
|
+
});
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
668
357
|
if (key.startsWith('on') && key.length > 2) {
|
|
669
|
-
|
|
670
|
-
|
|
358
|
+
let eventName = key.slice(2);
|
|
359
|
+
let useCapture = false;
|
|
360
|
+
if (eventName.endsWith('Capture')) {
|
|
361
|
+
eventName = eventName.slice(0, -7);
|
|
362
|
+
useCapture = true;
|
|
363
|
+
}
|
|
364
|
+
const event = eventName.toLowerCase();
|
|
365
|
+
const storageKey = useCapture ? event + '_capture' : event;
|
|
366
|
+
const old = el._events?.[storageKey];
|
|
671
367
|
if (old && old._original === value) return;
|
|
672
|
-
if (old) el.removeEventListener(event, old);
|
|
368
|
+
if (old) el.removeEventListener(event, old, useCapture);
|
|
369
|
+
if (value == null) return;
|
|
673
370
|
if (!el._events) el._events = {};
|
|
674
|
-
const wrappedHandler = (e) =>
|
|
371
|
+
const wrappedHandler = (e) => {
|
|
372
|
+
if (!e.nativeEvent) e.nativeEvent = e;
|
|
373
|
+
return untrack(() => value(e));
|
|
374
|
+
};
|
|
675
375
|
wrappedHandler._original = value;
|
|
676
|
-
el._events[
|
|
376
|
+
el._events[storageKey] = wrappedHandler;
|
|
677
377
|
const eventOpts = value._eventOpts;
|
|
678
|
-
el.addEventListener(event, wrappedHandler, eventOpts || undefined);
|
|
378
|
+
el.addEventListener(event, wrappedHandler, eventOpts || useCapture || undefined);
|
|
679
379
|
return;
|
|
680
380
|
}
|
|
681
381
|
if (key === 'className' || key === 'class') {
|
|
@@ -736,28 +436,4 @@ el[key] = value;
|
|
|
736
436
|
} else {
|
|
737
437
|
el.setAttribute(key, value);
|
|
738
438
|
}
|
|
739
|
-
}
|
|
740
|
-
function removeProp(el, key, oldValue) {
|
|
741
|
-
if (key.startsWith('on') && key.length > 2) {
|
|
742
|
-
const event = key.slice(2).toLowerCase();
|
|
743
|
-
if (el._events?.[event]) {
|
|
744
|
-
el.removeEventListener(event, el._events[event]);
|
|
745
|
-
delete el._events[event];
|
|
746
|
-
}
|
|
747
|
-
return;
|
|
748
|
-
}
|
|
749
|
-
if (key === 'className' || key === 'class') {
|
|
750
|
-
el.className = '';
|
|
751
|
-
return;
|
|
752
|
-
}
|
|
753
|
-
if (key === 'style') {
|
|
754
|
-
el.style.cssText = '';
|
|
755
|
-
el._prevStyle = null;
|
|
756
|
-
return;
|
|
757
|
-
}
|
|
758
|
-
if (key === 'dangerouslySetInnerHTML' || key === 'innerHTML') {
|
|
759
|
-
el.innerHTML = '';
|
|
760
|
-
return;
|
|
761
|
-
}
|
|
762
|
-
el.removeAttribute(key);
|
|
763
439
|
}
|