@c9up/aurora 0.1.15 → 0.1.16
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/hydrate.js +23 -48
- package/package.json +1 -1
- package/src/hydrate.ts +30 -59
package/dist/hydrate.js
CHANGED
|
@@ -358,29 +358,11 @@ function hydrateSlot(slot, node, value, cleanups, mountHooks, markerCursor) {
|
|
|
358
358
|
}
|
|
359
359
|
}
|
|
360
360
|
/**
|
|
361
|
-
* Hydrate a text slot
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
*
|
|
365
|
-
*
|
|
366
|
-
* For reactive values (signals/functions), the effect updates the
|
|
367
|
-
* existing text node in place. For nested TemplateResults, we
|
|
368
|
-
* recursively hydrate against the captured sibling range.
|
|
369
|
-
*/
|
|
370
|
-
/**
|
|
371
|
-
* First text node inside a marker pair's range, or a fresh empty one inserted
|
|
372
|
-
* before the end marker (when the SSR value was empty → no text node yet).
|
|
361
|
+
* Hydrate a text slot against its SSR boundary-marker pair. A reactive slot
|
|
362
|
+
* (signal/function) always goes through the swap-capable structured path so a
|
|
363
|
+
* value that changes type (scalar ↔ template ↔ array) re-renders correctly; a
|
|
364
|
+
* direct template/array adopts its SSR range once; a static scalar is left as-is.
|
|
373
365
|
*/
|
|
374
|
-
function reactiveTextNode(pair) {
|
|
375
|
-
for (let n = pair.start.nextSibling; n !== null && n !== pair.end; n = n.nextSibling) {
|
|
376
|
-
if (n.nodeType === 3 /* TEXT */)
|
|
377
|
-
return n;
|
|
378
|
-
}
|
|
379
|
-
const doc = pair.end.ownerDocument ?? document;
|
|
380
|
-
const fresh = doc.createTextNode("");
|
|
381
|
-
pair.end.parentNode?.insertBefore(fresh, pair.end);
|
|
382
|
-
return fresh;
|
|
383
|
-
}
|
|
384
366
|
function hydrateTextSlot(commentMarker, value, cleanups, mountHooks, markerCursor) {
|
|
385
367
|
// Every text slot is SSR-wrapped in a <!--$-->…<!--/$--> pair, and its path
|
|
386
368
|
// resolves (via collapseMarkerRanges) to the start marker. Consume the
|
|
@@ -395,39 +377,32 @@ function hydrateTextSlot(commentMarker, value, cleanups, mountHooks, markerCurso
|
|
|
395
377
|
const reactiveFn = isSignal(value) || typeof value === "function"
|
|
396
378
|
? value
|
|
397
379
|
: null;
|
|
398
|
-
|
|
399
|
-
//
|
|
400
|
-
//
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
380
|
+
// Reactive slot — its value TYPE can change across renders (scalar ↔ template
|
|
381
|
+
// ↔ array), e.g. `${() => collapsed() ? '' : html`<span>…</span>`}`. Always
|
|
382
|
+
// use the swap-capable structured path: its effect re-renders the value
|
|
383
|
+
// (whatever type) into the marker range via renderValueToNodes. Locking a
|
|
384
|
+
// reactive slot to a scalar text-node effect (based on its FIRST value) would
|
|
385
|
+
// String() a later template/array into "[object Object]".
|
|
386
|
+
if (reactiveFn) {
|
|
387
|
+
hydrateReactiveStructured(reactiveFn, pair, cleanups, mountHooks, markerCursor);
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
// Non-reactive (direct) value — adopt the SSR range once.
|
|
391
|
+
if (isTemplateResult(value) || Array.isArray(value)) {
|
|
406
392
|
const range = [];
|
|
407
393
|
for (let n = pair.start.nextSibling; n !== null && n !== pair.end; n = n.nextSibling) {
|
|
408
394
|
range.push(n);
|
|
409
395
|
}
|
|
410
|
-
if (isTemplateResult(
|
|
411
|
-
hydrateTemplateResult(
|
|
396
|
+
if (isTemplateResult(value)) {
|
|
397
|
+
hydrateTemplateResult(value, range, cleanups, mountHooks, markerCursor);
|
|
412
398
|
}
|
|
413
|
-
else if (Array.isArray(
|
|
414
|
-
// Direct
|
|
415
|
-
//
|
|
416
|
-
|
|
417
|
-
hydrateArrayItems(current, range, cleanups, mountHooks, markerCursor);
|
|
399
|
+
else if (Array.isArray(value)) {
|
|
400
|
+
// Direct array — hydrate each item so its inner marker pairs are
|
|
401
|
+
// consumed and the cursor stays aligned.
|
|
402
|
+
hydrateArrayItems(value, range, cleanups, mountHooks, markerCursor);
|
|
418
403
|
}
|
|
419
|
-
return;
|
|
420
|
-
}
|
|
421
|
-
// Scalar: a reactive scalar updates the range's text node on change; a static
|
|
422
|
-
// scalar is already rendered between the markers (nothing to wire).
|
|
423
|
-
if (reactiveFn) {
|
|
424
|
-
const textNode = reactiveTextNode(pair);
|
|
425
|
-
const dispose = effect(() => {
|
|
426
|
-
const v = reactiveFn();
|
|
427
|
-
textNode.data = v == null || v === false ? "" : String(v);
|
|
428
|
-
});
|
|
429
|
-
cleanups.push(dispose);
|
|
430
404
|
}
|
|
405
|
+
// else: static scalar — already rendered between the markers.
|
|
431
406
|
}
|
|
432
407
|
/**
|
|
433
408
|
* Pre-marker fallback — best-effort hydration when the SSR markup carries no
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@c9up/aurora",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"description": "Aurora — reactive UI runtime for the Ream framework. Tagged-template DOM, signal-based state, isomorphic SSR + hydration, zero build step.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/src/hydrate.ts
CHANGED
|
@@ -481,33 +481,11 @@ function hydrateSlot(
|
|
|
481
481
|
}
|
|
482
482
|
|
|
483
483
|
/**
|
|
484
|
-
* Hydrate a text slot
|
|
485
|
-
*
|
|
486
|
-
*
|
|
487
|
-
*
|
|
488
|
-
*
|
|
489
|
-
* For reactive values (signals/functions), the effect updates the
|
|
490
|
-
* existing text node in place. For nested TemplateResults, we
|
|
491
|
-
* recursively hydrate against the captured sibling range.
|
|
492
|
-
*/
|
|
493
|
-
/**
|
|
494
|
-
* First text node inside a marker pair's range, or a fresh empty one inserted
|
|
495
|
-
* before the end marker (when the SSR value was empty → no text node yet).
|
|
484
|
+
* Hydrate a text slot against its SSR boundary-marker pair. A reactive slot
|
|
485
|
+
* (signal/function) always goes through the swap-capable structured path so a
|
|
486
|
+
* value that changes type (scalar ↔ template ↔ array) re-renders correctly; a
|
|
487
|
+
* direct template/array adopts its SSR range once; a static scalar is left as-is.
|
|
496
488
|
*/
|
|
497
|
-
function reactiveTextNode(pair: MarkerPair): Text {
|
|
498
|
-
for (
|
|
499
|
-
let n = pair.start.nextSibling;
|
|
500
|
-
n !== null && n !== pair.end;
|
|
501
|
-
n = n.nextSibling
|
|
502
|
-
) {
|
|
503
|
-
if (n.nodeType === 3 /* TEXT */) return n as Text;
|
|
504
|
-
}
|
|
505
|
-
const doc = pair.end.ownerDocument ?? document;
|
|
506
|
-
const fresh = doc.createTextNode("");
|
|
507
|
-
pair.end.parentNode?.insertBefore(fresh, pair.end);
|
|
508
|
-
return fresh;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
489
|
function hydrateTextSlot(
|
|
512
490
|
commentMarker: Node,
|
|
513
491
|
value: unknown,
|
|
@@ -536,21 +514,26 @@ function hydrateTextSlot(
|
|
|
536
514
|
isSignal(value) || typeof value === "function"
|
|
537
515
|
? (value as () => unknown)
|
|
538
516
|
: null;
|
|
539
|
-
const current = reactiveFn ? reactiveFn() : value;
|
|
540
517
|
|
|
541
|
-
//
|
|
542
|
-
//
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
518
|
+
// Reactive slot — its value TYPE can change across renders (scalar ↔ template
|
|
519
|
+
// ↔ array), e.g. `${() => collapsed() ? '' : html`<span>…</span>`}`. Always
|
|
520
|
+
// use the swap-capable structured path: its effect re-renders the value
|
|
521
|
+
// (whatever type) into the marker range via renderValueToNodes. Locking a
|
|
522
|
+
// reactive slot to a scalar text-node effect (based on its FIRST value) would
|
|
523
|
+
// String() a later template/array into "[object Object]".
|
|
524
|
+
if (reactiveFn) {
|
|
525
|
+
hydrateReactiveStructured(
|
|
526
|
+
reactiveFn,
|
|
527
|
+
pair,
|
|
528
|
+
cleanups,
|
|
529
|
+
mountHooks,
|
|
530
|
+
markerCursor,
|
|
531
|
+
);
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// Non-reactive (direct) value — adopt the SSR range once.
|
|
536
|
+
if (isTemplateResult(value) || Array.isArray(value)) {
|
|
554
537
|
const range: ChildNode[] = [];
|
|
555
538
|
for (
|
|
556
539
|
let n = pair.start.nextSibling;
|
|
@@ -559,27 +542,15 @@ function hydrateTextSlot(
|
|
|
559
542
|
) {
|
|
560
543
|
range.push(n as ChildNode);
|
|
561
544
|
}
|
|
562
|
-
if (isTemplateResult(
|
|
563
|
-
hydrateTemplateResult(
|
|
564
|
-
} else if (Array.isArray(
|
|
565
|
-
// Direct
|
|
566
|
-
//
|
|
567
|
-
|
|
568
|
-
hydrateArrayItems(current, range, cleanups, mountHooks, markerCursor);
|
|
545
|
+
if (isTemplateResult(value)) {
|
|
546
|
+
hydrateTemplateResult(value, range, cleanups, mountHooks, markerCursor);
|
|
547
|
+
} else if (Array.isArray(value)) {
|
|
548
|
+
// Direct array — hydrate each item so its inner marker pairs are
|
|
549
|
+
// consumed and the cursor stays aligned.
|
|
550
|
+
hydrateArrayItems(value, range, cleanups, mountHooks, markerCursor);
|
|
569
551
|
}
|
|
570
|
-
return;
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
// Scalar: a reactive scalar updates the range's text node on change; a static
|
|
574
|
-
// scalar is already rendered between the markers (nothing to wire).
|
|
575
|
-
if (reactiveFn) {
|
|
576
|
-
const textNode = reactiveTextNode(pair);
|
|
577
|
-
const dispose = effect(() => {
|
|
578
|
-
const v = reactiveFn();
|
|
579
|
-
textNode.data = v == null || v === false ? "" : String(v);
|
|
580
|
-
});
|
|
581
|
-
cleanups.push(dispose);
|
|
582
552
|
}
|
|
553
|
+
// else: static scalar — already rendered between the markers.
|
|
583
554
|
}
|
|
584
555
|
|
|
585
556
|
/**
|