what-core 0.6.2 → 0.8.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/dist/index.js CHANGED
@@ -11,43 +11,42 @@ var insideComputed = false;
11
11
  var batchDepth = 0;
12
12
  var pendingEffects = [];
13
13
  var pendingNeedSort = false;
14
- var subSetOwner = /* @__PURE__ */ new WeakMap();
15
14
  var NEEDS_UPSTREAM = /* @__PURE__ */ Symbol("needs_upstream");
16
15
  var iterativeEvalStack = null;
17
16
  function signal(initial, debugName) {
18
17
  let value = initial;
19
18
  const subs = /* @__PURE__ */ new Set();
20
- function sig(...args) {
21
- if (args.length === 0) {
22
- if (currentEffect) {
23
- subs.add(currentEffect);
24
- currentEffect.deps.push(subs);
25
- }
26
- return value;
27
- }
19
+ let lastTracked = null;
20
+ let lastTrackedEpoch = 0;
21
+ function _sigWrite(next) {
28
22
  if (__DEV__ && insideComputed) {
29
23
  console.warn(
30
24
  "[what] Signal.set() called inside a computed function. This may cause infinite loops. Use effect() instead." + (debugName ? ` (signal: ${debugName})` : "")
31
25
  );
32
26
  }
33
- const nextVal = typeof args[0] === "function" ? args[0](value) : args[0];
34
- if (Object.is(value, nextVal)) return;
27
+ const nextVal = typeof next === "function" ? next(value) : next;
28
+ if (value === nextVal || value !== value && nextVal !== nextVal) return;
35
29
  value = nextVal;
30
+ lastTracked = null;
36
31
  if (__DEV__ && __devtools) __devtools.onSignalUpdate(sig);
37
32
  if (subs.size > 0) notify(subs);
38
33
  }
39
- sig.set = (next) => {
40
- if (__DEV__ && insideComputed) {
41
- console.warn(
42
- "[what] Signal.set() called inside a computed function. This may cause infinite loops. Use effect() instead." + (debugName ? ` (signal: ${debugName})` : "")
43
- );
34
+ function sig(newVal) {
35
+ if (arguments.length === 0) {
36
+ const ce = currentEffect;
37
+ if (ce !== null) {
38
+ if (ce !== lastTracked || ce._epoch !== lastTrackedEpoch) {
39
+ lastTracked = ce;
40
+ lastTrackedEpoch = ce._epoch;
41
+ subs.add(ce);
42
+ ce.deps.push(subs);
43
+ }
44
+ }
45
+ return value;
44
46
  }
45
- const nextVal = typeof next === "function" ? next(value) : next;
46
- if (Object.is(value, nextVal)) return;
47
- value = nextVal;
48
- if (__DEV__ && __devtools) __devtools.onSignalUpdate(sig);
49
- if (subs.size > 0) notify(subs);
50
- };
47
+ _sigWrite(newVal);
48
+ }
49
+ sig.set = _sigWrite;
51
50
  sig.peek = () => value;
52
51
  sig.subscribe = (fn) => {
53
52
  return effect(() => fn(sig()));
@@ -63,6 +62,8 @@ function signal(initial, debugName) {
63
62
  function computed(fn) {
64
63
  let value, dirty = true;
65
64
  const subs = /* @__PURE__ */ new Set();
65
+ let lastTracked = null;
66
+ let lastTrackedEpoch = 0;
66
67
  const inner = _createEffect(() => {
67
68
  const prevInsideComputed = insideComputed;
68
69
  if (__DEV__) insideComputed = true;
@@ -76,21 +77,27 @@ function computed(fn) {
76
77
  inner._level = 1;
77
78
  inner._computed = true;
78
79
  inner._computedSubs = subs;
79
- subSetOwner.set(subs, inner);
80
+ subs._owner = inner;
80
81
  inner._markDirty = () => {
81
82
  dirty = true;
82
83
  };
83
84
  inner._isDirty = () => dirty;
84
85
  function read() {
85
- if (currentEffect) {
86
- subs.add(currentEffect);
87
- currentEffect.deps.push(subs);
86
+ const ce = currentEffect;
87
+ if (ce !== null) {
88
+ if (ce !== lastTracked || ce._epoch !== lastTrackedEpoch) {
89
+ lastTracked = ce;
90
+ lastTrackedEpoch = ce._epoch;
91
+ subs.add(ce);
92
+ ce.deps.push(subs);
93
+ }
88
94
  }
89
95
  if (dirty) _evaluateComputed(inner);
90
96
  return value;
91
97
  }
92
98
  inner._onNotify = () => {
93
99
  dirty = true;
100
+ lastTracked = null;
94
101
  if (subs.size > 0) notify(subs);
95
102
  };
96
103
  read._signal = true;
@@ -117,7 +124,7 @@ function _evaluateComputed(computedEffect) {
117
124
  let pushedUpstream = false;
118
125
  const deps = current.deps;
119
126
  for (let i = 0; i < deps.length; i++) {
120
- const depOwner = subSetOwner.get(deps[i]);
127
+ const depOwner = deps[i]._owner;
121
128
  if (depOwner && depOwner._computed && depOwner._isDirty && depOwner._isDirty()) {
122
129
  stack.push(depOwner);
123
130
  pushedUpstream = true;
@@ -149,7 +156,7 @@ function _updateLevel(e) {
149
156
  let maxDepLevel = 0;
150
157
  const deps = e.deps;
151
158
  for (let i = 0; i < deps.length; i++) {
152
- const owner = subSetOwner.get(deps[i]);
159
+ const owner = deps[i]._owner;
153
160
  if (owner) {
154
161
  const depLevel = owner._level;
155
162
  if (depLevel > maxDepLevel) maxDepLevel = depLevel;
@@ -204,8 +211,12 @@ function _createEffect(fn, lazy2) {
204
211
  // reference to the computed's subscriber set
205
212
  _isDirty: null,
206
213
  // function to check if computed is dirty (set by computed())
207
- _markDirty: null
214
+ _markDirty: null,
208
215
  // function to mark computed dirty (set by computed())
216
+ _cleanup: null,
217
+ // cleanup function returned by effect fn (declared upfront for shape)
218
+ _epoch: 0
219
+ // incremented on cleanup — used by signal lastTracked cache
209
220
  };
210
221
  if (__DEV__ && __devtools) __devtools.onEffectCreate(e);
211
222
  return e;
@@ -235,12 +246,13 @@ function _runEffect(e) {
235
246
  if (__DEV__ && __devtools?.onEffectRun) __devtools.onEffectRun(e);
236
247
  return;
237
248
  }
249
+ const singleDep = e.deps.length === 1 ? e.deps[0] : null;
238
250
  cleanup(e);
239
251
  if (e._cleanup) {
240
252
  try {
241
253
  e._cleanup();
242
254
  } catch (err) {
243
- if (__devtools?.onError) __devtools.onError(err, { type: "effect-cleanup", effect: e });
255
+ if (__DEV__ && __devtools?.onError) __devtools.onError(err, { type: "effect-cleanup", effect: e });
244
256
  if (__DEV__) console.warn("[what] Error in effect cleanup:", err);
245
257
  }
246
258
  e._cleanup = null;
@@ -254,11 +266,14 @@ function _runEffect(e) {
254
266
  }
255
267
  } catch (err) {
256
268
  if (err === NEEDS_UPSTREAM) throw err;
257
- if (__devtools?.onError) __devtools.onError(err, { type: "effect", effect: e });
269
+ if (__DEV__ && __devtools?.onError) __devtools.onError(err, { type: "effect", effect: e });
258
270
  throw err;
259
271
  } finally {
260
272
  currentEffect = prev;
261
273
  }
274
+ if (singleDep !== null && e.deps.length === 1 && e.deps[0] === singleDep && !e._cleanup && !e._pending) {
275
+ e._stable = true;
276
+ }
262
277
  if (__DEV__ && __devtools?.onEffectRun) __devtools.onEffectRun(e);
263
278
  }
264
279
  function _disposeEffect(e) {
@@ -278,45 +293,51 @@ function cleanup(e) {
278
293
  const deps = e.deps;
279
294
  for (let i = 0; i < deps.length; i++) deps[i].delete(e);
280
295
  deps.length = 0;
296
+ e._epoch++;
281
297
  }
282
298
  var notifyDepth = 0;
283
299
  var notifyQueue = null;
284
300
  var notifyQueueLen = 0;
301
+ function _processSubscriber(e) {
302
+ if (e.disposed) return;
303
+ if (e._onNotify) {
304
+ e._onNotify();
305
+ } else if (!e._pending) {
306
+ if (batchDepth === 0 && e._stable) {
307
+ const prev = currentEffect;
308
+ currentEffect = null;
309
+ try {
310
+ const result = e.fn();
311
+ if (typeof result === "function") {
312
+ if (e._cleanup) try {
313
+ e._cleanup();
314
+ } catch (err) {
315
+ }
316
+ e._cleanup = result;
317
+ }
318
+ } catch (err) {
319
+ if (__DEV__ && __devtools?.onError) __devtools.onError(err, { type: "effect", effect: e });
320
+ if (__DEV__) console.warn("[what] Error in stable effect:", err);
321
+ } finally {
322
+ currentEffect = prev;
323
+ }
324
+ } else {
325
+ e._pending = true;
326
+ const level = e._level;
327
+ const len = pendingEffects.length;
328
+ if (len > 0 && pendingEffects[len - 1]._level > level) {
329
+ pendingNeedSort = true;
330
+ }
331
+ pendingEffects.push(e);
332
+ }
333
+ }
334
+ }
285
335
  function notify(subs) {
286
336
  if (notifyDepth === 0) {
287
337
  notifyDepth = 1;
288
338
  try {
289
339
  for (const e of subs) {
290
- if (e.disposed) continue;
291
- if (e._onNotify) {
292
- e._onNotify();
293
- } else if (batchDepth === 0 && e._stable) {
294
- const prev = currentEffect;
295
- currentEffect = null;
296
- try {
297
- const result = e.fn();
298
- if (typeof result === "function") {
299
- if (e._cleanup) try {
300
- e._cleanup();
301
- } catch (err) {
302
- }
303
- e._cleanup = result;
304
- }
305
- } catch (err) {
306
- if (__devtools?.onError) __devtools.onError(err, { type: "effect", effect: e });
307
- if (__DEV__) console.warn("[what] Error in stable effect:", err);
308
- } finally {
309
- currentEffect = prev;
310
- }
311
- } else if (!e._pending) {
312
- e._pending = true;
313
- const level = e._level;
314
- const len = pendingEffects.length;
315
- if (len > 0 && pendingEffects[len - 1]._level > level) {
316
- pendingNeedSort = true;
317
- }
318
- pendingEffects.push(e);
319
- }
340
+ _processSubscriber(e);
320
341
  }
321
342
  if (notifyQueueLen > 0) {
322
343
  let qi = 0;
@@ -325,36 +346,7 @@ function notify(subs) {
325
346
  notifyQueue[qi] = null;
326
347
  qi++;
327
348
  for (const e of queuedSubs) {
328
- if (e.disposed) continue;
329
- if (e._onNotify) {
330
- e._onNotify();
331
- } else if (batchDepth === 0 && e._stable) {
332
- const prev = currentEffect;
333
- currentEffect = null;
334
- try {
335
- const result = e.fn();
336
- if (typeof result === "function") {
337
- if (e._cleanup) try {
338
- e._cleanup();
339
- } catch (err) {
340
- }
341
- e._cleanup = result;
342
- }
343
- } catch (err) {
344
- if (__devtools?.onError) __devtools.onError(err, { type: "effect", effect: e });
345
- if (__DEV__) console.warn("[what] Error in stable effect:", err);
346
- } finally {
347
- currentEffect = prev;
348
- }
349
- } else if (!e._pending) {
350
- e._pending = true;
351
- const level = e._level;
352
- const len = pendingEffects.length;
353
- if (len > 0 && pendingEffects[len - 1]._level > level) {
354
- pendingNeedSort = true;
355
- }
356
- pendingEffects.push(e);
357
- }
349
+ _processSubscriber(e);
358
350
  }
359
351
  }
360
352
  notifyQueueLen = 0;
@@ -410,8 +402,6 @@ function flush() {
410
402
  iterations++;
411
403
  }
412
404
  if (iterations >= 25) {
413
- for (let i = 0; i < pendingEffects.length; i++) pendingEffects[i]._pending = false;
414
- pendingEffects.length = 0;
415
405
  if (__DEV__) {
416
406
  const remaining = pendingEffects.slice(0, 3);
417
407
  const effectNames = remaining.map((e) => e.fn?.name || e.fn?.toString().slice(0, 60) || "(anonymous)");
@@ -421,6 +411,8 @@ function flush() {
421
411
  } else {
422
412
  console.warn("[what] Possible infinite effect loop detected");
423
413
  }
414
+ for (let i = 0; i < pendingEffects.length; i++) pendingEffects[i]._pending = false;
415
+ pendingEffects.length = 0;
424
416
  }
425
417
  } finally {
426
418
  isFlushing = false;
@@ -452,7 +444,7 @@ function memo(fn) {
452
444
  e._level = 1;
453
445
  _runEffect(e);
454
446
  _updateLevel(e);
455
- subSetOwner.set(subs, e);
447
+ subs._owner = e;
456
448
  if (currentRoot) {
457
449
  currentRoot.disposals.push(() => _disposeEffect(e));
458
450
  }
@@ -562,6 +554,38 @@ function _disposeRoot(root) {
562
554
  }
563
555
  root.disposals.length = 0;
564
556
  }
557
+ function _createItemScope(fn) {
558
+ const prevRoot = currentRoot;
559
+ const prevOwner = currentOwner;
560
+ const scope = {
561
+ disposals: [],
562
+ owner: null,
563
+ // No parent registration
564
+ children: [],
565
+ // Kept for compat with effects that create sub-roots
566
+ _disposed: false
567
+ };
568
+ currentRoot = scope;
569
+ currentOwner = scope;
570
+ try {
571
+ const dispose = () => {
572
+ if (scope._disposed) return;
573
+ scope._disposed = true;
574
+ for (let i = scope.children.length - 1; i >= 0; i--) {
575
+ _disposeRoot(scope.children[i]);
576
+ }
577
+ scope.children.length = 0;
578
+ for (let i = scope.disposals.length - 1; i >= 0; i--) {
579
+ scope.disposals[i]();
580
+ }
581
+ scope.disposals.length = 0;
582
+ };
583
+ return fn(dispose);
584
+ } finally {
585
+ currentRoot = prevRoot;
586
+ currentOwner = prevOwner;
587
+ }
588
+ }
565
589
  function onCleanup(fn) {
566
590
  if (currentRoot) {
567
591
  currentRoot.disposals.push(fn);
@@ -570,9 +594,22 @@ function onCleanup(fn) {
570
594
 
571
595
  // packages/core/src/h.js
572
596
  var EMPTY_OBJ = /* @__PURE__ */ Object.create(null);
573
- function h(tag, props, ...children) {
597
+ var EMPTY_ARR = [];
598
+ function h(tag, props) {
574
599
  props = props || EMPTY_OBJ;
575
- const flat = flattenChildren(children);
600
+ const argLen = arguments.length;
601
+ let flat;
602
+ if (argLen <= 2) {
603
+ flat = EMPTY_ARR;
604
+ } else if (argLen === 3) {
605
+ flat = _flattenSingle(arguments[2]);
606
+ } else {
607
+ const out = [];
608
+ for (let i = 2; i < argLen; i++) {
609
+ _flattenInto(arguments[i], out);
610
+ }
611
+ flat = out;
612
+ }
576
613
  const key = props.key ?? null;
577
614
  if (props.key !== void 0) {
578
615
  props = { ...props };
@@ -583,22 +620,30 @@ function h(tag, props, ...children) {
583
620
  function Fragment({ children }) {
584
621
  return children;
585
622
  }
586
- function flattenChildren(children) {
587
- const out = [];
588
- for (let i = 0; i < children.length; i++) {
589
- const child = children[i];
590
- if (child == null || child === false || child === true) continue;
591
- if (Array.isArray(child)) {
592
- out.push(...flattenChildren(child));
593
- } else if (typeof child === "object" && child._vnode) {
594
- out.push(child);
595
- } else if (typeof child === "function") {
596
- out.push(child);
597
- } else {
598
- out.push(String(child));
623
+ function _flattenSingle(child) {
624
+ if (child == null || child === false || child === true) return EMPTY_ARR;
625
+ if (Array.isArray(child)) {
626
+ const out = [];
627
+ _flattenInto(child, out);
628
+ return out;
629
+ }
630
+ if (typeof child === "object" && child._vnode) return [child];
631
+ if (typeof child === "function") return [child];
632
+ return [String(child)];
633
+ }
634
+ function _flattenInto(child, out) {
635
+ if (child == null || child === false || child === true) return;
636
+ if (Array.isArray(child)) {
637
+ for (let i = 0; i < child.length; i++) {
638
+ _flattenInto(child[i], out);
599
639
  }
640
+ } else if (typeof child === "object" && child._vnode) {
641
+ out.push(child);
642
+ } else if (typeof child === "function") {
643
+ out.push(child);
644
+ } else {
645
+ out.push(String(child));
600
646
  }
601
- return out;
602
647
  }
603
648
  function html(strings, ...values) {
604
649
  const src = strings.reduce((acc, str, i) => acc + str + (i < values.length ? `\0${i}\0` : ""), "");
@@ -1177,9 +1222,11 @@ function disposeTree(node) {
1177
1222
  if (node._componentCtx) {
1178
1223
  disposeComponent(node._componentCtx);
1179
1224
  }
1180
- const commentCtx = _commentCtxMap.get(node);
1181
- if (commentCtx) {
1182
- disposeComponent(commentCtx);
1225
+ if (node.nodeType === 8) {
1226
+ const commentCtx = _commentCtxMap.get(node);
1227
+ if (commentCtx) {
1228
+ disposeComponent(commentCtx);
1229
+ }
1183
1230
  }
1184
1231
  if (node._dispose) {
1185
1232
  try {
@@ -1195,9 +1242,10 @@ function disposeTree(node) {
1195
1242
  }
1196
1243
  }
1197
1244
  }
1198
- if (node.childNodes) {
1199
- for (const child of node.childNodes) {
1200
- disposeTree(child);
1245
+ const children = node.childNodes;
1246
+ if (children && children.length > 0) {
1247
+ for (let i = 0; i < children.length; i++) {
1248
+ disposeTree(children[i]);
1201
1249
  }
1202
1250
  }
1203
1251
  }
@@ -1275,6 +1323,27 @@ function createDOM(vnode, parent, isSvg) {
1275
1323
  }
1276
1324
  return document.createTextNode(String(vnode));
1277
1325
  }
1326
+ var _propsProxyHandler = {
1327
+ get(target, key) {
1328
+ if (key === "_sig") return void 0;
1329
+ return target._sig()[key];
1330
+ },
1331
+ has(target, key) {
1332
+ if (key === "_sig") return false;
1333
+ return key in target._sig();
1334
+ },
1335
+ ownKeys(target) {
1336
+ return Reflect.ownKeys(target._sig());
1337
+ },
1338
+ getOwnPropertyDescriptor(target, key) {
1339
+ if (key === "_sig") return void 0;
1340
+ const current = target._sig();
1341
+ if (key in current) {
1342
+ return { value: current[key], writable: false, enumerable: true, configurable: true };
1343
+ }
1344
+ return void 0;
1345
+ }
1346
+ };
1278
1347
  var componentStack = [];
1279
1348
  function getCurrentComponent() {
1280
1349
  return componentStack[componentStack.length - 1];
@@ -1303,6 +1372,21 @@ function createComponent(vnode, parent, isSvg) {
1303
1372
  if (Component === "__portal" || vnode.tag === "__portal") {
1304
1373
  return createPortalDOM(vnode, parent);
1305
1374
  }
1375
+ const parentCtx = componentStack[componentStack.length - 1] || null;
1376
+ let errorBoundary = null;
1377
+ if (parentCtx) {
1378
+ errorBoundary = parentCtx._errorBoundary || null;
1379
+ if (!errorBoundary) {
1380
+ let p = parentCtx._parentCtx;
1381
+ while (p) {
1382
+ if (p._errorBoundary) {
1383
+ errorBoundary = p._errorBoundary;
1384
+ break;
1385
+ }
1386
+ p = p._parentCtx;
1387
+ }
1388
+ }
1389
+ }
1306
1390
  const ctx = {
1307
1391
  hooks: [],
1308
1392
  hookIndex: 0,
@@ -1311,15 +1395,8 @@ function createComponent(vnode, parent, isSvg) {
1311
1395
  mounted: false,
1312
1396
  disposed: false,
1313
1397
  Component,
1314
- _parentCtx: componentStack[componentStack.length - 1] || null,
1315
- _errorBoundary: (() => {
1316
- let p = componentStack[componentStack.length - 1];
1317
- while (p) {
1318
- if (p._errorBoundary) return p._errorBoundary;
1319
- p = p._parentCtx;
1320
- }
1321
- return null;
1322
- })()
1398
+ _parentCtx: parentCtx,
1399
+ _errorBoundary: errorBoundary
1323
1400
  };
1324
1401
  const startComment = document.createComment("c:start");
1325
1402
  const endComment = document.createComment("c:end");
@@ -1332,29 +1409,15 @@ function createComponent(vnode, parent, isSvg) {
1332
1409
  mountedComponents.add(ctx);
1333
1410
  if (__DEV__ && __devtools?.onComponentMount) __devtools.onComponentMount(ctx);
1334
1411
  const propsChildren = children.length === 0 ? void 0 : children.length === 1 ? children[0] : children;
1335
- const propsSignal = signal({ ...props, children: propsChildren });
1412
+ let mergedProps;
1413
+ if (propsChildren !== void 0) {
1414
+ mergedProps = props ? Object.assign({}, props, { children: propsChildren }) : { children: propsChildren };
1415
+ } else {
1416
+ mergedProps = props ? Object.assign({}, props) : {};
1417
+ }
1418
+ const propsSignal = signal(mergedProps);
1336
1419
  ctx._propsSignal = propsSignal;
1337
- const reactiveProps = new Proxy({}, {
1338
- get(_, key) {
1339
- const current = propsSignal();
1340
- return current[key];
1341
- },
1342
- has(_, key) {
1343
- const current = propsSignal();
1344
- return key in current;
1345
- },
1346
- ownKeys() {
1347
- const current = propsSignal();
1348
- return Reflect.ownKeys(current);
1349
- },
1350
- getOwnPropertyDescriptor(_, key) {
1351
- const current = propsSignal();
1352
- if (key in current) {
1353
- return { value: current[key], writable: false, enumerable: true, configurable: true };
1354
- }
1355
- return void 0;
1356
- }
1357
- });
1420
+ const reactiveProps = new Proxy({ _sig: propsSignal }, _propsProxyHandler);
1358
1421
  componentStack.push(ctx);
1359
1422
  let result;
1360
1423
  try {
@@ -1535,21 +1598,22 @@ function createElementFromVNode(vnode, parent, isSvg) {
1535
1598
  if (props) {
1536
1599
  applyProps(el, props, {}, svgContext);
1537
1600
  }
1538
- for (const child of children) {
1539
- const node = createDOM(child, el, svgContext && tag !== "foreignObject");
1601
+ const isSvgChildren = svgContext && tag !== "foreignObject";
1602
+ for (let i = 0; i < children.length; i++) {
1603
+ const node = createDOM(children[i], el, isSvgChildren);
1540
1604
  if (node) el.appendChild(node);
1541
1605
  }
1542
1606
  el._vnode = vnode;
1543
1607
  return el;
1544
1608
  }
1545
1609
  function applyProps(el, newProps, oldProps, isSvg) {
1546
- newProps = newProps || {};
1547
- oldProps = oldProps || {};
1610
+ if (!newProps) return;
1548
1611
  for (const key in newProps) {
1549
1612
  if (key === "key" || key === "children") continue;
1550
1613
  if (key === "ref") {
1551
- if (typeof newProps.ref === "function") newProps.ref(el);
1552
- else if (newProps.ref) newProps.ref.current = el;
1614
+ const ref = newProps.ref;
1615
+ if (typeof ref === "function") ref(el);
1616
+ else if (ref) ref.current = el;
1553
1617
  continue;
1554
1618
  }
1555
1619
  setProp(el, key, newProps[key], isSvg);
@@ -1586,8 +1650,9 @@ function setProp(el, key, value, isSvg) {
1586
1650
  if (!el._events) el._events = {};
1587
1651
  const wrappedHandler = (e) => {
1588
1652
  if (!e.nativeEvent) e.nativeEvent = e;
1589
- return untrack(() => value(e));
1653
+ return untrack(() => wrappedHandler._handler(e));
1590
1654
  };
1655
+ wrappedHandler._handler = value;
1591
1656
  wrappedHandler._original = value;
1592
1657
  el._events[storageKey] = wrappedHandler;
1593
1658
  const eventOpts = value._eventOpts;
@@ -1661,10 +1726,18 @@ function setProp(el, key, value, isSvg) {
1661
1726
  }
1662
1727
 
1663
1728
  // packages/core/src/render.js
1729
+ var _onTextInsert = null;
1730
+ function _setTextInsertHook(fn) {
1731
+ _onTextInsert = typeof fn === "function" ? fn : null;
1732
+ }
1664
1733
  function _$createComponent(Component, props, children) {
1665
1734
  if (children && children.length > 0) {
1666
1735
  const mergedChildren = children.length === 1 ? children[0] : children;
1667
- props = props ? { ...props, children: mergedChildren } : { children: mergedChildren };
1736
+ if (props) {
1737
+ props.children = mergedChildren;
1738
+ } else {
1739
+ props = { children: mergedChildren };
1740
+ }
1668
1741
  }
1669
1742
  return createDOM({ tag: Component, props: props || {}, children: children || [], key: null, _vnode: true });
1670
1743
  }
@@ -1752,13 +1825,9 @@ function _$templateImpl(html2) {
1752
1825
  if (tableInfo) {
1753
1826
  const t2 = document.createElement("template");
1754
1827
  t2.innerHTML = tableInfo.wrap + trimmed + tableInfo.unwrap;
1755
- return () => {
1756
- let node = t2.content.firstChild;
1757
- for (let i = 0; i < tableInfo.depth; i++) {
1758
- node = node.firstChild;
1759
- }
1760
- return node.cloneNode(true);
1761
- };
1828
+ let target = t2.content.firstChild;
1829
+ for (let i = 0; i < tableInfo.depth; i++) target = target.firstChild;
1830
+ return () => target.cloneNode(true);
1762
1831
  }
1763
1832
  const t = document.createElement("template");
1764
1833
  t.innerHTML = trimmed;
@@ -1788,12 +1857,47 @@ function svgTemplate(html2) {
1788
1857
  }
1789
1858
  function insert(parent, child, marker) {
1790
1859
  if (typeof child === "function") {
1791
- let current = null;
1860
+ const first = child();
1861
+ const t = typeof first;
1862
+ if (t === "string" || t === "number") {
1863
+ const textNode = document.createTextNode(String(first));
1864
+ const m = marker || null;
1865
+ if (m) parent.insertBefore(textNode, m);
1866
+ else parent.appendChild(textNode);
1867
+ if (_onTextInsert) _onTextInsert(parent, String(first));
1868
+ let current2 = textNode;
1869
+ let isTextFastPath = true;
1870
+ effect(() => {
1871
+ const val = child();
1872
+ const vt = typeof val;
1873
+ if (isTextFastPath && (vt === "string" || vt === "number")) {
1874
+ const str = String(val);
1875
+ if (textNode.data !== str) textNode.data = str;
1876
+ if (_onTextInsert) _onTextInsert(parent, str);
1877
+ } else {
1878
+ isTextFastPath = false;
1879
+ current2 = reconcileInsert(parent, val, current2, m);
1880
+ }
1881
+ });
1882
+ return textNode;
1883
+ }
1884
+ let current = first != null ? reconcileInsert(parent, first, null, marker || null) : null;
1792
1885
  effect(() => {
1793
1886
  current = reconcileInsert(parent, child(), current, marker || null);
1794
1887
  });
1795
1888
  return current;
1796
1889
  }
1890
+ if (typeof child === "string" || typeof child === "number") {
1891
+ const textNode = document.createTextNode(String(child));
1892
+ if (marker) parent.insertBefore(textNode, marker);
1893
+ else parent.appendChild(textNode);
1894
+ return textNode;
1895
+ }
1896
+ if (child != null && typeof child === "object" && child.nodeType > 0) {
1897
+ if (marker) parent.insertBefore(child, marker);
1898
+ else parent.appendChild(child);
1899
+ return child;
1900
+ }
1797
1901
  return reconcileInsert(parent, child, null, marker || null);
1798
1902
  }
1799
1903
  function isDomNode2(value) {
@@ -1804,8 +1908,9 @@ function isDomNode2(value) {
1804
1908
  function isVNode2(value) {
1805
1909
  return !!value && typeof value === "object" && (value._vnode === true || "tag" in value);
1806
1910
  }
1911
+ var _hasSVGElement = typeof SVGElement !== "undefined";
1807
1912
  function isSvgParent(parent) {
1808
- return typeof SVGElement !== "undefined" && parent instanceof SVGElement && parent.tagName.toLowerCase() !== "foreignobject";
1913
+ return _hasSVGElement && parent instanceof SVGElement && parent.tagName !== "foreignObject";
1809
1914
  }
1810
1915
  function asNodeArray(value) {
1811
1916
  if (value == null) return [];
@@ -1862,18 +1967,39 @@ function reconcileInsert(parent, value, current, marker) {
1862
1967
  }
1863
1968
  if ((typeof value === "string" || typeof value === "number") && current && !Array.isArray(current) && current.nodeType === 3) {
1864
1969
  const text = String(value);
1865
- if (current.textContent !== text) current.textContent = text;
1970
+ if (current.data !== text) current.data = text;
1866
1971
  return current;
1867
1972
  }
1973
+ if (typeof value === "object" && value !== null && value.nodeType > 0 && !Array.isArray(value)) {
1974
+ if (value === current) return current;
1975
+ if (current && !Array.isArray(current) && current.nodeType > 0) {
1976
+ if (current.parentNode === parent) {
1977
+ disposeTree(current);
1978
+ parent.replaceChild(value, current);
1979
+ } else {
1980
+ if (targetMarker) parent.insertBefore(value, targetMarker);
1981
+ else parent.appendChild(value);
1982
+ }
1983
+ return value;
1984
+ }
1985
+ }
1868
1986
  const newNodes = valuesToNodes(value, parent, []);
1869
1987
  const oldNodes = asNodeArray(current);
1870
1988
  if (sameNodeArray(oldNodes, newNodes)) {
1871
1989
  return current;
1872
1990
  }
1873
- const keep = new Set(newNodes);
1991
+ const newLen = newNodes.length;
1874
1992
  for (let i = 0; i < oldNodes.length; i++) {
1875
1993
  const oldNode = oldNodes[i];
1876
- if (!keep.has(oldNode) && oldNode.parentNode === parent) {
1994
+ if (oldNode.parentNode !== parent) continue;
1995
+ let found = false;
1996
+ for (let j = 0; j < newLen; j++) {
1997
+ if (newNodes[j] === oldNode) {
1998
+ found = true;
1999
+ break;
2000
+ }
2001
+ }
2002
+ if (!found) {
1877
2003
  disposeTree(oldNode);
1878
2004
  parent.removeChild(oldNode);
1879
2005
  }
@@ -1908,7 +2034,7 @@ function mapArray(source, mapFn, options) {
1908
2034
  } else {
1909
2035
  reconcileList(parent, endMarker, items, newItems, mappedNodes, disposeFns, mapFn);
1910
2036
  }
1911
- items = newItems.slice();
2037
+ items = newItems.length > 0 ? newItems.slice() : newItems;
1912
2038
  });
1913
2039
  return endMarker;
1914
2040
  };
@@ -1919,10 +2045,15 @@ function reconcileList(parent, endMarker, oldItems, newItems, mappedNodes, dispo
1919
2045
  if (newLen === 0) {
1920
2046
  if (oldLen > 0) {
1921
2047
  for (let i = 0; i < oldLen; i++) {
1922
- disposeFns[i]?.();
1923
- if (mappedNodes[i]?.parentNode === parent) {
1924
- disposeTree(mappedNodes[i]);
1925
- parent.removeChild(mappedNodes[i]);
2048
+ if (disposeFns[i]) disposeFns[i]();
2049
+ }
2050
+ for (let i = oldLen - 1; i >= 0; i--) {
2051
+ const node = mappedNodes[i];
2052
+ if (node) {
2053
+ if (node._componentCtx || node._dispose || node._propEffects) {
2054
+ disposeTree(node);
2055
+ }
2056
+ if (node.parentNode === parent) parent.removeChild(node);
1926
2057
  }
1927
2058
  }
1928
2059
  mappedNodes.length = 0;
@@ -1934,7 +2065,7 @@ function reconcileList(parent, endMarker, oldItems, newItems, mappedNodes, dispo
1934
2065
  const frag = document.createDocumentFragment();
1935
2066
  for (let i = 0; i < newLen; i++) {
1936
2067
  const item = newItems[i];
1937
- const node = createRoot((dispose) => {
2068
+ const node = _createItemScope((dispose) => {
1938
2069
  disposeFns[i] = dispose;
1939
2070
  return mapFn(item, i);
1940
2071
  });
@@ -1978,7 +2109,7 @@ function reconcileList(parent, endMarker, oldItems, newItems, mappedNodes, dispo
1978
2109
  for (let i = start; i <= newEnd; i++) {
1979
2110
  const item = newItems[i];
1980
2111
  const idx = i;
1981
- newMapped[i] = createRoot((dispose) => {
2112
+ newMapped[i] = _createItemScope((dispose) => {
1982
2113
  newDispose[idx] = dispose;
1983
2114
  return mapFn(item, idx);
1984
2115
  });
@@ -2058,7 +2189,7 @@ function _reconcileMiddle(parent, endMarker, oldItems, newItems, mappedNodes, di
2058
2189
  if (!newMapped[i]) {
2059
2190
  const item = newItems[i];
2060
2191
  const idx = i;
2061
- newMapped[i] = createRoot((dispose) => {
2192
+ newMapped[i] = _createItemScope((dispose) => {
2062
2193
  newDispose[idx] = dispose;
2063
2194
  return mapFn(item, idx);
2064
2195
  });
@@ -2116,10 +2247,15 @@ function reconcileKeyed(parent, endMarker, oldItems, newItems, mappedNodes, disp
2116
2247
  if (newLen === 0) {
2117
2248
  if (oldLen > 0) {
2118
2249
  for (let i = 0; i < oldLen; i++) {
2119
- disposeFns[i]?.();
2120
- if (mappedNodes[i]?.parentNode === parent) {
2121
- disposeTree(mappedNodes[i]);
2122
- parent.removeChild(mappedNodes[i]);
2250
+ if (disposeFns[i]) disposeFns[i]();
2251
+ }
2252
+ for (let i = oldLen - 1; i >= 0; i--) {
2253
+ const node = mappedNodes[i];
2254
+ if (node) {
2255
+ if (node._componentCtx || node._dispose || node._propEffects) {
2256
+ disposeTree(node);
2257
+ }
2258
+ if (node.parentNode === parent) parent.removeChild(node);
2123
2259
  }
2124
2260
  }
2125
2261
  mappedNodes.length = 0;
@@ -2142,7 +2278,7 @@ function reconcileKeyed(parent, endMarker, oldItems, newItems, mappedNodes, disp
2142
2278
  } else {
2143
2279
  accessor = item;
2144
2280
  }
2145
- const node = createRoot((dispose) => {
2281
+ const node = _createItemScope((dispose) => {
2146
2282
  disposeFns[idx] = dispose;
2147
2283
  return mapFn(accessor, idx);
2148
2284
  });
@@ -2211,7 +2347,7 @@ function reconcileKeyed(parent, endMarker, oldItems, newItems, mappedNodes, disp
2211
2347
  } else {
2212
2348
  accessor = item;
2213
2349
  }
2214
- newMapped[i] = createRoot((dispose) => {
2350
+ newMapped[i] = _createItemScope((dispose) => {
2215
2351
  newDispose[idx] = dispose;
2216
2352
  return mapFn(accessor, idx);
2217
2353
  });
@@ -2267,7 +2403,7 @@ function reconcileKeyed(parent, endMarker, oldItems, newItems, mappedNodes, disp
2267
2403
  } else {
2268
2404
  accessor = item;
2269
2405
  }
2270
- newMapped[i] = createRoot((dispose) => {
2406
+ newMapped[i] = _createItemScope((dispose) => {
2271
2407
  newDispose[idx] = dispose;
2272
2408
  return mapFn(accessor, idx);
2273
2409
  });
@@ -5655,6 +5791,8 @@ var VALID_EXPORTS = /* @__PURE__ */ new Set([
5655
5791
  "onResize",
5656
5792
  "onIntersect",
5657
5793
  "smoothScrollTo",
5794
+ // Text insertion hook (for external text engines)
5795
+ "_setTextInsertHook",
5658
5796
  // Animation
5659
5797
  "spring",
5660
5798
  "tween",
@@ -5885,6 +6023,7 @@ export {
5885
6023
  _$templateImpl as _$template,
5886
6024
  __getCacheSnapshot,
5887
6025
  __setDevToolsHooks,
6026
+ _setTextInsertHook,
5888
6027
  template as _template,
5889
6028
  announce,
5890
6029
  announceAssertive,