@askrjs/askr 0.0.99 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/benchmark.js +4 -4
- package/dist/boot/index.js +1 -1
- package/dist/{boot-DE-JutXH.js → boot-BjldNXqF.js} +267 -87
- package/dist/foundations/interactions/index.d.ts +8 -1
- package/dist/foundations/interactions/index.js +1 -1
- package/dist/fx/index.js +12 -11
- package/dist/index.js +1 -1
- package/dist/{interactions-B4XaFxt1.js → interactions-B-7vkBgx.js} +3 -2
- package/dist/{renderer-tXX_xj86.js → renderer-Cg92QKOm.js} +112 -4
- package/dist/router/index.js +1 -1
- package/dist/testing/index.js +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -91,8 +91,9 @@ Query and mutation helpers live in `@askrjs/askr/data`.
|
|
|
91
91
|
### Developer error boundaries
|
|
92
92
|
|
|
93
93
|
`ErrorBoundary` is the opt-in boundary primitive for render-time failures. It
|
|
94
|
-
renders a visible fallback in
|
|
95
|
-
|
|
94
|
+
renders a visible fallback in every environment (with error details expanded
|
|
95
|
+
by default in development), still logs the underlying error, and can reset via
|
|
96
|
+
a `resetKey` tied to your app state. The boundary protects both initial mount
|
|
96
97
|
and scheduled post-mount updates. Portal content follows its logical writer
|
|
97
98
|
boundary and can also recover through a boundary around its host.
|
|
98
99
|
|
package/dist/benchmark.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { r as flushRuntimeScheduler } from "./access-d_DCdwqn.js";
|
|
2
2
|
import { t as state } from "./state-DmkGM_LN.js";
|
|
3
3
|
import { t as selector } from "./selector-CyK-sDwB.js";
|
|
4
|
-
import { t as installRendererBridge } from "./renderer-
|
|
4
|
+
import { t as installRendererBridge } from "./renderer-Cg92QKOm.js";
|
|
5
5
|
import { i as For } from "./control-C0klPV7Q.js";
|
|
6
6
|
import { jsx, jsxs } from "./jsx-runtime.js";
|
|
7
|
-
import { t as createIsland } from "./boot-
|
|
7
|
+
import { t as createIsland } from "./boot-BjldNXqF.js";
|
|
8
8
|
//#region src/bench/components/benchmark-row.tsx
|
|
9
9
|
function BenchmarkRow({ item, isSelected, onSelect, onRemove }) {
|
|
10
10
|
return /* @__PURE__ */ jsxs("tr", {
|
|
@@ -63,8 +63,8 @@ function BenchmarkTable({ rows, isSelected, onSelect, onRemove }) {
|
|
|
63
63
|
installRendererBridge();
|
|
64
64
|
const benchmarkMetadata = {
|
|
65
65
|
packageName: "@askrjs/askr",
|
|
66
|
-
packageVersion: "0.0
|
|
67
|
-
buildLabel: "0.0
|
|
66
|
+
packageVersion: "0.2.0",
|
|
67
|
+
buildLabel: "0.2.0-local"
|
|
68
68
|
};
|
|
69
69
|
function getBenchmarkMetadata() {
|
|
70
70
|
return { ...benchmarkMetadata };
|
package/dist/boot/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as cleanupApp, i as hydrateSPA, n as createIslands, o as hasApp, r as createSPA, t as createIsland } from "../boot-
|
|
1
|
+
import { a as cleanupApp, i as hydrateSPA, n as createIslands, o as hasApp, r as createSPA, t as createIsland } from "../boot-BjldNXqF.js";
|
|
2
2
|
export { cleanupApp, createIsland, createIslands, createSPA, hasApp, hydrateSPA };
|
|
@@ -6,7 +6,7 @@ import { p as isPromiseLike } from "./lifecycle-batch-BH0fax4F.js";
|
|
|
6
6
|
import { _ as teardownNodeSubtree, d as removeAllListeners } from "./cleanup-D7uN-Z1s.js";
|
|
7
7
|
import { r as assertExecutionModel, t as _applyManifest } from "./manifest-D6rfj_jC.js";
|
|
8
8
|
import { d as stopHydrationRenderPhase, l as startHydrationRenderPhase, y as pageRenderEnvelope } from "./render-context-B7ohlh6t.js";
|
|
9
|
-
import { a as setStaticChildSlotsCacheEnabled, c as endHydrationDirectListenerMode, d as discardHydrationListenerTransaction, i as registerDeferredHydrationBoundary, l as beginHydrationListenerTransaction, n as activateHydrationBoundary$1, o as withIntrinsicHydrationAdoption, r as clearDeferredHydrationBoundaries, s as beginHydrationDirectListenerMode, t as installRendererBridge, u as commitHydrationListenerTransaction } from "./renderer-
|
|
9
|
+
import { a as setStaticChildSlotsCacheEnabled, c as endHydrationDirectListenerMode, d as discardHydrationListenerTransaction, i as registerDeferredHydrationBoundary, l as beginHydrationListenerTransaction, n as activateHydrationBoundary$1, o as withIntrinsicHydrationAdoption, r as clearDeferredHydrationBoundaries, s as beginHydrationDirectListenerMode, t as installRendererBridge, u as commitHydrationListenerTransaction } from "./renderer-Cg92QKOm.js";
|
|
10
10
|
import { r as validateCspNonce, t as CspNonceScope } from "./csp-nonce-BVybpV1v.js";
|
|
11
11
|
import { i as getDefaultDataRuntime } from "./data-runtime-7t_Y0iv3.js";
|
|
12
12
|
import { a as hydrateDataRuntime } from "./query-registry-Bua3cDyb.js";
|
|
@@ -108,7 +108,7 @@ function shouldVerifyHydrationMarkup(config) {
|
|
|
108
108
|
if (typeof explicit === "boolean") return explicit;
|
|
109
109
|
return !isProductionEnvironment();
|
|
110
110
|
}
|
|
111
|
-
async function applySelectiveHydration(rootElement, resolved, path, cleanupStrict, hydrateOptions, source, hooks) {
|
|
111
|
+
async function applySelectiveHydration(rootElement, resolved, path, cleanupStrict, hydrateOptions, source, hooks, interactionReplay) {
|
|
112
112
|
const hasPermanentSkips = (hydrateOptions.skipSelectors?.length ?? 0) > 0;
|
|
113
113
|
const hasBelowFoldDeferral = !!hydrateOptions.deferBelowFold;
|
|
114
114
|
const hasSelectiveBoundaries = hasPermanentSkips || hasBelowFoldDeferral;
|
|
@@ -126,6 +126,7 @@ async function applySelectiveHydration(rootElement, resolved, path, cleanupStric
|
|
|
126
126
|
staticChildSlotsCacheSuspended = true;
|
|
127
127
|
const foldY = hydrateOptions.foldThreshold ?? window.innerHeight;
|
|
128
128
|
deferredBoundaries = collectDeferredBelowFoldBoundaries(rootElement, foldY);
|
|
129
|
+
interactionReplay.registerDeferredBoundaries(deferredBoundaries);
|
|
129
130
|
let selectiveHydrationResourcesReleased = false;
|
|
130
131
|
let unregisterRootCleanupCallback = () => {};
|
|
131
132
|
function handleScroll() {
|
|
@@ -139,7 +140,9 @@ async function applySelectiveHydration(rootElement, resolved, path, cleanupStric
|
|
|
139
140
|
unregisterRootCleanupCallback();
|
|
140
141
|
window.removeEventListener("scroll", handleScroll);
|
|
141
142
|
restoreStaticChildSlotsCache();
|
|
143
|
+
interactionReplay.clearDeferredBoundaries();
|
|
142
144
|
};
|
|
145
|
+
interactionReplay.setOnDeferredBoundariesDrained(releaseSelectiveHydrationResources);
|
|
143
146
|
unregisterRootCleanupCallback = hooks.registerRootCleanupCallback(rootElement, releaseSelectiveHydrationResources);
|
|
144
147
|
window.addEventListener("scroll", handleScroll, { passive: true });
|
|
145
148
|
}
|
|
@@ -440,6 +443,175 @@ async function resolveInitialRoute(auth, source) {
|
|
|
440
443
|
throw new Error(`[Askr] Route redirect limit exceeded (${MAX_INITIAL_ROUTE_REDIRECTS}).`);
|
|
441
444
|
}
|
|
442
445
|
//#endregion
|
|
446
|
+
//#region src/boot/hydration-interaction-replay.ts
|
|
447
|
+
const HYDRATION_INTERACTION_TYPES = [
|
|
448
|
+
"click",
|
|
449
|
+
"dblclick",
|
|
450
|
+
"pointerdown",
|
|
451
|
+
"pointerup",
|
|
452
|
+
"keydown",
|
|
453
|
+
"keyup",
|
|
454
|
+
"input",
|
|
455
|
+
"change",
|
|
456
|
+
"submit"
|
|
457
|
+
];
|
|
458
|
+
function cloneInteractionEvent(event) {
|
|
459
|
+
const EventConstructor = event.constructor;
|
|
460
|
+
const eventWithDetails = event;
|
|
461
|
+
const init = {
|
|
462
|
+
bubbles: event.bubbles,
|
|
463
|
+
cancelable: event.cancelable,
|
|
464
|
+
composed: event.composed,
|
|
465
|
+
detail: eventWithDetails.detail,
|
|
466
|
+
view: eventWithDetails.view,
|
|
467
|
+
key: eventWithDetails.key,
|
|
468
|
+
code: eventWithDetails.code,
|
|
469
|
+
location: eventWithDetails.location,
|
|
470
|
+
repeat: eventWithDetails.repeat,
|
|
471
|
+
isComposing: eventWithDetails.isComposing,
|
|
472
|
+
ctrlKey: eventWithDetails.ctrlKey,
|
|
473
|
+
shiftKey: eventWithDetails.shiftKey,
|
|
474
|
+
altKey: eventWithDetails.altKey,
|
|
475
|
+
metaKey: eventWithDetails.metaKey,
|
|
476
|
+
button: eventWithDetails.button,
|
|
477
|
+
buttons: eventWithDetails.buttons,
|
|
478
|
+
clientX: eventWithDetails.clientX,
|
|
479
|
+
clientY: eventWithDetails.clientY,
|
|
480
|
+
screenX: eventWithDetails.screenX,
|
|
481
|
+
screenY: eventWithDetails.screenY,
|
|
482
|
+
pointerId: eventWithDetails.pointerId,
|
|
483
|
+
pointerType: eventWithDetails.pointerType,
|
|
484
|
+
isPrimary: eventWithDetails.isPrimary,
|
|
485
|
+
data: eventWithDetails.data,
|
|
486
|
+
inputType: eventWithDetails.inputType
|
|
487
|
+
};
|
|
488
|
+
try {
|
|
489
|
+
return new EventConstructor(event.type, init);
|
|
490
|
+
} catch {
|
|
491
|
+
return new Event(event.type, {
|
|
492
|
+
bubbles: event.bubbles,
|
|
493
|
+
cancelable: event.cancelable,
|
|
494
|
+
composed: event.composed
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Capture discrete interactions before hydrated handlers exist, then replay
|
|
500
|
+
* them after the listener transaction commits. Deferred boundaries remain
|
|
501
|
+
* interaction-activatable until they are revealed or the root is cleaned up.
|
|
502
|
+
*/
|
|
503
|
+
function beginHydrationInteractionReplay(root, activateBoundary, permanentSkipSelectors = []) {
|
|
504
|
+
const queued = [];
|
|
505
|
+
const deferredBoundaries = /* @__PURE__ */ new Set();
|
|
506
|
+
let active = true;
|
|
507
|
+
let hydratingRoot = true;
|
|
508
|
+
let replaying = false;
|
|
509
|
+
let hadDeferredBoundaries = false;
|
|
510
|
+
let onDeferredBoundariesDrained;
|
|
511
|
+
function isPermanentlySkipped(target) {
|
|
512
|
+
const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
|
|
513
|
+
if (!element) return false;
|
|
514
|
+
return permanentSkipSelectors.some((selector) => {
|
|
515
|
+
try {
|
|
516
|
+
return element.closest(selector) !== null;
|
|
517
|
+
} catch {
|
|
518
|
+
return false;
|
|
519
|
+
}
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
function findDeferredBoundary(target) {
|
|
523
|
+
if (!(target instanceof Node)) return;
|
|
524
|
+
for (const boundary of deferredBoundaries) if (boundary.hasAttribute("data-skip-hydrate") && boundary.contains(target)) return boundary;
|
|
525
|
+
}
|
|
526
|
+
function removeCaptureListeners() {
|
|
527
|
+
if (!active) return;
|
|
528
|
+
active = false;
|
|
529
|
+
for (const type of HYDRATION_INTERACTION_TYPES) root.removeEventListener(type, captureInteraction, true);
|
|
530
|
+
}
|
|
531
|
+
function releaseIfFinished() {
|
|
532
|
+
if (!hydratingRoot && deferredBoundaries.size === 0) removeCaptureListeners();
|
|
533
|
+
}
|
|
534
|
+
function notifyIfDeferredBoundariesDrained() {
|
|
535
|
+
if (hadDeferredBoundaries && deferredBoundaries.size === 0) onDeferredBoundariesDrained?.();
|
|
536
|
+
}
|
|
537
|
+
function replayInteraction(interaction) {
|
|
538
|
+
if (!(interaction.target instanceof Node) || !root.contains(interaction.target)) return;
|
|
539
|
+
const boundary = findDeferredBoundary(interaction.target);
|
|
540
|
+
if (boundary) {
|
|
541
|
+
try {
|
|
542
|
+
if (!activateBoundary(boundary)) return;
|
|
543
|
+
} catch {
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
deferredBoundaries.delete(boundary);
|
|
547
|
+
notifyIfDeferredBoundariesDrained();
|
|
548
|
+
}
|
|
549
|
+
replaying = true;
|
|
550
|
+
try {
|
|
551
|
+
interaction.target.dispatchEvent(interaction.event);
|
|
552
|
+
} finally {
|
|
553
|
+
replaying = false;
|
|
554
|
+
}
|
|
555
|
+
releaseIfFinished();
|
|
556
|
+
}
|
|
557
|
+
function captureInteraction(event) {
|
|
558
|
+
if (!active || replaying) return;
|
|
559
|
+
const target = event.target;
|
|
560
|
+
if (!target || isPermanentlySkipped(target)) return;
|
|
561
|
+
const boundary = findDeferredBoundary(target);
|
|
562
|
+
if (!hydratingRoot && !boundary) return;
|
|
563
|
+
event.preventDefault();
|
|
564
|
+
event.stopImmediatePropagation();
|
|
565
|
+
const interaction = {
|
|
566
|
+
target,
|
|
567
|
+
event: cloneInteractionEvent(event)
|
|
568
|
+
};
|
|
569
|
+
if (hydratingRoot) {
|
|
570
|
+
queued.push(interaction);
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
replayInteraction(interaction);
|
|
574
|
+
}
|
|
575
|
+
const installedTypes = [];
|
|
576
|
+
try {
|
|
577
|
+
for (const type of HYDRATION_INTERACTION_TYPES) {
|
|
578
|
+
root.addEventListener(type, captureInteraction, true);
|
|
579
|
+
installedTypes.push(type);
|
|
580
|
+
}
|
|
581
|
+
} catch (error) {
|
|
582
|
+
active = false;
|
|
583
|
+
for (const type of installedTypes) root.removeEventListener(type, captureInteraction, true);
|
|
584
|
+
throw error;
|
|
585
|
+
}
|
|
586
|
+
return {
|
|
587
|
+
registerDeferredBoundaries(boundaries) {
|
|
588
|
+
for (const boundary of boundaries) deferredBoundaries.add(boundary);
|
|
589
|
+
hadDeferredBoundaries ||= boundaries.length > 0;
|
|
590
|
+
},
|
|
591
|
+
setOnDeferredBoundariesDrained(callback) {
|
|
592
|
+
onDeferredBoundariesDrained = callback;
|
|
593
|
+
},
|
|
594
|
+
clearDeferredBoundaries() {
|
|
595
|
+
deferredBoundaries.clear();
|
|
596
|
+
releaseIfFinished();
|
|
597
|
+
},
|
|
598
|
+
complete() {
|
|
599
|
+
if (!active || !hydratingRoot) return;
|
|
600
|
+
hydratingRoot = false;
|
|
601
|
+
const pending = queued.splice(0);
|
|
602
|
+
for (const interaction of pending) replayInteraction(interaction);
|
|
603
|
+
releaseIfFinished();
|
|
604
|
+
},
|
|
605
|
+
abort() {
|
|
606
|
+
queued.length = 0;
|
|
607
|
+
deferredBoundaries.clear();
|
|
608
|
+
onDeferredBoundariesDrained = void 0;
|
|
609
|
+
hydratingRoot = false;
|
|
610
|
+
removeCaptureListeners();
|
|
611
|
+
}
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
//#endregion
|
|
443
615
|
//#region src/boot/index.ts
|
|
444
616
|
/**
|
|
445
617
|
* App bootstrap and mount
|
|
@@ -570,97 +742,105 @@ async function hydrateSPA(config) {
|
|
|
570
742
|
if (manifest.records.length === 0) throw new Error("hydrateSPA requires a route registry with at least one route. If you are enhancing existing HTML, use createIsland instead.");
|
|
571
743
|
const rootElement = resolveRootElement(config.root);
|
|
572
744
|
if (!rootElement) throw new Error(`Root element not found: ${config.root}`);
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
runtime: createAppRenderRuntime({
|
|
586
|
-
framework: hydrationRenderData?.framework,
|
|
587
|
-
route: hydrationRenderData?.route,
|
|
588
|
-
hasRoute: hydrationRenderData !== null,
|
|
589
|
-
routeRegistry: config.registry,
|
|
590
|
-
routeAuth
|
|
591
|
-
})
|
|
592
|
-
};
|
|
593
|
-
_setActiveRouteAuthOptions(routeAuth);
|
|
594
|
-
const { path, href: currentUrl, resolved } = await resolveInitialRoute(routeAuth, {
|
|
595
|
-
registry: config.registry,
|
|
596
|
-
load: false
|
|
597
|
-
});
|
|
598
|
-
setServerLocation(currentUrl);
|
|
599
|
-
if (isProductionEnvironment()) lockRouteRegistration();
|
|
600
|
-
if (!resolved) throw new Error(`hydrateSPA: no route found for current path (${path}).`);
|
|
601
|
-
if (resolved.kind === "redirect") throw new Error(`hydrateSPA: unresolved redirect for current path (${path}).`);
|
|
602
|
-
await reconcileInitialRouteMetadata(resolved);
|
|
603
|
-
const hydrationResolved = resolved.kind === "deny" ? {
|
|
604
|
-
handler: bindDeniedRouteHandler(resolved.status),
|
|
605
|
-
params: {}
|
|
606
|
-
} : {
|
|
607
|
-
handler: resolved.handler,
|
|
608
|
-
params: resolved.params
|
|
609
|
-
};
|
|
610
|
-
const mountHydratedRoot = (...args) => withIntrinsicHydrationAdoption(() => mountOrUpdate(args[0], args[1], {
|
|
611
|
-
...args[2],
|
|
612
|
-
cspNonce: config.cspNonce
|
|
613
|
-
}));
|
|
614
|
-
if (shouldVerifyHydrationMarkup(config)) {
|
|
615
|
-
const { verifyHydrationSyncForUrl } = await import("./verify-hydration-Bo5_tpen.js");
|
|
616
|
-
if (!verifyHydrationSyncForUrl({
|
|
617
|
-
root: rootElement,
|
|
618
|
-
url: currentUrl,
|
|
745
|
+
const interactionReplay = beginHydrationInteractionReplay(rootElement, (boundary) => activateHydrationBoundary(rootElement, boundary), config.hydrate?.skipSelectors);
|
|
746
|
+
try {
|
|
747
|
+
applyDeferredStreamPatches(rootElement);
|
|
748
|
+
const hydrationRenderData = takeHydrationRenderData(rootElement);
|
|
749
|
+
const hydrationQueryCache = hydrationRenderData?.resources;
|
|
750
|
+
if (hydrationQueryCache) hydrateDataRuntime(config.dataRuntime ?? getDefaultDataRuntime(), hydrationQueryCache);
|
|
751
|
+
const hydrationRenderDataForApp = hydrationRenderData;
|
|
752
|
+
configureScrollRestoration(config.scrollRestoration);
|
|
753
|
+
clearRouteState();
|
|
754
|
+
_applyManifest(manifest);
|
|
755
|
+
const routeAuth = config.auth ?? manifest.auth;
|
|
756
|
+
const appRouteSource = {
|
|
619
757
|
registry: config.registry,
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
758
|
+
auth: routeAuth,
|
|
759
|
+
runtime: createAppRenderRuntime({
|
|
760
|
+
framework: hydrationRenderData?.framework,
|
|
761
|
+
route: hydrationRenderData?.route,
|
|
762
|
+
hasRoute: hydrationRenderData !== null,
|
|
763
|
+
routeRegistry: config.registry,
|
|
764
|
+
routeAuth
|
|
765
|
+
})
|
|
766
|
+
};
|
|
767
|
+
_setActiveRouteAuthOptions(routeAuth);
|
|
768
|
+
const { path, href: currentUrl, resolved } = await resolveInitialRoute(routeAuth, {
|
|
769
|
+
registry: config.registry,
|
|
770
|
+
load: false
|
|
771
|
+
});
|
|
772
|
+
setServerLocation(currentUrl);
|
|
773
|
+
if (isProductionEnvironment()) lockRouteRegistration();
|
|
774
|
+
if (!resolved) throw new Error(`hydrateSPA: no route found for current path (${path}).`);
|
|
775
|
+
if (resolved.kind === "redirect") throw new Error(`hydrateSPA: unresolved redirect for current path (${path}).`);
|
|
776
|
+
await reconcileInitialRouteMetadata(resolved);
|
|
777
|
+
const hydrationResolved = resolved.kind === "deny" ? {
|
|
778
|
+
handler: bindDeniedRouteHandler(resolved.status),
|
|
779
|
+
params: {}
|
|
780
|
+
} : {
|
|
781
|
+
handler: resolved.handler,
|
|
782
|
+
params: resolved.params
|
|
783
|
+
};
|
|
784
|
+
const mountHydratedRoot = (...args) => withIntrinsicHydrationAdoption(() => mountOrUpdate(args[0], args[1], {
|
|
785
|
+
...args[2],
|
|
786
|
+
cspNonce: config.cspNonce
|
|
787
|
+
}));
|
|
788
|
+
if (shouldVerifyHydrationMarkup(config)) {
|
|
789
|
+
const { verifyHydrationSyncForUrl } = await import("./verify-hydration-Bo5_tpen.js");
|
|
790
|
+
if (!verifyHydrationSyncForUrl({
|
|
791
|
+
root: rootElement,
|
|
792
|
+
url: currentUrl,
|
|
793
|
+
registry: config.registry,
|
|
794
|
+
resolved: hydrationResolved,
|
|
795
|
+
options: {
|
|
796
|
+
data: hydrationRenderDataForApp?.resources,
|
|
797
|
+
dataRuntime: config.dataRuntime ?? getDefaultDataRuntime(),
|
|
798
|
+
envelope: hydrationRenderDataForApp ?? void 0,
|
|
799
|
+
cspNonce: config.cspNonce
|
|
800
|
+
}
|
|
801
|
+
})) throw new Error("[Askr] Hydration mismatch detected. Server HTML does not match expected server-render output.");
|
|
802
|
+
}
|
|
803
|
+
const hydrateOptions = config.hydrate;
|
|
804
|
+
if (hydrateOptions) {
|
|
805
|
+
if (hydrateOptions.deferUntilIdle || hydrateOptions.deferBelowFold) {
|
|
806
|
+
if (hydrationRenderDataForApp) startHydrationRenderPhase(hydrationRenderDataForApp);
|
|
807
|
+
try {
|
|
808
|
+
await applySelectiveHydration(rootElement, hydrationResolved, path, config.cleanupStrict, hydrateOptions, appRouteSource, {
|
|
809
|
+
mountOrUpdate: mountHydratedRoot,
|
|
810
|
+
registerAppNavigation,
|
|
811
|
+
registerRootCleanupCallback,
|
|
812
|
+
activateHydrationBoundary
|
|
813
|
+
}, interactionReplay);
|
|
814
|
+
} finally {
|
|
815
|
+
if (hydrationRenderDataForApp) stopHydrationRenderPhase();
|
|
816
|
+
}
|
|
817
|
+
interactionReplay.complete();
|
|
818
|
+
return;
|
|
642
819
|
}
|
|
643
|
-
|
|
820
|
+
if (hydrateOptions.skipSelectors?.length) markSkippedElements(rootElement, hydrateOptions.skipSelectors);
|
|
644
821
|
}
|
|
645
|
-
if (
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
822
|
+
if (hydrationRenderDataForApp) startHydrationRenderPhase(hydrationRenderDataForApp);
|
|
823
|
+
const listenerTransaction = beginHydrationListenerTransaction();
|
|
824
|
+
beginHydrationDirectListenerMode();
|
|
825
|
+
try {
|
|
826
|
+
mountHydratedRoot(rootElement, resolved.kind === "deny" ? bindDeniedStatus(resolved.status) : bindResolvedRouteHandler(hydrationResolved), {
|
|
827
|
+
cleanupStrict: config.cleanupStrict,
|
|
828
|
+
appRuntime: appRouteSource.runtime
|
|
829
|
+
});
|
|
830
|
+
commitHydrationListenerTransaction(listenerTransaction);
|
|
831
|
+
interactionReplay.complete();
|
|
832
|
+
} catch (error) {
|
|
833
|
+
discardHydrationListenerTransaction(listenerTransaction);
|
|
834
|
+
throw error;
|
|
835
|
+
} finally {
|
|
836
|
+
endHydrationDirectListenerMode();
|
|
837
|
+
if (hydrationRenderDataForApp) stopHydrationRenderPhase();
|
|
838
|
+
}
|
|
839
|
+
await registerAppNavigation(rootElement, path, { ...appRouteSource });
|
|
656
840
|
} catch (error) {
|
|
657
|
-
|
|
841
|
+
interactionReplay.abort();
|
|
658
842
|
throw error;
|
|
659
|
-
} finally {
|
|
660
|
-
endHydrationDirectListenerMode();
|
|
661
|
-
if (hydrationRenderDataForApp) stopHydrationRenderPhase();
|
|
662
843
|
}
|
|
663
|
-
await registerAppNavigation(rootElement, path, { ...appRouteSource });
|
|
664
844
|
}
|
|
665
845
|
//#endregion
|
|
666
846
|
export { cleanupApp as a, hydrateSPA as i, createIslands as n, hasApp as o, createSPA as r, createIsland as t };
|
|
@@ -73,6 +73,7 @@ declare function pressable({ disabled, onPress, isNativeButton }: PressableOptio
|
|
|
73
73
|
* - Returns standard event handler props (onKeyDown, onPointerDownCapture)
|
|
74
74
|
* - Composable via mergeProps with other foundations
|
|
75
75
|
* - Caller provides the protected node reference for outside detection
|
|
76
|
+
* - Portaled descendants are registered explicitly as additional inside nodes
|
|
76
77
|
* - Returned capture props must be attached to a surface that can observe both
|
|
77
78
|
* the protected subtree and the outside interaction path (for example, an
|
|
78
79
|
* overlay or wrapper around the protected node)
|
|
@@ -87,6 +88,7 @@ declare function pressable({ disabled, onPress, isNativeButton }: PressableOptio
|
|
|
87
88
|
* USAGE:
|
|
88
89
|
* const props = dismissable({
|
|
89
90
|
* node: elementRef,
|
|
91
|
+
* additionalInsideNodes: [dropdownPortalRef],
|
|
90
92
|
* disabled: false,
|
|
91
93
|
* onDismiss: () => close()
|
|
92
94
|
* });
|
|
@@ -107,6 +109,11 @@ interface DismissableOptions {
|
|
|
107
109
|
* returned capture props to a surface that encloses this node.
|
|
108
110
|
*/
|
|
109
111
|
node?: Node | null;
|
|
112
|
+
/**
|
|
113
|
+
* Additional roots that are logically inside the protected surface even
|
|
114
|
+
* when a portal places them outside `node` in the DOM tree.
|
|
115
|
+
*/
|
|
116
|
+
additionalInsideNodes?: readonly (Node | null | undefined)[];
|
|
110
117
|
/**
|
|
111
118
|
* Whether dismiss is disabled
|
|
112
119
|
*/
|
|
@@ -117,7 +124,7 @@ interface DismissableOptions {
|
|
|
117
124
|
onDismiss?: (trigger: 'escape' | 'outside') => void;
|
|
118
125
|
}
|
|
119
126
|
/** Produce keydown/outside-click props that invoke `onDismiss` on Escape or an outside click. */
|
|
120
|
-
declare function dismissable({ node, disabled, onDismiss }: DismissableOptions): {
|
|
127
|
+
declare function dismissable({ node, additionalInsideNodes, disabled, onDismiss }: DismissableOptions): {
|
|
121
128
|
onKeyDown: (e: KeyboardLikeEvent) => void;
|
|
122
129
|
onPointerDownCapture: (e: PointerLikeEvent) => void;
|
|
123
130
|
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as focusable, i as hoverable, n as mergeInteractionProps, o as dismissable, r as rovingFocus, s as pressable, t as applyInteractionPolicy } from "../../interactions-
|
|
1
|
+
import { a as focusable, i as hoverable, n as mergeInteractionProps, o as dismissable, r as rovingFocus, s as pressable, t as applyInteractionPolicy } from "../../interactions-B-7vkBgx.js";
|
|
2
2
|
export { applyInteractionPolicy, dismissable, focusable, hoverable, mergeInteractionProps, pressable, rovingFocus };
|
package/dist/fx/index.js
CHANGED
|
@@ -24,20 +24,20 @@ function debounce(fn, ms, options) {
|
|
|
24
24
|
const { leading = false, trailing = true } = options || {};
|
|
25
25
|
let lastArgs = null;
|
|
26
26
|
let lastThis = null;
|
|
27
|
-
let
|
|
27
|
+
let trailingPending = false;
|
|
28
28
|
const debounced = function(...args) {
|
|
29
|
-
const
|
|
29
|
+
const windowActive = timeoutId !== null;
|
|
30
30
|
lastArgs = args;
|
|
31
31
|
lastThis = this;
|
|
32
32
|
if (timeoutId !== null) clearTimeout(timeoutId);
|
|
33
|
-
if (leading &&
|
|
33
|
+
if (leading && !windowActive) {
|
|
34
34
|
callable.apply(this, args);
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
callable.apply(lastThis, lastArgs);
|
|
35
|
+
trailingPending = false;
|
|
36
|
+
} else if (trailing) trailingPending = true;
|
|
37
|
+
timeoutId = setTimeout(() => {
|
|
38
|
+
if (trailingPending) callable.apply(lastThis, lastArgs);
|
|
39
39
|
timeoutId = null;
|
|
40
|
-
|
|
40
|
+
trailingPending = false;
|
|
41
41
|
}, ms);
|
|
42
42
|
};
|
|
43
43
|
debounced.cancel = () => {
|
|
@@ -45,6 +45,7 @@ function debounce(fn, ms, options) {
|
|
|
45
45
|
clearTimeout(timeoutId);
|
|
46
46
|
timeoutId = null;
|
|
47
47
|
}
|
|
48
|
+
trailingPending = false;
|
|
48
49
|
};
|
|
49
50
|
return debounced;
|
|
50
51
|
}
|
|
@@ -121,13 +122,13 @@ function once(fn) {
|
|
|
121
122
|
const callable = fn;
|
|
122
123
|
let called = false;
|
|
123
124
|
let result;
|
|
124
|
-
return (
|
|
125
|
+
return function(...args) {
|
|
125
126
|
if (!called) {
|
|
126
127
|
called = true;
|
|
127
|
-
result = callable(
|
|
128
|
+
result = callable.apply(this, args);
|
|
128
129
|
}
|
|
129
130
|
return result;
|
|
130
|
-
}
|
|
131
|
+
};
|
|
131
132
|
}
|
|
132
133
|
/**
|
|
133
134
|
* Defer — schedule on microtask queue
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { n as isSnapshotSource } from "./snapshot-source-BB42xgwb.js";
|
|
|
7
7
|
import { c as registerSSRStyle } from "./render-context-B7ohlh6t.js";
|
|
8
8
|
import { t as state } from "./state-DmkGM_LN.js";
|
|
9
9
|
import { t as selector } from "./selector-CyK-sDwB.js";
|
|
10
|
-
import { t as installRendererBridge } from "./renderer-
|
|
10
|
+
import { t as installRendererBridge } from "./renderer-Cg92QKOm.js";
|
|
11
11
|
import { n as cspNonce, t as CspNonceScope } from "./csp-nonce-BVybpV1v.js";
|
|
12
12
|
import { i as For, n as Match, r as Show, t as Case } from "./control-C0klPV7Q.js";
|
|
13
13
|
import { jsx, jsxs } from "./jsx-runtime.js";
|
|
@@ -49,7 +49,7 @@ function pressable({ disabled, onPress, isNativeButton = false }) {
|
|
|
49
49
|
//#endregion
|
|
50
50
|
//#region src/foundations/interactions/dismissable.ts
|
|
51
51
|
/** Produce keydown/outside-click props that invoke `onDismiss` on Escape or an outside click. */
|
|
52
|
-
function dismissable({ node, disabled, onDismiss }) {
|
|
52
|
+
function dismissable({ node, additionalInsideNodes, disabled, onDismiss }) {
|
|
53
53
|
function handleKeyDown(e) {
|
|
54
54
|
if (disabled) return;
|
|
55
55
|
if (e.key === "Escape") {
|
|
@@ -63,7 +63,8 @@ function dismissable({ node, disabled, onDismiss }) {
|
|
|
63
63
|
const target = e.target;
|
|
64
64
|
if (!(target instanceof Node)) return;
|
|
65
65
|
if (!node) return;
|
|
66
|
-
|
|
66
|
+
const insideAdditionalNode = additionalInsideNodes?.some((insideNode) => insideNode?.contains(target));
|
|
67
|
+
if (!node.contains(target) && !insideAdditionalNode) onDismiss?.("outside");
|
|
67
68
|
}
|
|
68
69
|
return {
|
|
69
70
|
onKeyDown: handleKeyDown,
|
|
@@ -5918,6 +5918,9 @@ function materializeComponentResultNode(childInstance, result, parentNamespace)
|
|
|
5918
5918
|
} finally {
|
|
5919
5919
|
restoreDomCommitScope(previousInstance);
|
|
5920
5920
|
}
|
|
5921
|
+
return materializeResolvedComponentResultNode(childInstance, result, dom);
|
|
5922
|
+
}
|
|
5923
|
+
function materializeResolvedComponentResultNode(childInstance, result, dom) {
|
|
5921
5924
|
if (dom instanceof Element) {
|
|
5922
5925
|
mountInstanceInline(childInstance, dom);
|
|
5923
5926
|
return dom;
|
|
@@ -5961,6 +5964,20 @@ function materializeComponentResultNode(childInstance, result, parentNamespace)
|
|
|
5961
5964
|
return materialized.fragment ?? host;
|
|
5962
5965
|
}
|
|
5963
5966
|
//#endregion
|
|
5967
|
+
//#region src/renderer/component-chain-depth.ts
|
|
5968
|
+
const MAX_COMPONENT_CHAIN_DEPTH = 1e5;
|
|
5969
|
+
const COMPONENT_CHAIN_ERROR_CONTEXT = 8;
|
|
5970
|
+
function assertComponentChainDepth(depth, instance) {
|
|
5971
|
+
if (depth < MAX_COMPONENT_CHAIN_DEPTH) return;
|
|
5972
|
+
const names = [];
|
|
5973
|
+
let current = instance;
|
|
5974
|
+
while (current && names.length < COMPONENT_CHAIN_ERROR_CONTEXT) {
|
|
5975
|
+
names.push(current.fn.name || "<anonymous>");
|
|
5976
|
+
current = current.parentInstance;
|
|
5977
|
+
}
|
|
5978
|
+
throw new Error(`[Askr] Component chain exceeded ${MAX_COMPONENT_CHAIN_DEPTH.toLocaleString("en-US")} wrappers. This usually means component output recurses without terminating. Recent chain: ${names.reverse().join(" -> ")}`);
|
|
5979
|
+
}
|
|
5980
|
+
//#endregion
|
|
5964
5981
|
//#region src/renderer/component-host-nested-results.ts
|
|
5965
5982
|
function getNestedComponentVNode(result) {
|
|
5966
5983
|
if (_isDOMElement(result) && typeof result.type === "function") return result;
|
|
@@ -5972,8 +5989,10 @@ function getNestedComponentVNode(result) {
|
|
|
5972
5989
|
function resolveNestedComponentResult(result, snapshot, parentInstance) {
|
|
5973
5990
|
let currentResult = result;
|
|
5974
5991
|
let activeSnapshot = snapshot;
|
|
5992
|
+
let diagnosticParent = parentInstance;
|
|
5975
5993
|
let depth = 0;
|
|
5976
|
-
while (_isDOMElement(currentResult) && typeof currentResult.type === "function"
|
|
5994
|
+
while (_isDOMElement(currentResult) && typeof currentResult.type === "function") {
|
|
5995
|
+
assertComponentChainDepth(depth, diagnosticParent);
|
|
5977
5996
|
const nestedSnapshot = getVNodeContextFrame(currentResult) ?? activeSnapshot;
|
|
5978
5997
|
const nestedInstance = createComponentInstance(nextComponentInstanceId(), currentResult.type, currentResult.props ?? {}, null);
|
|
5979
5998
|
nestedInstance.isRoot = isRouteRootComponentVNode(currentResult);
|
|
@@ -5990,6 +6009,7 @@ function resolveNestedComponentResult(result, snapshot, parentInstance) {
|
|
|
5990
6009
|
throw error;
|
|
5991
6010
|
}
|
|
5992
6011
|
cleanupComponent(nestedInstance);
|
|
6012
|
+
diagnosticParent = nestedInstance;
|
|
5993
6013
|
activeSnapshot = nestedSnapshot ?? null;
|
|
5994
6014
|
currentResult = nextResult;
|
|
5995
6015
|
depth += 1;
|
|
@@ -6005,7 +6025,8 @@ function resolveHostNestedComponentResult(host, retainedInstance, result, snapsh
|
|
|
6005
6025
|
const createdVNodeOwners = [];
|
|
6006
6026
|
try {
|
|
6007
6027
|
let nestedVNode = getNestedComponentVNode(currentResult);
|
|
6008
|
-
while (nestedVNode
|
|
6028
|
+
while (nestedVNode) {
|
|
6029
|
+
assertComponentChainDepth(depth, activeParent);
|
|
6009
6030
|
const nestedSnapshot = getVNodeContextFrame(nestedVNode) ?? activeSnapshot;
|
|
6010
6031
|
let nestedInstance = findHostInstanceByType(host, nestedVNode.type, nestedVNode, activeParent, depth);
|
|
6011
6032
|
const hadNestedInstance = !!nestedInstance;
|
|
@@ -6063,7 +6084,8 @@ function resolveWrapperHostResult(host, retainedInstance, result, snapshot, reta
|
|
|
6063
6084
|
let activeParent = retainedInstance;
|
|
6064
6085
|
let depth = 0;
|
|
6065
6086
|
let nestedVNode = getNestedComponentVNode(currentResult);
|
|
6066
|
-
while (nestedVNode
|
|
6087
|
+
while (nestedVNode) {
|
|
6088
|
+
assertComponentChainDepth(depth, activeParent);
|
|
6067
6089
|
const nestedSnapshot = getVNodeContextFrame(nestedVNode) ?? activeSnapshot;
|
|
6068
6090
|
const nestedInstance = findHostInstanceByType(host, nestedVNode.type, nestedVNode, activeParent, depth);
|
|
6069
6091
|
if (!nestedInstance) break;
|
|
@@ -6090,6 +6112,81 @@ function resolveWrapperHostResult(host, retainedInstance, result, snapshot, reta
|
|
|
6090
6112
|
};
|
|
6091
6113
|
}
|
|
6092
6114
|
//#endregion
|
|
6115
|
+
//#region src/renderer/component-host-fresh-chain.ts
|
|
6116
|
+
function getFreshNestedComponentVNode(result) {
|
|
6117
|
+
if (_isDOMElement(result) && typeof result.type === "function") return result;
|
|
6118
|
+
if (!Array.isArray(result) && !isFragmentVNode(result)) return null;
|
|
6119
|
+
const children = normalizeComponentChildren(result);
|
|
6120
|
+
const child = children.length === 1 ? children[0] : void 0;
|
|
6121
|
+
return _isDOMElement(child) && typeof child.type === "function" ? child : null;
|
|
6122
|
+
}
|
|
6123
|
+
function prepareFreshNestedComponentResultDom(result, dom) {
|
|
6124
|
+
if (!Array.isArray(result) && !isFragmentVNode(result)) return dom;
|
|
6125
|
+
const fragment = document.createDocumentFragment();
|
|
6126
|
+
fragment.appendChild(dom);
|
|
6127
|
+
return fragment;
|
|
6128
|
+
}
|
|
6129
|
+
function rollbackFreshNestedComponentResolution(resolution) {
|
|
6130
|
+
for (let index = resolution.vnodeOwners.length - 1; index >= 0; index -= 1) {
|
|
6131
|
+
const owner = resolution.vnodeOwners[index];
|
|
6132
|
+
restoreVNodeComponentInstance(owner.node, owner.previous);
|
|
6133
|
+
}
|
|
6134
|
+
cleanupProvisionalComponentInstances(resolution.createdInstances);
|
|
6135
|
+
}
|
|
6136
|
+
function resolveFreshNestedComponentResult(result, snapshot, parentInstance) {
|
|
6137
|
+
let currentResult = result;
|
|
6138
|
+
let activeSnapshot = snapshot;
|
|
6139
|
+
let activeParent = parentInstance;
|
|
6140
|
+
let depth = 0;
|
|
6141
|
+
const resolution = {
|
|
6142
|
+
entries: [],
|
|
6143
|
+
createdInstances: [],
|
|
6144
|
+
vnodeOwners: []
|
|
6145
|
+
};
|
|
6146
|
+
try {
|
|
6147
|
+
let nestedVNode = getFreshNestedComponentVNode(currentResult);
|
|
6148
|
+
while (nestedVNode) {
|
|
6149
|
+
assertComponentChainDepth(depth, activeParent);
|
|
6150
|
+
const nestedSnapshot = getVNodeContextFrame(nestedVNode) ?? activeSnapshot;
|
|
6151
|
+
const componentFn = nestedVNode.type;
|
|
6152
|
+
const previous = getVNodeComponentInstance(nestedVNode);
|
|
6153
|
+
let nestedInstance = previous && hasComponentOwnershipIdentity(previous, componentFn, nestedVNode, activeParent, 0) ? previous : void 0;
|
|
6154
|
+
if (!nestedInstance) {
|
|
6155
|
+
nestedInstance = createComponentInstance(nextComponentInstanceId(), componentFn, nestedVNode.props ?? {}, null);
|
|
6156
|
+
resolution.vnodeOwners.push({
|
|
6157
|
+
node: nestedVNode,
|
|
6158
|
+
previous
|
|
6159
|
+
});
|
|
6160
|
+
registerVNodeComponentInstanceRollback(nestedVNode, previous, nestedInstance);
|
|
6161
|
+
setVNodeComponentInstance(nestedVNode, nestedInstance);
|
|
6162
|
+
resolution.createdInstances.push(nestedInstance);
|
|
6163
|
+
} else captureInlineRenderSnapshot(nestedInstance);
|
|
6164
|
+
setComponentOwnershipIdentity(nestedInstance, nestedVNode, activeParent, 0);
|
|
6165
|
+
nestedInstance.isRoot = isRouteRootComponentVNode(nestedVNode);
|
|
6166
|
+
nestedInstance.parentInstance = activeParent;
|
|
6167
|
+
nestedInstance.portalScope = activeParent.portalScope ?? nestedInstance.portalScope;
|
|
6168
|
+
nestedInstance.cleanupStrict = activeParent.cleanupStrict;
|
|
6169
|
+
nestedInstance.props = (nestedVNode.props ?? {}) || {};
|
|
6170
|
+
if (nestedSnapshot) nestedInstance.ownerFrame = nestedSnapshot;
|
|
6171
|
+
const nextResult = withContext(nestedSnapshot ?? null, () => renderComponentInline(nestedInstance));
|
|
6172
|
+
if (isPromiseLike(nextResult)) throw new Error("Async components are not supported. Components must return synchronously.");
|
|
6173
|
+
activeParent = nestedInstance;
|
|
6174
|
+
activeSnapshot = nestedSnapshot ?? null;
|
|
6175
|
+
currentResult = markVNodeTreeWithContextFrame(nextResult, activeSnapshot);
|
|
6176
|
+
resolution.entries.push({
|
|
6177
|
+
instance: nestedInstance,
|
|
6178
|
+
result: currentResult
|
|
6179
|
+
});
|
|
6180
|
+
depth += 1;
|
|
6181
|
+
nestedVNode = getFreshNestedComponentVNode(currentResult);
|
|
6182
|
+
}
|
|
6183
|
+
return resolution;
|
|
6184
|
+
} catch (error) {
|
|
6185
|
+
rollbackFreshNestedComponentResolution(resolution);
|
|
6186
|
+
throw error;
|
|
6187
|
+
}
|
|
6188
|
+
}
|
|
6189
|
+
//#endregion
|
|
6093
6190
|
//#region src/renderer/component-host-creation.ts
|
|
6094
6191
|
function createComponentElement(node, type, props, parentNamespace) {
|
|
6095
6192
|
const snapshot = getVNodeContextFrame(node) || getCurrentContextFrame();
|
|
@@ -6099,6 +6196,7 @@ function createComponentElement(node, type, props, parentNamespace) {
|
|
|
6099
6196
|
const currentParent = getCurrentInstance();
|
|
6100
6197
|
let childInstance = previousVNodeInstance && hasComponentOwnershipIdentity(previousVNodeInstance, componentFn, node, currentParent, 0) ? previousVNodeInstance : void 0;
|
|
6101
6198
|
const hadChildInstance = !!childInstance;
|
|
6199
|
+
let nestedResolution = null;
|
|
6102
6200
|
if (!childInstance) {
|
|
6103
6201
|
childInstance = createComponentInstance(nextComponentInstanceId(), componentFn, props || {}, null);
|
|
6104
6202
|
registerVNodeComponentInstanceRollback(node, previousVNodeInstance, childInstance);
|
|
@@ -6116,10 +6214,20 @@ function createComponentElement(node, type, props, parentNamespace) {
|
|
|
6116
6214
|
const result = snapshot ? withContext(snapshot, () => renderComponentInline(childInstance)) : renderComponentInline(childInstance);
|
|
6117
6215
|
if (isPromiseLike(result)) throw new Error("Async components are not supported. Components must return synchronously.");
|
|
6118
6216
|
const scopedResult = markVNodeTreeWithContextFrame(result, snapshot ?? null);
|
|
6119
|
-
|
|
6217
|
+
nestedResolution = resolveFreshNestedComponentResult(scopedResult, snapshot ?? null, childInstance);
|
|
6218
|
+
const deepestEntry = nestedResolution.entries[nestedResolution.entries.length - 1];
|
|
6219
|
+
let dom = snapshot ? withContext(snapshot, () => materializeComponentResultNode(deepestEntry?.instance ?? childInstance, deepestEntry?.result ?? scopedResult, parentNamespace)) : materializeComponentResultNode(deepestEntry?.instance ?? childInstance, deepestEntry?.result ?? scopedResult, parentNamespace);
|
|
6220
|
+
if (deepestEntry) {
|
|
6221
|
+
for (let index = nestedResolution.entries.length - 2; index >= 0; index -= 1) {
|
|
6222
|
+
const entry = nestedResolution.entries[index];
|
|
6223
|
+
dom = materializeResolvedComponentResultNode(entry.instance, entry.result, prepareFreshNestedComponentResultDom(entry.result, dom));
|
|
6224
|
+
}
|
|
6225
|
+
dom = materializeResolvedComponentResultNode(childInstance, scopedResult, prepareFreshNestedComponentResultDom(scopedResult, dom));
|
|
6226
|
+
}
|
|
6120
6227
|
if (dom instanceof Element) materializeFreshKey(dom, node, props);
|
|
6121
6228
|
return dom;
|
|
6122
6229
|
} catch (error) {
|
|
6230
|
+
if (nestedResolution) rollbackFreshNestedComponentResolution(nestedResolution);
|
|
6123
6231
|
if (!hadChildInstance) {
|
|
6124
6232
|
restoreVNodeComponentInstance(node, previousVNodeInstance);
|
|
6125
6233
|
cleanupProvisionalComponentInstance(childInstance);
|
package/dist/router/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { S as RouteDataLoadError, a as resolveRouteRequest, b as lazy, f as defe
|
|
|
7
7
|
import { n as onRouteChange, t as currentRoute } from "../activity-d4t3CdzK.js";
|
|
8
8
|
import { a as serializeRouteMeta, c as getCurrentHref, d as parseTargetUrl, h as syncRegisteredRouteSnapshot, i as resolveRouteMeta, l as getRegisteredAppsSnapshot, m as syncAppRegistrationLocation, n as navigate, p as setCurrentRouteLocation, r as reconcileRouteMeta, s as saveScrollPosition, u as getWindowHref } from "../navigate-Cix_Q9ym.js";
|
|
9
9
|
import { o as mergeProps } from "../compose-ref-1Fhs7mbF.js";
|
|
10
|
-
import { t as applyInteractionPolicy } from "../interactions-
|
|
10
|
+
import { t as applyInteractionPolicy } from "../interactions-B-7vkBgx.js";
|
|
11
11
|
//#region src/router/route-query.ts
|
|
12
12
|
function getRouteQueryHistoryMode(options) {
|
|
13
13
|
if (options.history) return options.history;
|
package/dist/testing/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { u as recordReadableRead } from "../readable-BsdGWsDE.js";
|
|
|
3
3
|
import { l as addInvalidationListener, t as createDataRuntime } from "../data-runtime-7t_Y0iv3.js";
|
|
4
4
|
import { a as notifySource, i as normalizeAsyncDataError, r as createReadableSource } from "../data-CnQwUS76.js";
|
|
5
5
|
import { r as computeRouteActivityMatches } from "../route-matching-Bo6UqG-5.js";
|
|
6
|
-
import { a as cleanupApp, r as createSPA, t as createIsland } from "../boot-
|
|
6
|
+
import { a as cleanupApp, r as createSPA, t as createIsland } from "../boot-BjldNXqF.js";
|
|
7
7
|
//#region src/testing/render.ts
|
|
8
8
|
const renderStates = /* @__PURE__ */ new WeakMap();
|
|
9
9
|
const eventConstructorNames = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askrjs/askr",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Actor-backed deterministic UI framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"askr",
|
|
@@ -148,8 +148,8 @@
|
|
|
148
148
|
"prepublishOnly": "npm run check"
|
|
149
149
|
},
|
|
150
150
|
"dependencies": {
|
|
151
|
-
"@askrjs/auth": ">=0.0
|
|
152
|
-
"@askrjs/schema": ">=0.0
|
|
151
|
+
"@askrjs/auth": ">=0.2.0 <0.3.0",
|
|
152
|
+
"@askrjs/schema": ">=0.2.0 <0.3.0"
|
|
153
153
|
},
|
|
154
154
|
"devDependencies": {
|
|
155
155
|
"@types/node": "^26.2.0",
|