@vesk/runtime 0.2.41 → 0.2.43

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.
@@ -1 +1 @@
1
- {"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../src/form.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE/D,MAAM,WAAW,cAAc;IAC9B,QAAQ,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,UAAU;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACrB;AAED,UAAU,SAAS;IAClB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,eAAe,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1F,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACrB;AAsCD,wBAAgB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,cAAc,CAErD;AAED,wBAAgB,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,cAAc,CAElD;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,cAAc,CAEjE;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,cAAc,CAEjE;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,cAAc,CAEhE;AAED,wBAAgB,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,cAAc,CAEhF;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI,GAAG,MAAM,CAoDhH;AA+GD,wBAAgB,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI,GAAG,MAAM,CA8C9G"}
1
+ {"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../src/form.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE/D,MAAM,WAAW,cAAc;IAC9B,QAAQ,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,UAAU;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACrB;AAED,UAAU,SAAS;IAClB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,eAAe,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1F,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACrB;AAsCD,wBAAgB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,cAAc,CAErD;AAED,wBAAgB,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,cAAc,CAElD;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,cAAc,CAEjE;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,cAAc,CAEjE;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,cAAc,CAEhE;AAED,wBAAgB,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,cAAc,CAEhF;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI,GAAG,MAAM,CAoDhH;AA+GD,wBAAgB,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI,GAAG,MAAM,CAoD9G"}
package/dist/form.js CHANGED
@@ -244,7 +244,13 @@ export function Form(props, registry, hydrate) {
244
244
  return `<form ${attrStr}>${children || ''}</form>`;
245
245
  }
246
246
  if (hydrate && hydrate.nextElement) {
247
- let form = hydrate.nextElement('form');
247
+ // The compiler may deposit the static residue that precedes this
248
+ // self-claiming component (for example <h1> before <Form>). Consume it
249
+ // before claiming the form root; otherwise the runtime would inspect
250
+ // the heading as the form slot, detach it as a mismatch, and only find
251
+ // the real form through the broad querySelector fallback.
252
+ const skipK = typeof hydrate.takeSkipK === 'function' ? hydrate.takeSkipK() : 0;
253
+ let form = hydrate.nextElement('form', skipK);
248
254
  if (form && !form.parentNode && hydrate.root) {
249
255
  const existing = hydrate.root.querySelector('form');
250
256
  if (existing)
package/dist/hydrate.d.ts CHANGED
@@ -20,7 +20,7 @@ export interface ClaimByKeyOptions {
20
20
  export interface HydrateWalker {
21
21
  root: HTMLElement | null;
22
22
  done(): boolean;
23
- nextElement(tag?: string): Element;
23
+ nextElement(tag?: string, skipK?: number): Element;
24
24
  /**
25
25
  * Claim an element like `nextElement` but without stripping its direct text
26
26
  * children. Used by static-component stubs whose SSR content is preserved
@@ -1 +1 @@
1
- {"version":3,"file":"hydrate.d.ts","sourceRoot":"","sources":["../src/hydrate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hydrate.d.ts","sourceRoot":"","sources":["../src/hydrate.ts"],"names":[],"mappings":"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"}
package/dist/hydrate.js CHANGED
@@ -38,16 +38,32 @@ export function reactiveProps(props) {
38
38
  // ---------------------------------------------------------------------------
39
39
  // Dev-mode hydration-integrity canary (T1)
40
40
  //
41
- // Claiming the SSR DOM is inherently positional: a element claimed from the
42
- // wrong slot fails silently in production (the SSR node is adopted as-is). To
43
- // surface SSR/client divergence early, dev mode:
44
- // * stamps every adopted node with `data-vsk-claimed`,
45
- // * warns with the container fragment when a positional claim misses, and
46
- // * runs `assertFullyHydrated()` at the end of every full hydration so
47
- // unclaimed phantom markers are reported instead of rotting in the DOM.
41
+ // Claiming the SSR DOM is inherently positional: an element claimed from the
42
+ // wrong slot fails silently in production. Hydration bookkeeping therefore
43
+ // lives in WeakMaps, never in DOM attributes. The canary audits the records at
44
+ // the end of every full hydration and warns when markers or structural claim
45
+ // records remain unresolved.
48
46
  // ---------------------------------------------------------------------------
49
47
  let __hydrateDevMode = true;
50
- const CLAIMED_ATTR = 'data-vsk-claimed';
48
+ // The first map answers "was this element adopted?" without observable DOM
49
+ // mutation. The second lets auditHydration inspect records even after a safe
50
+ // recovery detached a ghost: walker records stay reachable from their live
51
+ // owner root without keeping an otherwise-unreachable node globally alive.
52
+ const claimRegistry = new WeakMap();
53
+ const walkerClaimRecords = new WeakMap();
54
+ function recordClaim(root, record) {
55
+ claimRegistry.set(record.el, record);
56
+ if (!root)
57
+ return;
58
+ const records = walkerClaimRecords.get(root);
59
+ if (records)
60
+ records.push(record);
61
+ else
62
+ walkerClaimRecords.set(root, [record]);
63
+ }
64
+ function isAdopted(el) {
65
+ return claimRegistry.get(el)?.state === 'adopted';
66
+ }
51
67
  export function setHydrateDevMode(enabled) {
52
68
  __hydrateDevMode = enabled;
53
69
  }
@@ -89,16 +105,15 @@ function reportMiss(kind, detail, loud) {
89
105
  if (loud)
90
106
  devWarn(`${kind}: ${detail}`);
91
107
  }
92
- function stampClaimed(el) {
93
- if (__hydrateDevMode) {
94
- try {
95
- el.setAttribute(CLAIMED_ATTR, '');
96
- }
97
- catch {
98
- // Some hosts restrict attribute writes on special nodes (SVG,
99
- // <template> children); claiming is still valid.
100
- }
101
- }
108
+ function recordAdopted(root, el, expectedTag) {
109
+ recordClaim(root, {
110
+ state: 'adopted',
111
+ el,
112
+ owner: root,
113
+ expectedTag,
114
+ actualTag: el.tagName.toLowerCase(),
115
+ detached: false,
116
+ });
102
117
  }
103
118
  // Strip the direct text children of a claimed element. Static text inside a
104
119
  // claimed subtree is re-created client-side as fresh text nodes, so the
@@ -176,8 +191,8 @@ function scanTwins(container) {
176
191
  let a = false;
177
192
  let b = false;
178
193
  try {
179
- a = el.hasAttribute(CLAIMED_ATTR);
180
- b = prev.hasAttribute(CLAIMED_ATTR);
194
+ a = isAdopted(el);
195
+ b = isAdopted(prev);
181
196
  }
182
197
  catch {
183
198
  continue;
@@ -236,6 +251,32 @@ export function auditHydration(container) {
236
251
  if (!sample && container.outerHTML)
237
252
  sample = String(container.outerHTML).slice(0, 800);
238
253
  }
254
+ const structuralRecords = [];
255
+ const seenRecords = new Set();
256
+ const collectWalkerRecords = (el) => {
257
+ const records = walkerClaimRecords.get(el);
258
+ if (records) {
259
+ for (const record of records) {
260
+ if (!seenRecords.has(record)) {
261
+ seenRecords.add(record);
262
+ structuralRecords.push(record);
263
+ }
264
+ }
265
+ }
266
+ for (let i = 0; i < el.children.length; i++)
267
+ collectWalkerRecords(el.children[i]);
268
+ };
269
+ collectWalkerRecords(container);
270
+ const structuralGhosts = structuralRecords.filter((record) => record.state === 'ghost');
271
+ if (structuralGhosts.length > 0) {
272
+ unclaimed += structuralGhosts.length;
273
+ if (orphanNames.length < 5) {
274
+ orphanNames.push(`${structuralGhosts.length} structural hydration ghost(s) (${structuralGhosts
275
+ .slice(0, 3)
276
+ .map((record) => `<${record.actualTag}> expected <${record.expectedTag}>`)
277
+ .join(', ')})`);
278
+ }
279
+ }
239
280
  const twinRes = scanTwins(container);
240
281
  const issues = [];
241
282
  if (unclaimed > 0) {
@@ -268,6 +309,19 @@ export function auditHydration(container) {
268
309
  // Best-effort repair; the report above already recorded it.
269
310
  }
270
311
  }
312
+ for (const record of structuralGhosts) {
313
+ try {
314
+ // Only detach a still-connected ghost whose immediate parent is
315
+ // the walker's own root. Never sweep arbitrary descendants.
316
+ if (record.detached || !record.owner || record.el.parentNode !== record.owner)
317
+ continue;
318
+ record.el.remove();
319
+ record.detached = true;
320
+ }
321
+ catch {
322
+ // Best-effort repair; the report above already recorded it.
323
+ }
324
+ }
271
325
  }
272
326
  if (__mismatchHandler) {
273
327
  for (const issue of issues) {
@@ -308,7 +362,7 @@ export function assertFullyHydrated(container) {
308
362
  }
309
363
  function underClaimedAncestor(el, container) {
310
364
  for (let n = el; n && n !== container; n = n.parentElement) {
311
- if (n.nodeType === 1 && n.hasAttribute(CLAIMED_ATTR))
365
+ if (n.nodeType === 1 && isAdopted(n))
312
366
  return true;
313
367
  }
314
368
  return false;
@@ -384,7 +438,7 @@ function checkMarkerIdentity(marker, el) {
384
438
  }
385
439
  }
386
440
  }
387
- function adoptElement(marker, tag) {
441
+ function adoptElement(root, marker, tag) {
388
442
  const el = marker.nextElementSibling;
389
443
  if (!el) {
390
444
  marker.remove();
@@ -401,12 +455,12 @@ function adoptElement(marker, tag) {
401
455
  marker.remove();
402
456
  stripDirectTextNodes(el);
403
457
  captureSsrElementChildren(el);
404
- stampClaimed(el);
458
+ recordAdopted(root, el, tag || el.tagName.toLowerCase());
405
459
  return el;
406
460
  }
407
461
  // Like adoptElement but preserves direct text children. Used by static-component
408
462
  // stubs whose SSR content is kept as-is (no client-side re-rendering).
409
- function adoptElementRaw(marker, tag) {
463
+ function adoptElementRaw(root, marker, tag) {
410
464
  const el = marker.nextElementSibling;
411
465
  if (!el) {
412
466
  marker.remove();
@@ -417,7 +471,7 @@ function adoptElementRaw(marker, tag) {
417
471
  checkMarkerIdentity(marker, el);
418
472
  marker.remove();
419
473
  captureSsrElementChildren(el);
420
- stampClaimed(el);
474
+ recordAdopted(root, el, tag || el.tagName.toLowerCase());
421
475
  return el;
422
476
  }
423
477
  class WalkerEngine {
@@ -513,7 +567,7 @@ class WalkerEngine {
513
567
  break;
514
568
  }
515
569
  this.idx++;
516
- const adopted = adoptElement(tm.comment, tag);
570
+ const adopted = adoptElement(this.root, tm.comment, tag);
517
571
  if (adopted === null) {
518
572
  // SSR rendered no element after this marker. Fall out to a
519
573
  // fresh element instead of hunting through the remaining
@@ -589,7 +643,7 @@ class WalkerEngine {
589
643
  break;
590
644
  }
591
645
  this.idx++;
592
- const adopted = adoptElementRaw(tm.comment, tag);
646
+ const adopted = adoptElementRaw(this.root, tm.comment, tag);
593
647
  if (adopted === null) {
594
648
  tm.state = 'claimed';
595
649
  break;
@@ -694,7 +748,7 @@ class WalkerEngine {
694
748
  tm.comment.remove();
695
749
  stripDirectTextNodes(el);
696
750
  captureSsrElementChildren(el);
697
- stampClaimed(el);
751
+ recordAdopted(this.root, el, el.tagName.toLowerCase());
698
752
  return { el };
699
753
  }
700
754
  claimByKey(key, options) {
@@ -822,8 +876,9 @@ class WalkerEngine {
822
876
  // caller already consumed — static residues it retrieved from `__vsk_ssrEls`)
823
877
  // and by tag. The compiler emits `nextElement(tag, skipK)` claims with the
824
878
  // descriptor implicit in the tag; divergence follows §2.2 step 4: a tag
825
- // mismatch consumes exactly one slot, reports, and hands back a fresh element
826
- // that the caller mounts — the SSR node is never bound, never deleted.
879
+ // mismatch consumes exactly one slot, reports, detaches the provably-owned
880
+ // direct-child ghost, and hands back a fresh element that the caller mounts.
881
+ // The SSR node is never bound.
827
882
  //
828
883
  // The same engine backs `createHydrateChildWalker`, so runtime components that
829
884
  // claim offspring positionally (loading stubs, slot content) keep working with
@@ -923,12 +978,41 @@ class StructuralWalker {
923
978
  const el = this.els[target];
924
979
  if (tag && el.tagName.toLowerCase() !== tag) {
925
980
  // §2.2 step 4: descriptor failed. Consume exactly ONE slot and
926
- // hand back a fresh element — the SSR node is never bound, never
927
- // deleted. The caller detaches the fresh node when provably safe
928
- // or leaves it inert for the sweep.
981
+ // hand back a fresh element. The direct-child SSR ghost is
982
+ // detached below; nested recovery remains owned by its child walker.
929
983
  this.idx = this.advancePastSkippable(target + 1);
930
- reportMiss('tag-mismatch', `descriptor wanted <${tag}> but the SSR slot holds <${el.tagName.toLowerCase()}>; consuming one slot and rendering fresh.`, false);
931
- return document.createElement(tag || 'div');
984
+ const ghost = {
985
+ state: 'ghost',
986
+ el,
987
+ owner: this.root,
988
+ expectedTag: tag || 'div',
989
+ actualTag: el.tagName.toLowerCase(),
990
+ detached: false,
991
+ };
992
+ recordClaim(this.root, ghost);
993
+ // This is the walker's own immediate child slot, so detachment is
994
+ // provably boundary-local. Never remove nested content here: a
995
+ // nested mismatch belongs to the child walker's own recovery.
996
+ if (this.root && el.parentNode === this.root) {
997
+ try {
998
+ el.remove();
999
+ ghost.detached = true;
1000
+ }
1001
+ catch {
1002
+ // The final sweep will report/repair a still-owned ghost.
1003
+ }
1004
+ }
1005
+ const fresh = document.createElement(tag || 'div');
1006
+ recordClaim(this.root, {
1007
+ state: 'fresh',
1008
+ el: fresh,
1009
+ owner: this.root,
1010
+ expectedTag: tag || 'div',
1011
+ actualTag: fresh.tagName.toLowerCase(),
1012
+ detached: false,
1013
+ });
1014
+ reportMiss('tag-mismatch', `descriptor wanted <${tag}> but the SSR slot holds <${el.tagName.toLowerCase()}>; consumed one slot, detached the local ghost, and rendered fresh.`, false);
1015
+ return fresh;
932
1016
  }
933
1017
  if (this.adopted.has(el)) {
934
1018
  // Double-claim guard: a node already adopted (cross-position
@@ -941,16 +1025,25 @@ class StructuralWalker {
941
1025
  if (!raw)
942
1026
  stripDirectTextNodes(el);
943
1027
  captureSsrElementChildren(el);
944
- stampClaimed(el);
1028
+ recordAdopted(this.root, el, tag || el.tagName.toLowerCase());
945
1029
  return el;
946
1030
  }
947
1031
  this.idx = this.els.length;
1032
+ const fresh = document.createElement(tag || 'div');
1033
+ recordClaim(this.root, {
1034
+ state: 'fresh',
1035
+ el: fresh,
1036
+ owner: this.root,
1037
+ expectedTag: tag || 'div',
1038
+ actualTag: fresh.tagName.toLowerCase(),
1039
+ detached: false,
1040
+ });
948
1041
  reportMiss('exhausted', `hydration claim missed <${tag || 'element'}>; the client rendered more or different content than SSR.`,
949
1042
  // Not loud: an exhausted walker is the normal post-hydration
950
1043
  // re-render shape (every further claim legitimately builds fresh
951
1044
  // nodes) — telemetry-only, mirroring the marker engine.
952
1045
  false);
953
- return document.createElement(tag || 'div');
1046
+ return fresh;
954
1047
  }
955
1048
  nextElement(tag, skipK = 0) {
956
1049
  return this.claimAt(tag, skipK, false);
@@ -1016,7 +1109,7 @@ class StructuralWalker {
1016
1109
  this.adopted.add(el);
1017
1110
  stripDirectTextNodes(el);
1018
1111
  captureSsrElementChildren(el);
1019
- stampClaimed(el);
1112
+ recordAdopted(this.root, el, el.tagName.toLowerCase());
1020
1113
  return { el };
1021
1114
  }
1022
1115
  this.idx = this.els.length;
@@ -20,6 +20,8 @@ export { Experiment } from '@vesk/runtime/src/experiment';
20
20
  export { Form, Field, required, email, minLength, maxLength, pattern, custom } from '@vesk/runtime/src/form';
21
21
  export { Md } from '@vesk/runtime/src/md';
22
22
  export { Show, For, Switch, Match } from '@vesk/runtime/src/headless';
23
+ export { primitive, leaf, isPrimitive, isLeaf, isVeskComponent, toDomNode, rerenderNode } from '@vesk/runtime/src/primitive';
24
+ export type { VeskLeafComponent, VeskPrimitiveComponent, VeskTaggedLeafComponent, VeskComponentRegistry, VeskScope } from '@vesk/types';
23
25
  export { LoadingIndicator, useLoadingIndicator, configureLoadingIndicator, getLoadingProgress, isLoadingActive, getLoadingError, LOADING_INDICATOR_DEFAULT_COLOR, LOADING_INDICATOR_DEFAULT_ERROR_COLOR } from '@vesk/runtime/src/loading-indicator';
24
26
  export type { LoadingIndicatorHandle, LoadingIndicatorOptions, LoadingIndicatorProps } from '@vesk/runtime/src/loading-indicator';
25
27
  export { defineAction, getAction, clearActions, validateActionInput, issuesToFieldMap, isFormAction } from '@vesk/runtime/src/action';
@@ -1 +1 @@
1
- {"version":3,"file":"index-client.d.ts","sourceRoot":"","sources":["../src/index-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index-client.d.ts","sourceRoot":"","sources":["../src/index-client.ts"],"names":[],"mappings":"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"}
@@ -16,5 +16,6 @@ export { Experiment } from '@vesk/runtime/src/experiment';
16
16
  export { Form, Field, required, email, minLength, maxLength, pattern, custom } from '@vesk/runtime/src/form';
17
17
  export { Md } from '@vesk/runtime/src/md';
18
18
  export { Show, For, Switch, Match } from '@vesk/runtime/src/headless';
19
+ export { primitive, leaf, isPrimitive, isLeaf, isVeskComponent, toDomNode, rerenderNode } from '@vesk/runtime/src/primitive';
19
20
  export { LoadingIndicator, useLoadingIndicator, configureLoadingIndicator, getLoadingProgress, isLoadingActive, getLoadingError, LOADING_INDICATOR_DEFAULT_COLOR, LOADING_INDICATOR_DEFAULT_ERROR_COLOR } from '@vesk/runtime/src/loading-indicator';
20
21
  export { defineAction, getAction, clearActions, validateActionInput, issuesToFieldMap, isFormAction } from '@vesk/runtime/src/action';
@@ -13,6 +13,8 @@ export { Experiment } from '@vesk/runtime/src/experiment';
13
13
  export { Form, Field, required, email, minLength, maxLength, pattern, custom } from '@vesk/runtime/src/form';
14
14
  export { Md } from '@vesk/runtime/src/md';
15
15
  export { Show, For, Switch, Match } from '@vesk/runtime/src/headless';
16
+ export { primitive, leaf, isPrimitive, isLeaf, isVeskComponent, toDomNode, rerenderNode } from '@vesk/runtime/src/primitive';
17
+ export type { VeskLeafComponent, VeskPrimitiveComponent, VeskTaggedLeafComponent, VeskComponentRegistry, VeskScope } from '@vesk/types';
16
18
  export { LoadingIndicator, useLoadingIndicator, configureLoadingIndicator, getLoadingProgress, isLoadingActive, getLoadingError } from '@vesk/runtime/src/loading-indicator';
17
19
  export type { LoadingIndicatorHandle, LoadingIndicatorOptions, LoadingIndicatorProps } from '@vesk/runtime/src/loading-indicator';
18
20
  export { defineAction, getAction, clearActions, validateActionInput, issuesToFieldMap, isFormAction } from '@vesk/runtime/src/action';
@@ -1 +1 @@
1
- {"version":3,"file":"index-server.d.ts","sourceRoot":"","sources":["../src/index-server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index-server.d.ts","sourceRoot":"","sources":["../src/index-server.ts"],"names":[],"mappings":"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"}
@@ -13,5 +13,6 @@ export { Experiment } from '@vesk/runtime/src/experiment';
13
13
  export { Form, Field, required, email, minLength, maxLength, pattern, custom } from '@vesk/runtime/src/form';
14
14
  export { Md } from '@vesk/runtime/src/md';
15
15
  export { Show, For, Switch, Match } from '@vesk/runtime/src/headless';
16
+ export { primitive, leaf, isPrimitive, isLeaf, isVeskComponent, toDomNode, rerenderNode } from '@vesk/runtime/src/primitive';
16
17
  export { LoadingIndicator, useLoadingIndicator, configureLoadingIndicator, getLoadingProgress, isLoadingActive, getLoadingError } from '@vesk/runtime/src/loading-indicator';
17
18
  export { defineAction, getAction, clearActions, validateActionInput, issuesToFieldMap, isFormAction } from '@vesk/runtime/src/action';
@@ -0,0 +1,119 @@
1
+ /**
2
+ * `primitive` / `leaf` — the two authoring wrappers for the Vesk component ABI.
3
+ *
4
+ * Every component call in Vesk, including a bare `<Badge/>` with no
5
+ * attributes, is invoked as `callee(props, __registry, __veskScope)`. The
6
+ * compiler always passes an object literal at the call site (`{}` when there
7
+ * are no attributes), so `props` is never nullish coming *from the framework*.
8
+ *
9
+ * The gap this module closes is the other direction: a component exported from
10
+ * a module is an ordinary function, and an ordinary function can be called
11
+ * with no arguments at all — `Badge()` from a helper, a test, a render
12
+ * callback, or a manual `registry.get('Badge')!(undefined, reg, scope)` probe.
13
+ * A hand-written `function Badge(props) { return props.children }` throws
14
+ * `Cannot read properties of undefined` in that case. `primitive()` removes
15
+ * that whole class of failure by normalizing nullish props to a frozen empty
16
+ * object before the wrapped function ever sees them.
17
+ *
18
+ * `leaf()` is the behavioural counterpart: stateful widgets, own click
19
+ * handlers, async components. They implement the `VeskLeafComponent` ABI
20
+ * directly — the wrapper only stamps the marker so the two kinds can be told
21
+ * apart at runtime.
22
+ *
23
+ * Both wrappers are pure: no `document`/`window` access, no top-level side
24
+ * effects, safe to import from the client and server barrels alike.
25
+ */
26
+ import type { VeskComponentRegistry, VeskLeafComponent, VeskPrimitiveComponent, VeskScope, VeskTaggedLeafComponent } from '@vesk/types';
27
+ /**
28
+ * Wrap a presentational component so it is safe to call with no arguments.
29
+ *
30
+ * The wrapped function is *not* a copy of `fn` — it forwards `props`,
31
+ * `__registry` and the scope untouched, so identity-sensitive behavior
32
+ * (scope preference, `__veskScope`) is unchanged. Only a nullish `props` is
33
+ * substituted; a real props object is never cloned, merged or stripped, which
34
+ * matters because on the client `props.children` can be a live reactive
35
+ * container that must reach `fn` by reference.
36
+ *
37
+ * @param fn - The presentational component. Receives `(props, registry, scope)`.
38
+ * @returns A {@link VeskPrimitiveComponent} callable as `Badge()` or `<Badge/>`.
39
+ * @example
40
+ * ```ts
41
+ * const Badge = primitive((props) => `<span class="badge">${props.label ?? ''}</span>`);
42
+ * Badge(); // '' — no throw
43
+ * Badge({ label: 'new' }); // '<span class="badge">new</span>'
44
+ * ```
45
+ */
46
+ export declare function primitive<P extends object = Record<string, unknown>>(fn: (props: P, registry?: VeskComponentRegistry, scope?: VeskScope) => unknown | Promise<unknown>): VeskPrimitiveComponent<P>;
47
+ /**
48
+ * Tag a stateful/async component as a leaf so `isLeaf()` can identify it.
49
+ *
50
+ * Behaviourally a no-op — the function is returned as-is (plus the marker) so
51
+ * the `__veskScope` property the SSR renderer assigns to compiled components
52
+ * stays writable. Use it to document intent and to let tooling distinguish a
53
+ * behavioural widget from a `primitive()` one; do not use it to give a
54
+ * primitive extra behavior it cannot support.
55
+ *
56
+ * @param fn - The leaf component implementing `(props, registry, scope)`.
57
+ * @returns The same function, tagged with `__veskLeaf`.
58
+ * @example
59
+ * ```ts
60
+ * const Tabs = leaf((props, registry, scope) => {
61
+ * const &[open] = track(0);
62
+ * return `<div>${open}</div>`;
63
+ * });
64
+ * ```
65
+ */
66
+ export declare function leaf<P extends object = Record<string, unknown>>(fn: VeskLeafComponent<P>): VeskTaggedLeafComponent<P>;
67
+ /** True when `value` was produced by {@link primitive}. */
68
+ export declare function isPrimitive(value: unknown): value is VeskPrimitiveComponent;
69
+ /** True when `value` was tagged by {@link leaf}. */
70
+ export declare function isLeaf(value: unknown): value is VeskTaggedLeafComponent;
71
+ /**
72
+ * True when `value` is callable as a Vesk component — i.e. it is a function at
73
+ * all. Every registry entry satisfies this; the distinction that matters for
74
+ * authoring is {@link isPrimitive} vs {@link isLeaf}.
75
+ */
76
+ export declare function isVeskComponent(value: unknown): value is VeskLeafComponent;
77
+ /**
78
+ * Normalize a component call's return value into something the client renderer
79
+ * can insert.
80
+ *
81
+ * A compiled `.vsk` component returns a DOM `Node`, and the runtime components
82
+ * (`Image`, `Form`, `Md`, …) build one when `document` exists. A `primitive()`
83
+ * or `leaf()` written as a template string has no such branch — it returns a
84
+ * string on BOTH sides, because that is the whole point of the terse form. The
85
+ * server concatenates it into the HTML; the client would otherwise hand a
86
+ * string to `appendChild`/`replaceChild` and throw "parameter 1 is not of type
87
+ * 'Node'", taking the page's error boundary with it.
88
+ *
89
+ * So: a `Node` passes through untouched, a string is parsed into its root
90
+ * node(s), and every other value (including `null`/`undefined`/`false`, which
91
+ * callers test for) is returned as-is. On the server there is nothing to
92
+ * normalize into, so strings pass through unchanged.
93
+ */
94
+ export declare function toDomNode<T>(value: T): T | Node | DocumentFragment;
95
+ /**
96
+ * Keep a rendered markup node in sync with the tracked values it was built
97
+ * from, without re-invoking the component at mount.
98
+ *
99
+ * A `primitive()` or `leaf()` written as a template string is called once and
100
+ * its result is converted to DOM once. Tracked values it READ (through the
101
+ * `reactiveProps` proxy) therefore subscribe nobody: a later write updated the
102
+ * cell and left the markup stale, so a leaf driven by a parent's counter never
103
+ * moved. Compiled components avoid this because their bindings re-run; string
104
+ * components have no bindings, so the runtime re-runs the call and swaps the
105
+ * produced nodes in place.
106
+ *
107
+ * The dep list is read by the effect purely to SUBSCRIBE. The first effect run
108
+ * therefore performs no re-render — it compares against the values captured at
109
+ * mount, which also covers a write that lands between mount and the first
110
+ * flush. Re-rendering is skipped when the node has been detached (its owner was
111
+ * torn down), so a stale effect can never graft nodes back into the document.
112
+ *
113
+ * @param node - The node (or fragment) the mount already inserted.
114
+ * @param deps - Tracked cells / values the markup was derived from.
115
+ * @param call - Re-invokes the component and returns fresh markup.
116
+ * @returns `node`, so the call can wrap the mount expression in place.
117
+ */
118
+ export declare function rerenderNode<T>(node: T, deps: readonly unknown[], call: () => unknown): T;
119
+ //# sourceMappingURL=primitive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primitive.d.ts","sourceRoot":"","sources":["../src/primitive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EACX,qBAAqB,EACrB,iBAAiB,EACjB,sBAAsB,EACtB,SAAS,EACT,uBAAuB,EACvB,MAAM,aAAa,CAAC;AAmBrB;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnE,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,QAAQ,CAAC,EAAE,qBAAqB,EAAE,KAAK,CAAC,EAAE,SAAS,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAC/F,sBAAsB,CAAC,CAAC,CAAC,CAS3B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9D,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC,GACtB,uBAAuB,CAAC,CAAC,CAAC,CAG5B;AAED,2DAA2D;AAC3D,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,sBAAsB,CAE3E;AAED,oDAAoD;AACpD,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,uBAAuB,CAEvE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,iBAAiB,CAE1E;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,gBAAgB,CAwBlE;AAYD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,OAAO,GAAG,CAAC,CA4CzF"}
@@ -0,0 +1,234 @@
1
+ /**
2
+ * `primitive` / `leaf` — the two authoring wrappers for the Vesk component ABI.
3
+ *
4
+ * Every component call in Vesk, including a bare `<Badge/>` with no
5
+ * attributes, is invoked as `callee(props, __registry, __veskScope)`. The
6
+ * compiler always passes an object literal at the call site (`{}` when there
7
+ * are no attributes), so `props` is never nullish coming *from the framework*.
8
+ *
9
+ * The gap this module closes is the other direction: a component exported from
10
+ * a module is an ordinary function, and an ordinary function can be called
11
+ * with no arguments at all — `Badge()` from a helper, a test, a render
12
+ * callback, or a manual `registry.get('Badge')!(undefined, reg, scope)` probe.
13
+ * A hand-written `function Badge(props) { return props.children }` throws
14
+ * `Cannot read properties of undefined` in that case. `primitive()` removes
15
+ * that whole class of failure by normalizing nullish props to a frozen empty
16
+ * object before the wrapped function ever sees them.
17
+ *
18
+ * `leaf()` is the behavioural counterpart: stateful widgets, own click
19
+ * handlers, async components. They implement the `VeskLeafComponent` ABI
20
+ * directly — the wrapper only stamps the marker so the two kinds can be told
21
+ * apart at runtime.
22
+ *
23
+ * Both wrappers are pure: no `document`/`window` access, no top-level side
24
+ * effects, safe to import from the client and server barrels alike.
25
+ */
26
+ import { get } from '@vesk/runtime/src/ripple-runtime';
27
+ import { effect } from '@vesk/runtime/src/ripple-blocks';
28
+ /**
29
+ * Shared stand-in for "called with no props". Frozen so a primitive that
30
+ * mutates `props` by mistake fails loudly in strict mode instead of leaking
31
+ * state between unrelated zero-arg calls.
32
+ */
33
+ const EMPTY_PROPS = Object.freeze({});
34
+ /**
35
+ * Wrap a presentational component so it is safe to call with no arguments.
36
+ *
37
+ * The wrapped function is *not* a copy of `fn` — it forwards `props`,
38
+ * `__registry` and the scope untouched, so identity-sensitive behavior
39
+ * (scope preference, `__veskScope`) is unchanged. Only a nullish `props` is
40
+ * substituted; a real props object is never cloned, merged or stripped, which
41
+ * matters because on the client `props.children` can be a live reactive
42
+ * container that must reach `fn` by reference.
43
+ *
44
+ * @param fn - The presentational component. Receives `(props, registry, scope)`.
45
+ * @returns A {@link VeskPrimitiveComponent} callable as `Badge()` or `<Badge/>`.
46
+ * @example
47
+ * ```ts
48
+ * const Badge = primitive((props) => `<span class="badge">${props.label ?? ''}</span>`);
49
+ * Badge(); // '' — no throw
50
+ * Badge({ label: 'new' }); // '<span class="badge">new</span>'
51
+ * ```
52
+ */
53
+ export function primitive(fn) {
54
+ const wrapped = ((props, registry, scope) => {
55
+ // Nullish-only guard: any other value is the caller's business. A frozen
56
+ // singleton avoids an allocation per zero-arg call and keeps `Object.is`
57
+ // stable for the common no-props case.
58
+ return fn(props == null ? EMPTY_PROPS : props, registry, scope);
59
+ });
60
+ wrapped.__veskPrimitive = true;
61
+ return wrapped;
62
+ }
63
+ /**
64
+ * Tag a stateful/async component as a leaf so `isLeaf()` can identify it.
65
+ *
66
+ * Behaviourally a no-op — the function is returned as-is (plus the marker) so
67
+ * the `__veskScope` property the SSR renderer assigns to compiled components
68
+ * stays writable. Use it to document intent and to let tooling distinguish a
69
+ * behavioural widget from a `primitive()` one; do not use it to give a
70
+ * primitive extra behavior it cannot support.
71
+ *
72
+ * @param fn - The leaf component implementing `(props, registry, scope)`.
73
+ * @returns The same function, tagged with `__veskLeaf`.
74
+ * @example
75
+ * ```ts
76
+ * const Tabs = leaf((props, registry, scope) => {
77
+ * const &[open] = track(0);
78
+ * return `<div>${open}</div>`;
79
+ * });
80
+ * ```
81
+ */
82
+ export function leaf(fn) {
83
+ fn.__veskLeaf = true;
84
+ return fn;
85
+ }
86
+ /** True when `value` was produced by {@link primitive}. */
87
+ export function isPrimitive(value) {
88
+ return typeof value === 'function' && value.__veskPrimitive === true;
89
+ }
90
+ /** True when `value` was tagged by {@link leaf}. */
91
+ export function isLeaf(value) {
92
+ return typeof value === 'function' && value.__veskLeaf === true;
93
+ }
94
+ /**
95
+ * True when `value` is callable as a Vesk component — i.e. it is a function at
96
+ * all. Every registry entry satisfies this; the distinction that matters for
97
+ * authoring is {@link isPrimitive} vs {@link isLeaf}.
98
+ */
99
+ export function isVeskComponent(value) {
100
+ return typeof value === 'function';
101
+ }
102
+ /**
103
+ * Normalize a component call's return value into something the client renderer
104
+ * can insert.
105
+ *
106
+ * A compiled `.vsk` component returns a DOM `Node`, and the runtime components
107
+ * (`Image`, `Form`, `Md`, …) build one when `document` exists. A `primitive()`
108
+ * or `leaf()` written as a template string has no such branch — it returns a
109
+ * string on BOTH sides, because that is the whole point of the terse form. The
110
+ * server concatenates it into the HTML; the client would otherwise hand a
111
+ * string to `appendChild`/`replaceChild` and throw "parameter 1 is not of type
112
+ * 'Node'", taking the page's error boundary with it.
113
+ *
114
+ * So: a `Node` passes through untouched, a string is parsed into its root
115
+ * node(s), and every other value (including `null`/`undefined`/`false`, which
116
+ * callers test for) is returned as-is. On the server there is nothing to
117
+ * normalize into, so strings pass through unchanged.
118
+ */
119
+ export function toDomNode(value) {
120
+ if (typeof document === 'undefined')
121
+ return value;
122
+ if (value == null || typeof value === 'boolean')
123
+ return value;
124
+ if (typeof value.nodeType === 'number') {
125
+ return value;
126
+ }
127
+ if (typeof value !== 'string')
128
+ return value;
129
+ if (value === '')
130
+ return document.createDocumentFragment();
131
+ const template = document.createElement('template');
132
+ template.innerHTML = value;
133
+ const { content } = template;
134
+ // A single root becomes that node; several roots stay a fragment so the
135
+ // caller can splice them in without inventing a wrapper element that was
136
+ // never in the SSR markup.
137
+ if (content.childNodes.length === 1) {
138
+ const only = content.firstChild;
139
+ // Detach before returning: a node still parented to the template's
140
+ // content fragment reads as "already mounted" to the compiler's
141
+ // hydrate guard (`value.parentNode == null`), so the fresh node would
142
+ // never be inserted and the claimed SSR node would be retired instead.
143
+ content.removeChild(only);
144
+ return only;
145
+ }
146
+ return content;
147
+ }
148
+ /** True when `value` is a tracked cell (the shape `get`/`set` operate on). */
149
+ function isCell(value) {
150
+ return typeof value === 'object' && value !== null && typeof value.f === 'number';
151
+ }
152
+ /** Read a dep as the value a render would see: cells unwrap, literals pass. */
153
+ function readDep(dep) {
154
+ return isCell(dep) ? get(dep) : dep;
155
+ }
156
+ /**
157
+ * Keep a rendered markup node in sync with the tracked values it was built
158
+ * from, without re-invoking the component at mount.
159
+ *
160
+ * A `primitive()` or `leaf()` written as a template string is called once and
161
+ * its result is converted to DOM once. Tracked values it READ (through the
162
+ * `reactiveProps` proxy) therefore subscribe nobody: a later write updated the
163
+ * cell and left the markup stale, so a leaf driven by a parent's counter never
164
+ * moved. Compiled components avoid this because their bindings re-run; string
165
+ * components have no bindings, so the runtime re-runs the call and swaps the
166
+ * produced nodes in place.
167
+ *
168
+ * The dep list is read by the effect purely to SUBSCRIBE. The first effect run
169
+ * therefore performs no re-render — it compares against the values captured at
170
+ * mount, which also covers a write that lands between mount and the first
171
+ * flush. Re-rendering is skipped when the node has been detached (its owner was
172
+ * torn down), so a stale effect can never graft nodes back into the document.
173
+ *
174
+ * @param node - The node (or fragment) the mount already inserted.
175
+ * @param deps - Tracked cells / values the markup was derived from.
176
+ * @param call - Re-invokes the component and returns fresh markup.
177
+ * @returns `node`, so the call can wrap the mount expression in place.
178
+ */
179
+ export function rerenderNode(node, deps, call) {
180
+ if (typeof document === 'undefined')
181
+ return node;
182
+ if (deps.length === 0)
183
+ return node;
184
+ // The markup this call site owns. A component that rendered several roots
185
+ // hands them over as a list: the call site drains the fragment into the
186
+ // mount point, so by the time this runs the fragment itself is detached and
187
+ // useless as a handle. The list is followed as one range, which lets a
188
+ // later render add, drop or reorder roots.
189
+ let owned = null;
190
+ let current = null;
191
+ if (Array.isArray(node)) {
192
+ const roots = node.filter((n) => n && typeof n.nodeType === 'number');
193
+ owned = roots.length ? roots : null;
194
+ current = owned ? owned[0] : null;
195
+ }
196
+ else if (node && typeof node.nodeType === 'number') {
197
+ current = node;
198
+ }
199
+ if (!current)
200
+ return node;
201
+ const liveRange = () => {
202
+ if (owned)
203
+ return owned;
204
+ return current && current.parentNode ? [current] : null;
205
+ };
206
+ let seen = deps.map(readDep);
207
+ effect(() => {
208
+ const now = deps.map(readDep);
209
+ if (now.length === seen.length && now.every((v, i) => Object.is(v, seen[i])))
210
+ return;
211
+ seen = now;
212
+ // Detachment is checked BEFORE re-invoking: once the owner is gone the
213
+ // component must not run again (side effects, fetches) and its markup
214
+ // must never be grafted back into the document.
215
+ const old = liveRange();
216
+ if (!old || !old[0].parentNode)
217
+ return;
218
+ const next = toDomNode(call());
219
+ if (!next || typeof next.nodeType !== 'number')
220
+ return;
221
+ // Snapshot the children before inserting: moving them out empties the
222
+ // fragment, which is what tells us whether this render had several roots.
223
+ const fresh = next.nodeType === 11 ? Array.from(next.childNodes) : [next];
224
+ const parent = old[0].parentNode;
225
+ for (const freshNode of fresh)
226
+ parent.insertBefore(freshNode, old[0]);
227
+ for (const oldNode of old)
228
+ if (oldNode.parentNode)
229
+ oldNode.parentNode.removeChild(oldNode);
230
+ owned = next.nodeType === 11 ? fresh : null;
231
+ current = fresh[0] ?? current;
232
+ });
233
+ return node;
234
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vesk/runtime",
3
- "version": "0.2.41",
3
+ "version": "0.2.43",
4
4
  "type": "module",
5
5
  "description": "Vesk runtime — reactivity, blocks, DOM operations, hydration",
6
6
  "main": "./dist/index-client.js",
@@ -51,7 +51,7 @@
51
51
  }
52
52
  },
53
53
  "dependencies": {
54
- "@vesk/compiler": "^0.2.41"
54
+ "@vesk/compiler": "^0.2.43"
55
55
  },
56
56
  "scripts": {
57
57
  "typecheck": "tsc --noEmit",