what-core 0.4.1 → 0.4.2
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/dist/dom.js +59 -1
- package/package.json +1 -1
- package/src/dom.js +46 -14
package/dist/dom.js
CHANGED
|
@@ -60,12 +60,16 @@ function disposeComponent(ctx) {
|
|
|
60
60
|
mountedComponents.delete(ctx);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
// Dispose all components attached to a DOM subtree
|
|
63
|
+
// Dispose all components and reactive effects attached to a DOM subtree
|
|
64
64
|
function disposeTree(node) {
|
|
65
65
|
if (!node) return;
|
|
66
66
|
if (node._componentCtx) {
|
|
67
67
|
disposeComponent(node._componentCtx);
|
|
68
68
|
}
|
|
69
|
+
// Dispose reactive function child effects ({() => ...} wrappers)
|
|
70
|
+
if (node._dispose) {
|
|
71
|
+
try { node._dispose(); } catch (e) { /* already disposed */ }
|
|
72
|
+
}
|
|
69
73
|
if (node.childNodes) {
|
|
70
74
|
for (const child of node.childNodes) {
|
|
71
75
|
disposeTree(child);
|
|
@@ -101,6 +105,31 @@ function createDOM(vnode, parent, isSvg) {
|
|
|
101
105
|
return document.createTextNode(String(vnode));
|
|
102
106
|
}
|
|
103
107
|
|
|
108
|
+
// Reactive function child — creates a wrapper that updates fine-grained
|
|
109
|
+
// Handles both primitives ({() => count()}) and vnodes ({() => items().map(...)})
|
|
110
|
+
if (typeof vnode === 'function') {
|
|
111
|
+
const wrapper = document.createElement('what-c');
|
|
112
|
+
let mounted = false;
|
|
113
|
+
const dispose = effect(() => {
|
|
114
|
+
const val = vnode();
|
|
115
|
+
// Normalize: null/false/true → empty, primitives and vnodes → array
|
|
116
|
+
const vnodes = (val == null || val === false || val === true)
|
|
117
|
+
? []
|
|
118
|
+
: Array.isArray(val) ? val : [val];
|
|
119
|
+
if (!mounted) {
|
|
120
|
+
mounted = true;
|
|
121
|
+
for (const v of vnodes) {
|
|
122
|
+
const node = createDOM(v, wrapper, parent?._isSvg);
|
|
123
|
+
if (node) wrapper.appendChild(node);
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
reconcileChildren(wrapper, vnodes);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
wrapper._dispose = dispose;
|
|
130
|
+
return wrapper;
|
|
131
|
+
}
|
|
132
|
+
|
|
104
133
|
// Array (fragment)
|
|
105
134
|
if (Array.isArray(vnode)) {
|
|
106
135
|
const frag = document.createDocumentFragment();
|
|
@@ -253,6 +282,7 @@ function createComponent(vnode, parent, isSvg) {
|
|
|
253
282
|
});
|
|
254
283
|
|
|
255
284
|
ctx.effects.push(dispose);
|
|
285
|
+
wrapper._vnode = vnode; // Store vnode for keyed reconciliation
|
|
256
286
|
return wrapper;
|
|
257
287
|
}
|
|
258
288
|
|
|
@@ -615,6 +645,33 @@ function patchNode(parent, domNode, vnode) {
|
|
|
615
645
|
return placeholder;
|
|
616
646
|
}
|
|
617
647
|
|
|
648
|
+
// Reactive function child — replace whatever's there with a reactive wrapper
|
|
649
|
+
if (typeof vnode === 'function') {
|
|
650
|
+
const wrapper = document.createElement('what-c');
|
|
651
|
+
let mounted = false;
|
|
652
|
+
const dispose = effect(() => {
|
|
653
|
+
const val = vnode();
|
|
654
|
+
const vnodes = (val == null || val === false || val === true)
|
|
655
|
+
? []
|
|
656
|
+
: Array.isArray(val) ? val : [val];
|
|
657
|
+
if (!mounted) {
|
|
658
|
+
mounted = true;
|
|
659
|
+
for (const v of vnodes) {
|
|
660
|
+
const node = createDOM(v, wrapper);
|
|
661
|
+
if (node) wrapper.appendChild(node);
|
|
662
|
+
}
|
|
663
|
+
} else {
|
|
664
|
+
reconcileChildren(wrapper, vnodes);
|
|
665
|
+
}
|
|
666
|
+
});
|
|
667
|
+
wrapper._dispose = dispose;
|
|
668
|
+
if (domNode && domNode.parentNode) {
|
|
669
|
+
disposeTree(domNode);
|
|
670
|
+
parent.replaceChild(wrapper, domNode);
|
|
671
|
+
}
|
|
672
|
+
return wrapper;
|
|
673
|
+
}
|
|
674
|
+
|
|
618
675
|
// Text
|
|
619
676
|
if (typeof vnode === 'string' || typeof vnode === 'number') {
|
|
620
677
|
const text = String(vnode);
|
|
@@ -688,6 +745,7 @@ function patchNode(parent, domNode, vnode) {
|
|
|
688
745
|
&& domNode._componentCtx.Component === vnode.tag) {
|
|
689
746
|
// Same component — update props reactively, let its effect re-render
|
|
690
747
|
domNode._componentCtx._propsSignal.set({ ...vnode.props, children: vnode.children });
|
|
748
|
+
domNode._vnode = vnode; // Keep vnode current for keyed reconciliation
|
|
691
749
|
return domNode;
|
|
692
750
|
}
|
|
693
751
|
// Different component or not a component — dispose old, create new
|
package/package.json
CHANGED
package/src/dom.js
CHANGED
|
@@ -60,12 +60,16 @@ function disposeComponent(ctx) {
|
|
|
60
60
|
mountedComponents.delete(ctx);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
// Dispose all components attached to a DOM subtree
|
|
63
|
+
// Dispose all components and reactive effects attached to a DOM subtree
|
|
64
64
|
function disposeTree(node) {
|
|
65
65
|
if (!node) return;
|
|
66
66
|
if (node._componentCtx) {
|
|
67
67
|
disposeComponent(node._componentCtx);
|
|
68
68
|
}
|
|
69
|
+
// Dispose reactive function child effects ({() => ...} wrappers)
|
|
70
|
+
if (node._dispose) {
|
|
71
|
+
try { node._dispose(); } catch (e) { /* already disposed */ }
|
|
72
|
+
}
|
|
69
73
|
if (node.childNodes) {
|
|
70
74
|
for (const child of node.childNodes) {
|
|
71
75
|
disposeTree(child);
|
|
@@ -101,16 +105,29 @@ function createDOM(vnode, parent, isSvg) {
|
|
|
101
105
|
return document.createTextNode(String(vnode));
|
|
102
106
|
}
|
|
103
107
|
|
|
104
|
-
// Reactive function child — creates a
|
|
108
|
+
// Reactive function child — creates a wrapper that updates fine-grained
|
|
109
|
+
// Handles both primitives ({() => count()}) and vnodes ({() => items().map(...)})
|
|
105
110
|
if (typeof vnode === 'function') {
|
|
106
|
-
const
|
|
107
|
-
|
|
111
|
+
const wrapper = document.createElement('what-c');
|
|
112
|
+
let mounted = false;
|
|
113
|
+
const dispose = effect(() => {
|
|
108
114
|
const val = vnode();
|
|
109
|
-
//
|
|
110
|
-
|
|
111
|
-
|
|
115
|
+
// Normalize: null/false/true → empty, primitives and vnodes → array
|
|
116
|
+
const vnodes = (val == null || val === false || val === true)
|
|
117
|
+
? []
|
|
118
|
+
: Array.isArray(val) ? val : [val];
|
|
119
|
+
if (!mounted) {
|
|
120
|
+
mounted = true;
|
|
121
|
+
for (const v of vnodes) {
|
|
122
|
+
const node = createDOM(v, wrapper, parent?._isSvg);
|
|
123
|
+
if (node) wrapper.appendChild(node);
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
reconcileChildren(wrapper, vnodes);
|
|
127
|
+
}
|
|
112
128
|
});
|
|
113
|
-
|
|
129
|
+
wrapper._dispose = dispose;
|
|
130
|
+
return wrapper;
|
|
114
131
|
}
|
|
115
132
|
|
|
116
133
|
// Array (fragment)
|
|
@@ -265,6 +282,7 @@ function createComponent(vnode, parent, isSvg) {
|
|
|
265
282
|
});
|
|
266
283
|
|
|
267
284
|
ctx.effects.push(dispose);
|
|
285
|
+
wrapper._vnode = vnode; // Store vnode for keyed reconciliation
|
|
268
286
|
return wrapper;
|
|
269
287
|
}
|
|
270
288
|
|
|
@@ -627,18 +645,31 @@ function patchNode(parent, domNode, vnode) {
|
|
|
627
645
|
return placeholder;
|
|
628
646
|
}
|
|
629
647
|
|
|
630
|
-
// Reactive function child — replace whatever's there with a reactive
|
|
648
|
+
// Reactive function child — replace whatever's there with a reactive wrapper
|
|
631
649
|
if (typeof vnode === 'function') {
|
|
632
|
-
const
|
|
633
|
-
|
|
650
|
+
const wrapper = document.createElement('what-c');
|
|
651
|
+
let mounted = false;
|
|
652
|
+
const dispose = effect(() => {
|
|
634
653
|
const val = vnode();
|
|
635
|
-
|
|
654
|
+
const vnodes = (val == null || val === false || val === true)
|
|
655
|
+
? []
|
|
656
|
+
: Array.isArray(val) ? val : [val];
|
|
657
|
+
if (!mounted) {
|
|
658
|
+
mounted = true;
|
|
659
|
+
for (const v of vnodes) {
|
|
660
|
+
const node = createDOM(v, wrapper);
|
|
661
|
+
if (node) wrapper.appendChild(node);
|
|
662
|
+
}
|
|
663
|
+
} else {
|
|
664
|
+
reconcileChildren(wrapper, vnodes);
|
|
665
|
+
}
|
|
636
666
|
});
|
|
667
|
+
wrapper._dispose = dispose;
|
|
637
668
|
if (domNode && domNode.parentNode) {
|
|
638
669
|
disposeTree(domNode);
|
|
639
|
-
parent.replaceChild(
|
|
670
|
+
parent.replaceChild(wrapper, domNode);
|
|
640
671
|
}
|
|
641
|
-
return
|
|
672
|
+
return wrapper;
|
|
642
673
|
}
|
|
643
674
|
|
|
644
675
|
// Text
|
|
@@ -714,6 +745,7 @@ function patchNode(parent, domNode, vnode) {
|
|
|
714
745
|
&& domNode._componentCtx.Component === vnode.tag) {
|
|
715
746
|
// Same component — update props reactively, let its effect re-render
|
|
716
747
|
domNode._componentCtx._propsSignal.set({ ...vnode.props, children: vnode.children });
|
|
748
|
+
domNode._vnode = vnode; // Keep vnode current for keyed reconciliation
|
|
717
749
|
return domNode;
|
|
718
750
|
}
|
|
719
751
|
// Different component or not a component — dispose old, create new
|