@askrjs/askr 0.0.48 → 0.0.49
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/benchmark.js +6 -6
- package/dist/benchmark.js.map +1 -1
- package/dist/boot/hydration.js +140 -0
- package/dist/boot/hydration.js.map +1 -0
- package/dist/boot/index.d.ts +3 -56
- package/dist/boot/index.d.ts.map +1 -1
- package/dist/boot/index.js +62 -410
- package/dist/boot/index.js.map +1 -1
- package/dist/boot/root-lifecycle.d.ts +15 -0
- package/dist/boot/root-lifecycle.d.ts.map +1 -0
- package/dist/boot/root-lifecycle.js +205 -0
- package/dist/boot/root-lifecycle.js.map +1 -0
- package/dist/boot/route-startup.js +45 -0
- package/dist/boot/route-startup.js.map +1 -0
- package/dist/boot/types.d.ts +62 -0
- package/dist/boot/types.d.ts.map +1 -0
- package/dist/common/component.d.ts +3 -1
- package/dist/common/component.d.ts.map +1 -1
- package/dist/common/jsx.d.ts +1 -1
- package/dist/common/jsx.d.ts.map +1 -1
- package/dist/common/jsx.js.map +1 -1
- package/dist/common/props.d.ts +1 -1
- package/dist/common/render-context.js +55 -0
- package/dist/common/render-context.js.map +1 -0
- package/dist/common/router.d.ts +5 -1
- package/dist/common/router.d.ts.map +1 -1
- package/dist/common/ssr.d.ts +1 -1
- package/dist/common/ssr.js.map +1 -1
- package/dist/common/vnode.d.ts +5 -4
- package/dist/common/vnode.d.ts.map +1 -1
- package/dist/common/vnode.js.map +1 -1
- package/dist/components/error-boundary.d.ts +1 -1
- package/dist/components/error-boundary.js +2 -1
- package/dist/components/error-boundary.js.map +1 -1
- package/dist/components/link.js.map +1 -1
- package/dist/control/for.js +2 -1
- package/dist/control/for.js.map +1 -1
- package/dist/data/data-runtime.d.ts +28 -0
- package/dist/data/data-runtime.d.ts.map +1 -0
- package/dist/data/data-runtime.js +114 -0
- package/dist/data/data-runtime.js.map +1 -0
- package/dist/data/index.d.ts +6 -142
- package/dist/data/index.js +5 -539
- package/dist/data/invalidation.d.ts +9 -0
- package/dist/data/invalidation.d.ts.map +1 -0
- package/dist/data/invalidation.js +27 -0
- package/dist/data/invalidation.js.map +1 -0
- package/dist/data/mutation-cell.d.ts +28 -0
- package/dist/data/mutation-cell.d.ts.map +1 -0
- package/dist/data/mutation-cell.js +132 -0
- package/dist/data/mutation-cell.js.map +1 -0
- package/dist/data/query-cell.d.ts +46 -0
- package/dist/data/query-cell.d.ts.map +1 -0
- package/dist/data/query-cell.js +290 -0
- package/dist/data/query-cell.js.map +1 -0
- package/dist/data/query-key.js +42 -0
- package/dist/data/query-key.js.map +1 -0
- package/dist/data/shared.js +20 -0
- package/dist/data/shared.js.map +1 -0
- package/dist/data/types.d.ts +161 -0
- package/dist/data/types.d.ts.map +1 -0
- package/dist/foundations/icon/icon.d.ts.map +1 -1
- package/dist/foundations/icon/icon.js.map +1 -1
- package/dist/foundations/structures/portal.d.ts +1 -1
- package/dist/foundations/structures/portal.d.ts.map +1 -1
- package/dist/foundations/structures/portal.js +2 -1
- package/dist/foundations/structures/portal.js.map +1 -1
- package/dist/fx/fx.d.ts +1 -1
- package/dist/fx/fx.js +5 -4
- package/dist/fx/fx.js.map +1 -1
- package/dist/fx/timing.d.ts.map +1 -1
- package/dist/fx/timing.js +10 -6
- package/dist/fx/timing.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/jsx/index.d.ts +2 -1
- package/dist/jsx/index.js +3 -2
- package/dist/jsx/types.d.ts +2 -0
- package/dist/jsx/types.js +2 -1
- package/dist/jsx-runtime2.d.ts +2 -1
- package/dist/jsx-runtime2.js +3 -2
- package/dist/renderer/attributes.js +231 -0
- package/dist/renderer/attributes.js.map +1 -0
- package/dist/renderer/boundaries.js +266 -0
- package/dist/renderer/boundaries.js.map +1 -0
- package/dist/renderer/child-shape.js +85 -0
- package/dist/renderer/child-shape.js.map +1 -0
- package/dist/renderer/children.js +3 -2
- package/dist/renderer/children.js.map +1 -1
- package/dist/renderer/cleanup.js +2 -1
- package/dist/renderer/cleanup.js.map +1 -1
- package/dist/renderer/component-host-cleanup.js +68 -0
- package/dist/renderer/component-host-cleanup.js.map +1 -0
- package/dist/renderer/component-host-instances.js +65 -0
- package/dist/renderer/component-host-instances.js.map +1 -0
- package/dist/renderer/component-host.js +247 -0
- package/dist/renderer/component-host.js.map +1 -0
- package/dist/renderer/dom-host.js +13 -0
- package/dist/renderer/dom-host.js.map +1 -0
- package/dist/renderer/dom-internal.js +185 -0
- package/dist/renderer/dom-internal.js.map +1 -0
- package/dist/renderer/dom.js +9 -2356
- package/dist/renderer/element-children.js +279 -0
- package/dist/renderer/element-children.js.map +1 -0
- package/dist/renderer/env.js +2 -1
- package/dist/renderer/error-boundary-dom.js +29 -0
- package/dist/renderer/error-boundary-dom.js.map +1 -0
- package/dist/renderer/evaluate-dom-range.js +85 -0
- package/dist/renderer/evaluate-dom-range.js.map +1 -0
- package/dist/renderer/evaluate-reconcile.js +281 -0
- package/dist/renderer/evaluate-reconcile.js.map +1 -0
- package/dist/renderer/evaluate.js +13 -399
- package/dist/renderer/evaluate.js.map +1 -1
- package/dist/renderer/fastpath.js +6 -5
- package/dist/renderer/fastpath.js.map +1 -1
- package/dist/renderer/for-commit-dom-map.js +83 -0
- package/dist/renderer/for-commit-dom-map.js.map +1 -0
- package/dist/renderer/for-commit-removal.js +36 -0
- package/dist/renderer/for-commit-removal.js.map +1 -0
- package/dist/renderer/for-commit-reorder.js +89 -0
- package/dist/renderer/for-commit-reorder.js.map +1 -0
- package/dist/renderer/for-commit.js +6 -188
- package/dist/renderer/for-commit.js.map +1 -1
- package/dist/renderer/index.js +28 -16
- package/dist/renderer/index.js.map +1 -1
- package/dist/renderer/keyed-children.js +32 -0
- package/dist/renderer/keyed-children.js.map +1 -0
- package/dist/renderer/keyed.js +2 -15
- package/dist/renderer/keyed.js.map +1 -1
- package/dist/renderer/namespaces.js +23 -0
- package/dist/renderer/namespaces.js.map +1 -0
- package/dist/renderer/prop-bindings.js +280 -0
- package/dist/renderer/prop-bindings.js.map +1 -0
- package/dist/renderer/reactive-child-dom.js +133 -0
- package/dist/renderer/reactive-child-dom.js.map +1 -0
- package/dist/renderer/reactive-child-sources.js +184 -0
- package/dist/renderer/reactive-child-sources.js.map +1 -0
- package/dist/renderer/reactive-children.js +294 -0
- package/dist/renderer/reactive-children.js.map +1 -0
- package/dist/renderer/reconcile-commit.js +38 -0
- package/dist/renderer/reconcile-commit.js.map +1 -0
- package/dist/renderer/reconcile-fastpaths.js +106 -0
- package/dist/renderer/reconcile-fastpaths.js.map +1 -0
- package/dist/renderer/reconcile-resolution.js +187 -0
- package/dist/renderer/reconcile-resolution.js.map +1 -0
- package/dist/renderer/reconcile.js +9 -371
- package/dist/renderer/reconcile.js.map +1 -1
- package/dist/renderer/retained-element-rollback.js +276 -0
- package/dist/renderer/retained-element-rollback.js.map +1 -0
- package/dist/renderer/stable-patch.js +82 -0
- package/dist/renderer/stable-patch.js.map +1 -0
- package/dist/renderer/static-reuse.js +96 -0
- package/dist/renderer/static-reuse.js.map +1 -0
- package/dist/renderer/types.js +2 -1
- package/dist/renderer/utils.js +4 -4
- package/dist/renderer/utils.js.map +1 -1
- package/dist/resources/index.d.ts +3 -2
- package/dist/resources/index.js +5 -2
- package/dist/router/access.js +36 -0
- package/dist/router/access.js.map +1 -0
- package/dist/router/activity.d.ts +10 -0
- package/dist/router/activity.d.ts.map +1 -0
- package/dist/router/activity.js +89 -0
- package/dist/router/activity.js.map +1 -0
- package/dist/router/authoring.d.ts +22 -0
- package/dist/router/authoring.d.ts.map +1 -0
- package/dist/router/authoring.js +198 -0
- package/dist/router/authoring.js.map +1 -0
- package/dist/router/index.d.ts +12 -4
- package/dist/router/index.js +10 -3
- package/dist/router/internal-types.d.ts +31 -0
- package/dist/router/internal-types.d.ts.map +1 -0
- package/dist/router/lazy.d.ts +19 -0
- package/dist/router/lazy.d.ts.map +1 -0
- package/dist/router/lazy.js +52 -0
- package/dist/router/lazy.js.map +1 -0
- package/dist/router/manifest.d.ts +10 -0
- package/dist/router/manifest.d.ts.map +1 -0
- package/dist/router/manifest.js +49 -0
- package/dist/router/manifest.js.map +1 -0
- package/dist/router/navigate.d.ts +4 -51
- package/dist/router/navigate.d.ts.map +1 -1
- package/dist/router/navigate.js +16 -459
- package/dist/router/navigate.js.map +1 -1
- package/dist/router/navigation-registry.d.ts +32 -0
- package/dist/router/navigation-registry.d.ts.map +1 -0
- package/dist/router/navigation-registry.js +105 -0
- package/dist/router/navigation-registry.js.map +1 -0
- package/dist/router/navigation-scroll.d.ts +14 -0
- package/dist/router/navigation-scroll.d.ts.map +1 -0
- package/dist/router/navigation-scroll.js +93 -0
- package/dist/router/navigation-scroll.js.map +1 -0
- package/dist/router/navigation-targets.d.ts +31 -0
- package/dist/router/navigation-targets.d.ts.map +1 -0
- package/dist/router/navigation-targets.js +253 -0
- package/dist/router/navigation-targets.js.map +1 -0
- package/dist/router/policy.d.ts +7 -1
- package/dist/router/policy.d.ts.map +1 -1
- package/dist/router/policy.js +27 -9
- package/dist/router/policy.js.map +1 -1
- package/dist/router/rendering.d.ts +10 -0
- package/dist/router/rendering.d.ts.map +1 -0
- package/dist/router/rendering.js +45 -0
- package/dist/router/rendering.js.map +1 -0
- package/dist/router/resolution.d.ts +17 -0
- package/dist/router/resolution.d.ts.map +1 -0
- package/dist/router/resolution.js +253 -0
- package/dist/router/resolution.js.map +1 -0
- package/dist/router/route-query.d.ts +17 -0
- package/dist/router/route-query.d.ts.map +1 -0
- package/dist/router/route-query.js +47 -0
- package/dist/router/route-query.js.map +1 -0
- package/dist/router/route.d.ts +8 -149
- package/dist/router/route.js +8 -854
- package/dist/router/store.d.ts +50 -0
- package/dist/router/store.d.ts.map +1 -0
- package/dist/router/store.js +171 -0
- package/dist/router/store.js.map +1 -0
- package/dist/runtime/access.js +45 -0
- package/dist/runtime/access.js.map +1 -0
- package/dist/runtime/child-scope.d.ts +1 -1
- package/dist/runtime/child-scope.js +4 -1
- package/dist/runtime/child-scope.js.map +1 -1
- package/dist/runtime/component-cleanup.d.ts +16 -0
- package/dist/runtime/component-cleanup.d.ts.map +1 -0
- package/dist/runtime/component-cleanup.js +70 -0
- package/dist/runtime/component-cleanup.js.map +1 -0
- package/dist/runtime/component-commit.js +165 -0
- package/dist/runtime/component-commit.js.map +1 -0
- package/dist/runtime/component-contracts.js +5 -0
- package/dist/runtime/component-facade.d.ts +5 -0
- package/dist/runtime/component-facade.js +4 -0
- package/dist/runtime/component-internal.d.ts +100 -0
- package/dist/runtime/component-internal.d.ts.map +1 -0
- package/dist/runtime/component-internal.js +219 -0
- package/dist/runtime/component-internal.js.map +1 -0
- package/dist/runtime/component-lifecycle.d.ts +49 -0
- package/dist/runtime/component-lifecycle.d.ts.map +1 -0
- package/dist/runtime/component-lifecycle.js +176 -0
- package/dist/runtime/component-lifecycle.js.map +1 -0
- package/dist/runtime/component-scope.d.ts +55 -0
- package/dist/runtime/component-scope.d.ts.map +1 -0
- package/dist/runtime/component-scope.js +154 -0
- package/dist/runtime/component-scope.js.map +1 -0
- package/dist/runtime/component.d.ts +4 -152
- package/dist/runtime/component.js +4 -692
- package/dist/runtime/context.d.ts +1 -1
- package/dist/runtime/context.js +6 -4
- package/dist/runtime/context.js.map +1 -1
- package/dist/runtime/control.d.ts +3 -3
- package/dist/runtime/control.js +2 -1
- package/dist/runtime/control.js.map +1 -1
- package/dist/runtime/derive.d.ts.map +1 -1
- package/dist/runtime/derive.js +6 -5
- package/dist/runtime/derive.js.map +1 -1
- package/dist/runtime/effect.d.ts +1 -1
- package/dist/runtime/effect.d.ts.map +1 -1
- package/dist/runtime/effect.js +2 -2
- package/dist/runtime/effect.js.map +1 -1
- package/dist/runtime/events.js +3 -3
- package/dist/runtime/events.js.map +1 -1
- package/dist/runtime/fastlane.js +13 -27
- package/dist/runtime/fastlane.js.map +1 -1
- package/dist/runtime/for-bench.d.ts +1 -1
- package/dist/runtime/for-bench.js +1 -4
- package/dist/runtime/for-bench.js.map +1 -1
- package/dist/runtime/for-internal.d.ts +43 -0
- package/dist/runtime/for-internal.d.ts.map +1 -0
- package/dist/runtime/for-internal.js +98 -0
- package/dist/runtime/for-internal.js.map +1 -0
- package/dist/runtime/for-reconcile.d.ts +8 -0
- package/dist/runtime/for-reconcile.d.ts.map +1 -0
- package/dist/runtime/for-reconcile.js +389 -0
- package/dist/runtime/for-reconcile.js.map +1 -0
- package/dist/runtime/for-scopes.d.ts +26 -0
- package/dist/runtime/for-scopes.d.ts.map +1 -0
- package/dist/runtime/for-scopes.js +160 -0
- package/dist/runtime/for-scopes.js.map +1 -0
- package/dist/runtime/for-signals.d.ts +30 -0
- package/dist/runtime/for-signals.d.ts.map +1 -0
- package/dist/runtime/for-signals.js +139 -0
- package/dist/runtime/for-signals.js.map +1 -0
- package/dist/runtime/for.d.ts +4 -66
- package/dist/runtime/for.js +5 -773
- package/dist/runtime/lifecycle-operations.d.ts +31 -0
- package/dist/runtime/lifecycle-operations.d.ts.map +1 -0
- package/dist/runtime/lifecycle-operations.js +195 -0
- package/dist/runtime/lifecycle-operations.js.map +1 -0
- package/dist/runtime/operations.d.ts +3 -40
- package/dist/runtime/operations.js +2 -357
- package/dist/runtime/readable.d.ts +2 -3
- package/dist/runtime/readable.d.ts.map +1 -1
- package/dist/runtime/readable.js +6 -5
- package/dist/runtime/readable.js.map +1 -1
- package/dist/runtime/resource-cell.js +2 -2
- package/dist/runtime/resource-cell.js.map +1 -1
- package/dist/runtime/resource-operation.d.ts +13 -0
- package/dist/runtime/resource-operation.d.ts.map +1 -0
- package/dist/runtime/resource-operation.js +170 -0
- package/dist/runtime/resource-operation.js.map +1 -0
- package/dist/runtime/runtime.d.ts +42 -0
- package/dist/runtime/runtime.d.ts.map +1 -0
- package/dist/runtime/runtime.js +59 -0
- package/dist/runtime/runtime.js.map +1 -0
- package/dist/runtime/scheduler.d.ts +5 -1
- package/dist/runtime/scheduler.d.ts.map +1 -1
- package/dist/runtime/scheduler.js +17 -17
- package/dist/runtime/scheduler.js.map +1 -1
- package/dist/runtime/selector.js +4 -3
- package/dist/runtime/selector.js.map +1 -1
- package/dist/runtime/snapshot-source.d.ts +1 -1
- package/dist/runtime/snapshot-source.js +1 -1
- package/dist/runtime/state.js +2 -1
- package/dist/runtime/state.js.map +1 -1
- package/dist/ssg/batch-render.js +2 -1
- package/dist/ssg/batch-render.js.map +1 -1
- package/dist/ssg/create-static-gen.d.ts +9 -3
- package/dist/ssg/create-static-gen.d.ts.map +1 -1
- package/dist/ssg/create-static-gen.js +12 -99
- package/dist/ssg/create-static-gen.js.map +1 -1
- package/dist/ssg/generation-plan.js +70 -0
- package/dist/ssg/generation-plan.js.map +1 -0
- package/dist/ssg/incremental-manifest.js +1 -1
- package/dist/ssg/static-routes.js +101 -0
- package/dist/ssg/static-routes.js.map +1 -0
- package/dist/ssg/types.d.ts +15 -7
- package/dist/ssg/types.d.ts.map +1 -1
- package/dist/ssr/boundaries.js +113 -0
- package/dist/ssr/boundaries.js.map +1 -0
- package/dist/ssr/component-runtime.js +111 -0
- package/dist/ssr/component-runtime.js.map +1 -0
- package/dist/ssr/context.d.ts +3 -1
- package/dist/ssr/context.d.ts.map +1 -1
- package/dist/ssr/context.js +9 -2
- package/dist/ssr/context.js.map +1 -1
- package/dist/ssr/errors.d.ts +2 -0
- package/dist/ssr/errors.js +11 -1
- package/dist/ssr/errors.js.map +1 -1
- package/dist/ssr/escape.js +3 -3
- package/dist/ssr/escape.js.map +1 -1
- package/dist/ssr/hydration-data.js +10 -0
- package/dist/ssr/hydration-data.js.map +1 -0
- package/dist/ssr/hydration-verify.d.ts +12 -0
- package/dist/ssr/hydration-verify.d.ts.map +1 -0
- package/dist/ssr/hydration-verify.js +144 -0
- package/dist/ssr/hydration-verify.js.map +1 -0
- package/dist/ssr/index-internal.d.ts +15 -0
- package/dist/ssr/index-internal.d.ts.map +1 -0
- package/dist/ssr/index-internal.js +19 -0
- package/dist/ssr/index-internal.js.map +1 -0
- package/dist/ssr/index.d.ts +5 -57
- package/dist/ssr/index.js +3 -738
- package/dist/ssr/render-keys.js +9 -32
- package/dist/ssr/render-keys.js.map +1 -1
- package/dist/ssr/render-resolved.d.ts +1 -1
- package/dist/ssr/render-resolved.d.ts.map +1 -1
- package/dist/ssr/render-resolved.js +4 -2
- package/dist/ssr/render-resolved.js.map +1 -1
- package/dist/ssr/render-sync.d.ts +21 -0
- package/dist/ssr/render-sync.d.ts.map +1 -0
- package/dist/ssr/render-sync.js +275 -0
- package/dist/ssr/render-sync.js.map +1 -0
- package/dist/ssr/route-policy-resolution.js +77 -0
- package/dist/ssr/route-policy-resolution.js.map +1 -0
- package/dist/ssr/route-render.d.ts +77 -0
- package/dist/ssr/route-render.d.ts.map +1 -0
- package/dist/ssr/route-render.js +119 -0
- package/dist/ssr/route-render.js.map +1 -0
- package/dist/ssr/sink.d.ts +26 -0
- package/dist/ssr/sink.d.ts.map +1 -0
- package/dist/ssr/types.d.ts +1 -0
- package/dist/ssr/types.d.ts.map +1 -1
- package/dist/ssr/verify-hydration.js.map +1 -1
- package/dist/testing/index.d.ts +1 -2
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +2 -1
- package/dist/testing/index.js.map +1 -1
- package/package.json +4 -3
- package/dist/data/index.d.ts.map +0 -1
- package/dist/data/index.js.map +0 -1
- package/dist/renderer/dom.js.map +0 -1
- package/dist/router/route.d.ts.map +0 -1
- package/dist/router/route.js.map +0 -1
- package/dist/runtime/component.d.ts.map +0 -1
- package/dist/runtime/component.js.map +0 -1
- package/dist/runtime/for.d.ts.map +0 -1
- package/dist/runtime/for.js.map +0 -1
- package/dist/runtime/operations.d.ts.map +0 -1
- package/dist/runtime/operations.js.map +0 -1
- package/dist/runtime/ssr-bridge.js +0 -24
- package/dist/runtime/ssr-bridge.js.map +0 -1
- package/dist/ssr/index.d.ts.map +0 -1
- package/dist/ssr/index.js.map +0 -1
package/dist/router/navigate.js
CHANGED
|
@@ -1,431 +1,21 @@
|
|
|
1
|
-
import { isDevelopmentEnvironment, isProductionEnvironment } from "../common/env.js";
|
|
2
1
|
import { logger } from "../dev/logger.js";
|
|
3
|
-
import { ELEMENT_TYPE, Fragment } from "../common/jsx.js";
|
|
4
2
|
import { isPromiseLike } from "../common/promise.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import "
|
|
9
|
-
import { DefaultPortal, clearDefaultPortalForInstance } from "../foundations/structures/portal.js";
|
|
3
|
+
import { configureScrollRestoration, saveScrollPosition } from "./navigation-scroll.js";
|
|
4
|
+
import { configureNavigationRegistryHost, getCurrentHref, hasRegisteredApps, parseTargetUrl, registerAppInstance, unregisterAppInstance } from "./navigation-registry.js";
|
|
5
|
+
import { applyNavigationTargets, applyPopStateNavigationTargets, beginRouteRequest, cancelRouteRequests, isStaleRouteRequest, resolveNavigationTargetsForApps } from "./navigation-targets.js";
|
|
6
|
+
import { updateRouteQuery } from "./route-query.js";
|
|
10
7
|
//#region src/router/navigate.ts
|
|
11
8
|
/**
|
|
12
9
|
* Client-side navigation with History API
|
|
13
10
|
*/
|
|
14
|
-
let currentInstance = null;
|
|
15
|
-
let currentPathname = "/";
|
|
16
|
-
let currentHref = "/";
|
|
17
11
|
let navigationInitialized = false;
|
|
18
|
-
|
|
19
|
-
let activeRouteRequestController = null;
|
|
20
|
-
const MAX_NAVIGATION_REDIRECTS = 20;
|
|
21
|
-
const registeredApps = [];
|
|
22
|
-
function collectRouteActivityMatches(pathname, apps = registeredApps) {
|
|
23
|
-
const matches = [];
|
|
24
|
-
const seenPaths = /* @__PURE__ */ new Set();
|
|
25
|
-
for (const app of apps) {
|
|
26
|
-
const appMatches = computeRouteActivityMatches(pathname, {
|
|
27
|
-
manifest: app.manifest,
|
|
28
|
-
routes: app.routes
|
|
29
|
-
});
|
|
30
|
-
for (const match of appMatches) {
|
|
31
|
-
if (seenPaths.has(match.path)) continue;
|
|
32
|
-
seenPaths.add(match.path);
|
|
33
|
-
matches.push(match);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return matches;
|
|
37
|
-
}
|
|
38
|
-
function syncRegisteredRouteSnapshot() {
|
|
39
|
-
if (typeof window === "undefined") return;
|
|
40
|
-
const pathname = window.location.pathname || "/";
|
|
41
|
-
syncCurrentRouteSnapshot(pathname, window.location.search || "", window.location.hash || "", collectRouteActivityMatches(pathname));
|
|
42
|
-
}
|
|
43
|
-
function syncAppRegistrationLocation(app, pathname, href) {
|
|
44
|
-
app.pathname = pathname;
|
|
45
|
-
app.href = href;
|
|
46
|
-
}
|
|
47
|
-
const DEFAULT_SCROLL_RESTORATION = {
|
|
48
|
-
enabled: true,
|
|
49
|
-
navigation: "top",
|
|
50
|
-
history: "restore"
|
|
51
|
-
};
|
|
52
|
-
let scrollRestorationOptions = { ...DEFAULT_SCROLL_RESTORATION };
|
|
53
|
-
const scrollPositions = /* @__PURE__ */ new Map();
|
|
54
|
-
function getWindowHref() {
|
|
55
|
-
if (typeof window === "undefined") return currentHref;
|
|
56
|
-
return `${window.location.pathname}${window.location.search}${window.location.hash}`;
|
|
57
|
-
}
|
|
58
|
-
function normalizeScrollRestorationOptions(options) {
|
|
59
|
-
if (options === false) return {
|
|
60
|
-
enabled: false,
|
|
61
|
-
navigation: DEFAULT_SCROLL_RESTORATION.navigation,
|
|
62
|
-
history: DEFAULT_SCROLL_RESTORATION.history
|
|
63
|
-
};
|
|
64
|
-
if (options === true || options === void 0) return { ...DEFAULT_SCROLL_RESTORATION };
|
|
65
|
-
return {
|
|
66
|
-
enabled: true,
|
|
67
|
-
navigation: options.navigation ?? DEFAULT_SCROLL_RESTORATION.navigation,
|
|
68
|
-
history: options.history ?? DEFAULT_SCROLL_RESTORATION.history
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
function readScrollPosition() {
|
|
72
|
-
if (typeof window === "undefined") return {
|
|
73
|
-
x: 0,
|
|
74
|
-
y: 0
|
|
75
|
-
};
|
|
76
|
-
return {
|
|
77
|
-
x: typeof window.scrollX === "number" ? window.scrollX : typeof window.pageXOffset === "number" ? window.pageXOffset : 0,
|
|
78
|
-
y: typeof window.scrollY === "number" ? window.scrollY : typeof window.pageYOffset === "number" ? window.pageYOffset : 0
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
function writeHistoryScrollPosition(href, position) {
|
|
82
|
-
if (typeof window === "undefined" || getWindowHref() !== href) return;
|
|
83
|
-
if (typeof window.history?.replaceState !== "function") return;
|
|
84
|
-
const state = window.history.state && typeof window.history.state === "object" ? window.history.state : {};
|
|
85
|
-
window.history.replaceState({
|
|
86
|
-
...state,
|
|
87
|
-
path: href,
|
|
88
|
-
scroll: position
|
|
89
|
-
}, "", href);
|
|
90
|
-
}
|
|
91
|
-
function saveScrollPosition(href) {
|
|
92
|
-
if (!scrollRestorationOptions.enabled || typeof window === "undefined") return;
|
|
93
|
-
const position = readScrollPosition();
|
|
94
|
-
scrollPositions.set(href, position);
|
|
95
|
-
writeHistoryScrollPosition(href, position);
|
|
96
|
-
}
|
|
97
|
-
function scrollToPosition(position) {
|
|
98
|
-
if (typeof window === "undefined" || typeof window.scrollTo !== "function") return;
|
|
99
|
-
window.scrollTo(position.x, position.y);
|
|
100
|
-
}
|
|
101
|
-
function applyNavigationScroll(behavior) {
|
|
102
|
-
if (!scrollRestorationOptions.enabled || behavior === "preserve") return;
|
|
103
|
-
scrollToPosition({
|
|
104
|
-
x: 0,
|
|
105
|
-
y: 0
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
function applyHistoryScroll(href, state) {
|
|
109
|
-
if (!scrollRestorationOptions.enabled) return;
|
|
110
|
-
if (scrollRestorationOptions.history === "preserve") return;
|
|
111
|
-
if (scrollRestorationOptions.history === "top") {
|
|
112
|
-
scrollToPosition({
|
|
113
|
-
x: 0,
|
|
114
|
-
y: 0
|
|
115
|
-
});
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
const fromState = state && typeof state === "object" && "scroll" in state ? state.scroll : void 0;
|
|
119
|
-
scrollToPosition((fromState && typeof fromState.x === "number" && typeof fromState.y === "number" ? {
|
|
120
|
-
x: fromState.x,
|
|
121
|
-
y: fromState.y
|
|
122
|
-
} : scrollPositions.get(href)) ?? {
|
|
123
|
-
x: 0,
|
|
124
|
-
y: 0
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
function configureScrollRestoration(options) {
|
|
128
|
-
scrollRestorationOptions = normalizeScrollRestorationOptions(options);
|
|
129
|
-
if (typeof window === "undefined") return;
|
|
130
|
-
if ("scrollRestoration" in window.history) try {
|
|
131
|
-
window.history.scrollRestoration = scrollRestorationOptions.enabled ? "manual" : "auto";
|
|
132
|
-
} catch {}
|
|
133
|
-
}
|
|
134
|
-
function parseTargetUrl(path) {
|
|
135
|
-
const pathname = window.location.pathname || "/";
|
|
136
|
-
const search = window.location.search || "";
|
|
137
|
-
const hash = window.location.hash || "";
|
|
138
|
-
const href = typeof window.location.href === "string" ? window.location.href : "";
|
|
139
|
-
const base = href && href !== "about:blank" && !href.startsWith("about:") && !href.startsWith("data:") ? href : `http://localhost${pathname}${search}${hash}`;
|
|
140
|
-
return new URL(path, base);
|
|
141
|
-
}
|
|
142
|
-
function isRenderResult(result) {
|
|
143
|
-
return result !== null && result.kind === "render";
|
|
144
|
-
}
|
|
145
|
-
function getRedirectHistoryMode(replace) {
|
|
146
|
-
return replace === false ? "push" : "replace";
|
|
147
|
-
}
|
|
148
|
-
function getNavigationHistoryMode(options) {
|
|
149
|
-
if (options.history) return options.history;
|
|
150
|
-
return options.replace ? "replace" : "push";
|
|
151
|
-
}
|
|
152
|
-
function getRouteQueryHistoryMode(options) {
|
|
153
|
-
if (options.history) return options.history;
|
|
154
|
-
return options.replace === false ? "push" : "replace";
|
|
155
|
-
}
|
|
156
|
-
function setRouteQueryValue(searchParams, key, value) {
|
|
157
|
-
searchParams.delete(key);
|
|
158
|
-
if (Array.isArray(value)) {
|
|
159
|
-
for (const entry of value) {
|
|
160
|
-
if (entry === null || entry === void 0) continue;
|
|
161
|
-
searchParams.append(key, String(entry));
|
|
162
|
-
}
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
if (value === null || value === void 0) return;
|
|
166
|
-
searchParams.set(key, String(value));
|
|
167
|
-
}
|
|
168
|
-
function applyRouteQueryUpdates(searchParams, updates) {
|
|
169
|
-
if (typeof updates === "function") {
|
|
170
|
-
updates(searchParams);
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
for (const [key, value] of Object.entries(updates)) setRouteQueryValue(searchParams, key, value);
|
|
174
|
-
}
|
|
175
|
-
/**
|
|
176
|
-
* Update the current URL query string without resolving or remounting the
|
|
177
|
-
* route. This is intended for route-local view state such as filters, search,
|
|
178
|
-
* tabs, and pagination.
|
|
179
|
-
*/
|
|
180
|
-
function updateRouteQuery(updates, options = {}) {
|
|
181
|
-
if (typeof window === "undefined") return;
|
|
182
|
-
const url = parseTargetUrl(getWindowHref());
|
|
183
|
-
applyRouteQueryUpdates(url.searchParams, updates);
|
|
184
|
-
const href = `${url.pathname}${url.search}${url.hash}`;
|
|
185
|
-
if (href === getWindowHref()) return;
|
|
186
|
-
const historyMode = getRouteQueryHistoryMode(options);
|
|
187
|
-
if (historyMode === "push") saveScrollPosition(currentHref);
|
|
188
|
-
const state = window.history.state && typeof window.history.state === "object" ? window.history.state : {};
|
|
189
|
-
window.history[historyMode === "replace" ? "replaceState" : "pushState"]({
|
|
190
|
-
...state,
|
|
191
|
-
path: href
|
|
192
|
-
}, "", href);
|
|
193
|
-
currentPathname = url.pathname;
|
|
194
|
-
currentHref = href;
|
|
195
|
-
for (const app of registeredApps) syncAppRegistrationLocation(app, url.pathname, href);
|
|
196
|
-
syncRegisteredRouteSnapshot();
|
|
197
|
-
}
|
|
198
|
-
function beginRouteRequest() {
|
|
199
|
-
activeRouteRequestId += 1;
|
|
200
|
-
activeRouteRequestController?.abort();
|
|
201
|
-
activeRouteRequestController = new AbortController();
|
|
202
|
-
return {
|
|
203
|
-
id: activeRouteRequestId,
|
|
204
|
-
signal: activeRouteRequestController.signal
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
function isStaleRouteRequest(requestId) {
|
|
208
|
-
return requestId !== activeRouteRequestId;
|
|
209
|
-
}
|
|
210
|
-
function createDeniedResolvedRoute(status) {
|
|
211
|
-
return {
|
|
212
|
-
handler: () => ({
|
|
213
|
-
type: "div",
|
|
214
|
-
props: { "data-route-denied": String(status) },
|
|
215
|
-
children: [String(status)]
|
|
216
|
-
}),
|
|
217
|
-
params: {}
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
function bindResolvedRouteHandler(resolved) {
|
|
221
|
-
return () => resolved.handler(resolved.params);
|
|
222
|
-
}
|
|
223
|
-
function wrapRootRouteHandler(componentFn) {
|
|
224
|
-
const wrappedFn = (props, ctx) => {
|
|
225
|
-
const out = componentFn(props, ctx);
|
|
226
|
-
if (isPromiseLike(out)) throw new Error("Async components are not supported. Components must return synchronously.");
|
|
227
|
-
const portalVNode = {
|
|
228
|
-
$$typeof: ELEMENT_TYPE,
|
|
229
|
-
type: DefaultPortal,
|
|
230
|
-
props: {},
|
|
231
|
-
key: "__default_portal"
|
|
232
|
-
};
|
|
233
|
-
return {
|
|
234
|
-
$$typeof: ELEMENT_TYPE,
|
|
235
|
-
type: Fragment,
|
|
236
|
-
props: { children: out === void 0 || out === null ? [portalVNode] : [out, portalVNode] }
|
|
237
|
-
};
|
|
238
|
-
};
|
|
239
|
-
Object.defineProperty(wrappedFn, "name", { value: componentFn.name || "Component" });
|
|
240
|
-
return wrappedFn;
|
|
241
|
-
}
|
|
242
|
-
function cleanupRouteOwnership(instance) {
|
|
243
|
-
const cleanupErrors = [];
|
|
244
|
-
const children = instance.target ? Array.from(instance.target.childNodes) : [];
|
|
245
|
-
for (const child of children) try {
|
|
246
|
-
cleanupInstancesUnder(child, { strict: instance.cleanupStrict });
|
|
247
|
-
} catch (error) {
|
|
248
|
-
cleanupErrors.push(error);
|
|
249
|
-
}
|
|
250
|
-
try {
|
|
251
|
-
cleanupComponent(instance);
|
|
252
|
-
} catch (error) {
|
|
253
|
-
cleanupErrors.push(error);
|
|
254
|
-
}
|
|
255
|
-
if (cleanupErrors.length > 0) throw new AggregateError(cleanupErrors, "Route cleanup failed");
|
|
256
|
-
}
|
|
257
|
-
function remountResolvedRoute(instance, resolved, pathname, href) {
|
|
258
|
-
clearDefaultPortalForInstance(instance);
|
|
259
|
-
cleanupRouteOwnership(instance);
|
|
260
|
-
instance.fn = wrapRootRouteHandler(bindResolvedRouteHandler(resolved));
|
|
261
|
-
instance.props = {};
|
|
262
|
-
instance.stateValues = [];
|
|
263
|
-
instance.expectedStateIndices = [];
|
|
264
|
-
instance.firstRenderComplete = false;
|
|
265
|
-
instance.stateIndexCheck = -1;
|
|
266
|
-
instance.evaluationGeneration++;
|
|
267
|
-
instance.notifyUpdate = null;
|
|
268
|
-
instance.mountOperations = [];
|
|
269
|
-
instance.commitOperations = [];
|
|
270
|
-
instance.lifecycleSlots = [];
|
|
271
|
-
instance.cleanupFns = [];
|
|
272
|
-
instance._placeholder = void 0;
|
|
273
|
-
instance.hasPendingUpdate = false;
|
|
274
|
-
instance._currentRenderToken = void 0;
|
|
275
|
-
instance.lastRenderToken = 0;
|
|
276
|
-
instance._pendingReadSources = void 0;
|
|
277
|
-
instance._lastReadSources = void 0;
|
|
278
|
-
instance.abortController = null;
|
|
279
|
-
mountComponent(instance);
|
|
280
|
-
currentPathname = pathname;
|
|
281
|
-
currentHref = href;
|
|
282
|
-
return true;
|
|
283
|
-
}
|
|
284
|
-
function rerenderResolvedRoute(instance, pathname, href) {
|
|
285
|
-
currentPathname = pathname;
|
|
286
|
-
currentHref = href;
|
|
287
|
-
instance._enqueueRun?.();
|
|
288
|
-
return true;
|
|
289
|
-
}
|
|
290
|
-
function resolveAppRouteRequest(app, pathname, href, signal) {
|
|
291
|
-
if (app.routes) {
|
|
292
|
-
const resolved = resolveRouteFromRoutes(pathname, app.routes);
|
|
293
|
-
if (!resolved) return null;
|
|
294
|
-
return {
|
|
295
|
-
kind: "render",
|
|
296
|
-
handler: resolved.handler,
|
|
297
|
-
params: resolved.params
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
return resolveRouteRequest(href, {
|
|
301
|
-
manifest: app.manifest,
|
|
302
|
-
auth: app.auth,
|
|
303
|
-
signal
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
function resolveNavigationTargetsForApps(pathname, href, signal) {
|
|
307
|
-
const apps = [...registeredApps];
|
|
308
|
-
if (apps.length === 1) {
|
|
309
|
-
const app = apps[0];
|
|
310
|
-
const resolved = resolveAppRouteRequest(app, pathname, href, signal);
|
|
311
|
-
if (isPromiseLike(resolved)) return Promise.resolve(resolved).then((next) => [{
|
|
312
|
-
app,
|
|
313
|
-
resolved: next
|
|
314
|
-
}]);
|
|
315
|
-
return [{
|
|
316
|
-
app,
|
|
317
|
-
resolved
|
|
318
|
-
}];
|
|
319
|
-
}
|
|
320
|
-
const syncTargets = [];
|
|
321
|
-
const pendingTargets = [];
|
|
322
|
-
for (const app of apps) {
|
|
323
|
-
const resolved = resolveAppRouteRequest(app, pathname, href, signal);
|
|
324
|
-
if (isPromiseLike(resolved)) {
|
|
325
|
-
pendingTargets.push(Promise.resolve(resolved).then((next) => ({
|
|
326
|
-
app,
|
|
327
|
-
resolved: next
|
|
328
|
-
})));
|
|
329
|
-
continue;
|
|
330
|
-
}
|
|
331
|
-
syncTargets.push({
|
|
332
|
-
app,
|
|
333
|
-
resolved
|
|
334
|
-
});
|
|
335
|
-
}
|
|
336
|
-
if (pendingTargets.length === 0) return syncTargets;
|
|
337
|
-
return Promise.all([...syncTargets.map((target) => Promise.resolve(target)), ...pendingTargets]);
|
|
338
|
-
}
|
|
339
|
-
function applyNavigationTargets(path, options, redirectState, pathname, href, targets) {
|
|
340
|
-
const previousPathname = currentPathname;
|
|
341
|
-
for (const target of targets) {
|
|
342
|
-
const resolved = target.resolved;
|
|
343
|
-
if (!resolved || resolved.kind !== "redirect") continue;
|
|
344
|
-
const redirectTarget = parseTargetUrl(resolved.to);
|
|
345
|
-
const redirectHref = `${redirectTarget.pathname}${redirectTarget.search}${redirectTarget.hash}`;
|
|
346
|
-
if (redirectHref === href) {
|
|
347
|
-
if (isDevelopmentEnvironment()) logger.warn(`Navigation guard redirected to the same path: ${redirectHref}`);
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
350
|
-
if (redirectState.visited.has(redirectHref)) throw new Error(`[Askr] Navigation redirect cycle detected at ${redirectHref}.`);
|
|
351
|
-
if (redirectState.redirects >= MAX_NAVIGATION_REDIRECTS) throw new Error(`[Askr] Navigation redirect limit exceeded (${MAX_NAVIGATION_REDIRECTS}).`);
|
|
352
|
-
redirectState.visited.add(redirectHref);
|
|
353
|
-
redirectState.redirects++;
|
|
354
|
-
navigateWithRedirectState(redirectHref, { history: getRedirectHistoryMode(resolved.replace) }, redirectState);
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
const matchedTargets = targets.filter((target) => target.resolved !== null);
|
|
358
|
-
if (matchedTargets.length === 0) {
|
|
359
|
-
if (isDevelopmentEnvironment()) logger.warn(`No route found for path: ${path}`);
|
|
360
|
-
return;
|
|
361
|
-
}
|
|
362
|
-
saveScrollPosition(currentHref);
|
|
363
|
-
const historyMethod = getNavigationHistoryMode(options) === "replace" ? "replaceState" : "pushState";
|
|
364
|
-
window.history[historyMethod]({ path: href }, "", href);
|
|
365
|
-
syncRegisteredRouteSnapshot();
|
|
366
|
-
for (const target of matchedTargets) {
|
|
367
|
-
const resolved = target.resolved;
|
|
368
|
-
if (resolved.kind === "redirect") continue;
|
|
369
|
-
if (pathname === target.app.pathname && isRenderResult(resolved)) {
|
|
370
|
-
rerenderResolvedRoute(target.app.instance, pathname, href);
|
|
371
|
-
syncAppRegistrationLocation(target.app, pathname, href);
|
|
372
|
-
continue;
|
|
373
|
-
}
|
|
374
|
-
remountResolvedRoute(target.app.instance, resolved.kind === "deny" ? createDeniedResolvedRoute(resolved.status) : {
|
|
375
|
-
handler: resolved.handler,
|
|
376
|
-
params: resolved.params
|
|
377
|
-
}, pathname, href);
|
|
378
|
-
syncAppRegistrationLocation(target.app, pathname, href);
|
|
379
|
-
}
|
|
380
|
-
if (pathname !== previousPathname) applyNavigationScroll(options.scroll ?? scrollRestorationOptions.navigation);
|
|
381
|
-
}
|
|
382
|
-
/** Register the current app instance (called by createSPA/hydrateSPA). */
|
|
383
|
-
function registerAppInstance(instance, path, source = {}) {
|
|
384
|
-
const existingIndex = registeredApps.findIndex((app) => app.instance === instance);
|
|
385
|
-
const registration = {
|
|
386
|
-
instance,
|
|
387
|
-
pathname: path,
|
|
388
|
-
href: getWindowHref(),
|
|
389
|
-
...source
|
|
390
|
-
};
|
|
391
|
-
if (existingIndex >= 0) registeredApps[existingIndex] = registration;
|
|
392
|
-
else registeredApps.push(registration);
|
|
393
|
-
currentInstance = instance;
|
|
394
|
-
currentPathname = path;
|
|
395
|
-
currentHref = getWindowHref();
|
|
396
|
-
syncRegisteredRouteSnapshot();
|
|
397
|
-
if (isProductionEnvironment()) lockRouteRegistration();
|
|
398
|
-
}
|
|
399
|
-
function unregisterAppInstance(instance) {
|
|
400
|
-
const existingIndex = registeredApps.findIndex((app) => app.instance === instance);
|
|
401
|
-
if (existingIndex >= 0) registeredApps.splice(existingIndex, 1);
|
|
402
|
-
syncRegisteredRouteSnapshot();
|
|
403
|
-
if (currentInstance !== instance) return;
|
|
404
|
-
const nextApp = registeredApps.length > 0 ? registeredApps[registeredApps.length - 1] : null;
|
|
405
|
-
currentInstance = nextApp?.instance ?? null;
|
|
406
|
-
if (nextApp) {
|
|
407
|
-
currentPathname = nextApp.pathname;
|
|
408
|
-
currentHref = nextApp.href;
|
|
409
|
-
syncRegisteredRouteSnapshot();
|
|
410
|
-
return;
|
|
411
|
-
}
|
|
412
|
-
activeRouteRequestId += 1;
|
|
413
|
-
activeRouteRequestController?.abort();
|
|
414
|
-
activeRouteRequestController = null;
|
|
415
|
-
currentPathname = "/";
|
|
416
|
-
currentHref = "/";
|
|
417
|
-
if (typeof window === "undefined") syncCurrentRouteSnapshot("/", "", "", []);
|
|
418
|
-
}
|
|
419
|
-
/**
|
|
420
|
-
* Navigate to a new path
|
|
421
|
-
* Updates URL, resolves route, and re-mounts app with new handler
|
|
422
|
-
*/
|
|
12
|
+
configureNavigationRegistryHost({ cancelRouteRequests });
|
|
423
13
|
function navigate(path, options = {}) {
|
|
424
14
|
if (typeof window === "undefined") return;
|
|
425
15
|
const initialTarget = parseTargetUrl(path);
|
|
426
16
|
navigateWithRedirectState(path, options, {
|
|
427
17
|
redirects: 0,
|
|
428
|
-
visited: new Set([`${initialTarget.pathname}${initialTarget.search}${initialTarget.hash}`])
|
|
18
|
+
visited: /* @__PURE__ */ new Set([`${initialTarget.pathname}${initialTarget.search}${initialTarget.hash}`])
|
|
429
19
|
});
|
|
430
20
|
}
|
|
431
21
|
function navigateWithRedirectState(path, options, redirectState) {
|
|
@@ -439,7 +29,7 @@ function navigateWithRedirectState(path, options, redirectState) {
|
|
|
439
29
|
Promise.resolve(resolvedTargets).then((targets) => {
|
|
440
30
|
if (isStaleRouteRequest(request.id)) return;
|
|
441
31
|
try {
|
|
442
|
-
applyNavigationTargets(path, options, redirectState, pathname, href, targets);
|
|
32
|
+
applyNavigationTargets(path, options, redirectState, pathname, href, targets, navigateWithRedirectState);
|
|
443
33
|
} catch (error) {
|
|
444
34
|
logger.error("[Askr] navigation failed:", error);
|
|
445
35
|
}
|
|
@@ -448,56 +38,26 @@ function navigateWithRedirectState(path, options, redirectState) {
|
|
|
448
38
|
});
|
|
449
39
|
return;
|
|
450
40
|
}
|
|
451
|
-
applyNavigationTargets(path, options, redirectState, pathname, href, resolvedTargets);
|
|
41
|
+
applyNavigationTargets(path, options, redirectState, pathname, href, resolvedTargets, navigateWithRedirectState);
|
|
452
42
|
}
|
|
453
|
-
|
|
454
|
-
* Handle browser back/forward buttons
|
|
455
|
-
*/
|
|
456
|
-
function handlePopState(_event) {
|
|
43
|
+
function handlePopState(event) {
|
|
457
44
|
const request = beginRouteRequest();
|
|
458
|
-
const previousHref =
|
|
45
|
+
const previousHref = getCurrentHref();
|
|
459
46
|
const pathname = window.location.pathname;
|
|
460
47
|
const href = `${window.location.pathname}${window.location.search}${window.location.hash}`;
|
|
461
48
|
saveScrollPosition(previousHref);
|
|
462
|
-
if (
|
|
49
|
+
if (!hasRegisteredApps()) return;
|
|
463
50
|
const applyResolved = (targets) => {
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
return;
|
|
469
|
-
}
|
|
470
|
-
for (const target of matchedTargets) {
|
|
471
|
-
const resolved = target.resolved;
|
|
472
|
-
if (resolved.kind !== "redirect") continue;
|
|
473
|
-
navigate(resolved.to, { history: getRedirectHistoryMode(resolved.replace) });
|
|
474
|
-
return;
|
|
475
|
-
}
|
|
476
|
-
syncRegisteredRouteSnapshot();
|
|
477
|
-
for (const target of matchedTargets) {
|
|
478
|
-
const resolved = target.resolved;
|
|
479
|
-
if (pathname === target.app.pathname && isRenderResult(resolved)) {
|
|
480
|
-
rerenderResolvedRoute(target.app.instance, pathname, href);
|
|
481
|
-
syncAppRegistrationLocation(target.app, pathname, href);
|
|
482
|
-
continue;
|
|
483
|
-
}
|
|
484
|
-
if (resolved.kind === "redirect") continue;
|
|
485
|
-
remountResolvedRoute(target.app.instance, resolved.kind === "deny" ? createDeniedResolvedRoute(resolved.status) : {
|
|
486
|
-
handler: resolved.handler,
|
|
487
|
-
params: resolved.params
|
|
488
|
-
}, pathname, href);
|
|
489
|
-
syncAppRegistrationLocation(target.app, pathname, href);
|
|
51
|
+
try {
|
|
52
|
+
applyPopStateNavigationTargets(request.id, pathname, href, event.state, targets, navigate);
|
|
53
|
+
} catch (error) {
|
|
54
|
+
logger.error("[Askr] popstate navigation failed:", error);
|
|
490
55
|
}
|
|
491
|
-
applyHistoryScroll(href, _event.state);
|
|
492
56
|
};
|
|
493
57
|
const resolvedTargets = resolveNavigationTargetsForApps(pathname, href, request.signal);
|
|
494
58
|
if (isPromiseLike(resolvedTargets)) {
|
|
495
59
|
Promise.resolve(resolvedTargets).then((next) => {
|
|
496
|
-
|
|
497
|
-
applyResolved(next);
|
|
498
|
-
} catch (error) {
|
|
499
|
-
logger.error("[Askr] popstate navigation failed:", error);
|
|
500
|
-
}
|
|
60
|
+
applyResolved(next);
|
|
501
61
|
}, (error) => {
|
|
502
62
|
logger.error("[Askr] popstate navigation failed:", error);
|
|
503
63
|
});
|
|
@@ -505,9 +65,6 @@ function handlePopState(_event) {
|
|
|
505
65
|
}
|
|
506
66
|
applyResolved(resolvedTargets);
|
|
507
67
|
}
|
|
508
|
-
/**
|
|
509
|
-
* Setup popstate listener for browser navigation
|
|
510
|
-
*/
|
|
511
68
|
function initializeNavigation() {
|
|
512
69
|
if (typeof window === "undefined" || navigationInitialized) return;
|
|
513
70
|
navigationInitialized = true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigate.js","names":[],"sources":["../../src/router/navigate.ts"],"sourcesContent":["/**\n * Client-side navigation with History API\n */\n\nimport {\n computeRouteActivityMatches,\n resolveRouteRequest,\n resolveRouteFromRoutes,\n lockRouteRegistration,\n syncCurrentRouteSnapshot,\n type ResolvedRoute,\n} from './route';\nimport {\n cleanupComponent,\n mountComponent,\n type ComponentInstance,\n} from '../runtime/component';\nimport {\n isDevelopmentEnvironment,\n isProductionEnvironment,\n} from '../common/env';\nimport { logger } from '../dev/logger';\nimport type {\n Route,\n RouteAuthOptions,\n RouteManifest,\n RouteRenderResult,\n RouteRequestResult,\n} from '../common/router';\nimport { Fragment, ELEMENT_TYPE } from '../jsx';\nimport {\n DefaultPortal,\n clearDefaultPortalForInstance,\n} from '../foundations/structures/portal';\nimport { isPromiseLike } from '../common/promise';\nimport { cleanupInstancesUnder } from '../renderer/cleanup';\n\n// Global app state for navigation\nlet currentInstance: ComponentInstance | null = null;\nlet currentPathname = '/';\nlet currentHref = '/';\nlet navigationInitialized = false;\nlet activeRouteRequestId = 0;\nlet activeRouteRequestController: AbortController | null = null;\nconst MAX_NAVIGATION_REDIRECTS = 20;\n\ntype AppNavigationSource = {\n manifest?: RouteManifest;\n routes?: readonly Route[];\n auth?: RouteAuthOptions;\n};\n\ntype AppRegistration = AppNavigationSource & {\n instance: ComponentInstance;\n pathname: string;\n href: string;\n};\n\nconst registeredApps: AppRegistration[] = [];\n\nfunction collectRouteActivityMatches(\n pathname: string,\n apps: readonly AppRegistration[] = registeredApps\n) {\n const matches: ReturnType<typeof computeRouteActivityMatches> = [];\n const seenPaths = new Set<string>();\n\n for (const app of apps) {\n const appMatches = computeRouteActivityMatches(pathname, {\n manifest: app.manifest,\n routes: app.routes,\n });\n\n for (const match of appMatches) {\n if (seenPaths.has(match.path)) {\n continue;\n }\n seenPaths.add(match.path);\n matches.push(match);\n }\n }\n\n return matches;\n}\n\nfunction syncRegisteredRouteSnapshot(): void {\n if (typeof window === 'undefined') {\n return;\n }\n\n const pathname = window.location.pathname || '/';\n syncCurrentRouteSnapshot(\n pathname,\n window.location.search || '',\n window.location.hash || '',\n collectRouteActivityMatches(pathname)\n );\n}\n\nfunction syncAppRegistrationLocation(\n app: AppRegistration,\n pathname: string,\n href: string\n): void {\n app.pathname = pathname;\n app.href = href;\n}\n\nexport type NavigationScrollBehavior = 'top' | 'preserve';\nexport type HistoryScrollBehavior = 'restore' | 'top' | 'preserve';\n\nexport type ScrollRestorationOptions = {\n navigation?: NavigationScrollBehavior;\n history?: HistoryScrollBehavior;\n};\n\ntype NormalizedScrollRestorationOptions = {\n enabled: boolean;\n navigation: NavigationScrollBehavior;\n history: HistoryScrollBehavior;\n};\n\nconst DEFAULT_SCROLL_RESTORATION: NormalizedScrollRestorationOptions = {\n enabled: true,\n navigation: 'top',\n history: 'restore',\n};\n\nlet scrollRestorationOptions: NormalizedScrollRestorationOptions = {\n ...DEFAULT_SCROLL_RESTORATION,\n};\n\nconst scrollPositions = new Map<string, { x: number; y: number }>();\n\nexport type NavigateOptions = {\n history?: 'push' | 'replace';\n replace?: boolean;\n scroll?: NavigationScrollBehavior;\n};\n\nexport type RouteQueryParamValue = string | number | boolean | null | undefined;\nexport type RouteQueryParamInput =\n | RouteQueryParamValue\n | readonly RouteQueryParamValue[];\nexport type RouteQueryUpdates = Record<string, RouteQueryParamInput>;\nexport type RouteQueryUpdater = (searchParams: URLSearchParams) => void;\n\nexport type UpdateRouteQueryOptions = {\n /**\n * Defaults to replace so high-frequency controls such as search inputs do not\n * create one browser-history entry per character.\n */\n history?: 'push' | 'replace';\n replace?: boolean;\n};\n\nfunction getWindowHref(): string {\n if (typeof window === 'undefined') {\n return currentHref;\n }\n\n return `${window.location.pathname}${window.location.search}${window.location.hash}`;\n}\n\nfunction normalizeScrollRestorationOptions(\n options?: boolean | ScrollRestorationOptions\n): NormalizedScrollRestorationOptions {\n if (options === false) {\n return {\n enabled: false,\n navigation: DEFAULT_SCROLL_RESTORATION.navigation,\n history: DEFAULT_SCROLL_RESTORATION.history,\n };\n }\n\n if (options === true || options === undefined) {\n return { ...DEFAULT_SCROLL_RESTORATION };\n }\n\n return {\n enabled: true,\n navigation: options.navigation ?? DEFAULT_SCROLL_RESTORATION.navigation,\n history: options.history ?? DEFAULT_SCROLL_RESTORATION.history,\n };\n}\n\nfunction readScrollPosition(): { x: number; y: number } {\n if (typeof window === 'undefined') {\n return { x: 0, y: 0 };\n }\n\n const x =\n typeof window.scrollX === 'number'\n ? window.scrollX\n : typeof window.pageXOffset === 'number'\n ? window.pageXOffset\n : 0;\n const y =\n typeof window.scrollY === 'number'\n ? window.scrollY\n : typeof window.pageYOffset === 'number'\n ? window.pageYOffset\n : 0;\n\n return { x, y };\n}\n\nfunction writeHistoryScrollPosition(\n href: string,\n position: { x: number; y: number }\n): void {\n if (typeof window === 'undefined' || getWindowHref() !== href) {\n return;\n }\n if (typeof window.history?.replaceState !== 'function') {\n return;\n }\n const state =\n window.history.state && typeof window.history.state === 'object'\n ? window.history.state\n : {};\n\n window.history.replaceState(\n {\n ...state,\n path: href,\n scroll: position,\n },\n '',\n href\n );\n}\n\nfunction saveScrollPosition(href: string): void {\n if (!scrollRestorationOptions.enabled || typeof window === 'undefined') {\n return;\n }\n\n const position = readScrollPosition();\n scrollPositions.set(href, position);\n writeHistoryScrollPosition(href, position);\n}\n\nfunction scrollToPosition(position: { x: number; y: number }): void {\n if (typeof window === 'undefined' || typeof window.scrollTo !== 'function') {\n return;\n }\n\n window.scrollTo(position.x, position.y);\n}\n\nfunction applyNavigationScroll(behavior: NavigationScrollBehavior): void {\n if (!scrollRestorationOptions.enabled || behavior === 'preserve') {\n return;\n }\n\n scrollToPosition({ x: 0, y: 0 });\n}\n\nfunction applyHistoryScroll(href: string, state: PopStateEvent['state']): void {\n if (!scrollRestorationOptions.enabled) {\n return;\n }\n\n if (scrollRestorationOptions.history === 'preserve') {\n return;\n }\n\n if (scrollRestorationOptions.history === 'top') {\n scrollToPosition({ x: 0, y: 0 });\n return;\n }\n\n const fromState =\n state && typeof state === 'object' && 'scroll' in state\n ? (state.scroll as { x?: unknown; y?: unknown })\n : undefined;\n const saved =\n fromState &&\n typeof fromState.x === 'number' &&\n typeof fromState.y === 'number'\n ? { x: fromState.x, y: fromState.y }\n : scrollPositions.get(href);\n\n scrollToPosition(saved ?? { x: 0, y: 0 });\n}\n\nexport function configureScrollRestoration(\n options?: boolean | ScrollRestorationOptions\n): void {\n scrollRestorationOptions = normalizeScrollRestorationOptions(options);\n\n if (typeof window === 'undefined') {\n return;\n }\n\n if ('scrollRestoration' in window.history) {\n try {\n window.history.scrollRestoration = scrollRestorationOptions.enabled\n ? 'manual'\n : 'auto';\n } catch {\n // Ignore environments that expose but do not allow setting scrollRestoration.\n }\n }\n}\n\nfunction parseTargetUrl(path: string): URL {\n const pathname = window.location.pathname || '/';\n const search = window.location.search || '';\n const hash = window.location.hash || '';\n const href =\n typeof window.location.href === 'string' ? window.location.href : '';\n const base =\n href &&\n href !== 'about:blank' &&\n !href.startsWith('about:') &&\n !href.startsWith('data:')\n ? href\n : `http://localhost${pathname}${search}${hash}`;\n\n return new URL(path, base);\n}\n\nfunction isRenderResult(\n result: RouteRequestResult\n): result is RouteRenderResult {\n return result !== null && result.kind === 'render';\n}\n\nfunction getRedirectHistoryMode(\n replace: boolean | undefined\n): 'push' | 'replace' {\n return replace === false ? 'push' : 'replace';\n}\n\nfunction getNavigationHistoryMode(\n options: NavigateOptions\n): 'push' | 'replace' {\n if (options.history) {\n return options.history;\n }\n\n return options.replace ? 'replace' : 'push';\n}\n\nfunction getRouteQueryHistoryMode(\n options: UpdateRouteQueryOptions\n): 'push' | 'replace' {\n if (options.history) {\n return options.history;\n }\n\n return options.replace === false ? 'push' : 'replace';\n}\n\nfunction setRouteQueryValue(\n searchParams: URLSearchParams,\n key: string,\n value: RouteQueryParamInput\n): void {\n searchParams.delete(key);\n\n if (Array.isArray(value)) {\n for (const entry of value) {\n if (entry === null || entry === undefined) {\n continue;\n }\n searchParams.append(key, String(entry));\n }\n return;\n }\n\n if (value === null || value === undefined) {\n return;\n }\n\n searchParams.set(key, String(value));\n}\n\nfunction applyRouteQueryUpdates(\n searchParams: URLSearchParams,\n updates: RouteQueryUpdates | RouteQueryUpdater\n): void {\n if (typeof updates === 'function') {\n updates(searchParams);\n return;\n }\n\n for (const [key, value] of Object.entries(updates)) {\n setRouteQueryValue(searchParams, key, value);\n }\n}\n\n/**\n * Update the current URL query string without resolving or remounting the\n * route. This is intended for route-local view state such as filters, search,\n * tabs, and pagination.\n */\nexport function updateRouteQuery(\n updates: RouteQueryUpdates | RouteQueryUpdater,\n options: UpdateRouteQueryOptions = {}\n): void {\n if (typeof window === 'undefined') {\n return;\n }\n\n const url = parseTargetUrl(getWindowHref());\n applyRouteQueryUpdates(url.searchParams, updates);\n\n const href = `${url.pathname}${url.search}${url.hash}`;\n if (href === getWindowHref()) {\n return;\n }\n\n const historyMode = getRouteQueryHistoryMode(options);\n if (historyMode === 'push') {\n saveScrollPosition(currentHref);\n }\n\n const state =\n window.history.state && typeof window.history.state === 'object'\n ? window.history.state\n : {};\n\n window.history[historyMode === 'replace' ? 'replaceState' : 'pushState'](\n {\n ...state,\n path: href,\n },\n '',\n href\n );\n\n currentPathname = url.pathname;\n currentHref = href;\n for (const app of registeredApps) {\n syncAppRegistrationLocation(app, url.pathname, href);\n }\n syncRegisteredRouteSnapshot();\n}\n\nfunction beginRouteRequest(): { id: number; signal: AbortSignal } {\n activeRouteRequestId += 1;\n activeRouteRequestController?.abort();\n activeRouteRequestController = new AbortController();\n\n return {\n id: activeRouteRequestId,\n signal: activeRouteRequestController.signal,\n };\n}\n\nfunction isStaleRouteRequest(requestId: number): boolean {\n return requestId !== activeRouteRequestId;\n}\n\nfunction createDeniedResolvedRoute(status: number): ResolvedRoute {\n return {\n handler: () => ({\n type: 'div',\n props: {\n 'data-route-denied': String(status),\n },\n children: [String(status)],\n }),\n params: {},\n };\n}\n\nfunction bindResolvedRouteHandler(\n resolved: ResolvedRoute\n): ComponentInstance['fn'] {\n return () =>\n resolved.handler(resolved.params) as ReturnType<ComponentInstance['fn']>;\n}\n\nfunction wrapRootRouteHandler(\n componentFn: ComponentInstance['fn']\n): ComponentInstance['fn'] {\n const wrappedFn: ComponentInstance['fn'] = (props, ctx) => {\n const out = componentFn(props, ctx);\n if (isPromiseLike(out)) {\n throw new Error(\n 'Async components are not supported. Components must return synchronously.'\n );\n }\n const portalVNode = {\n $$typeof: ELEMENT_TYPE,\n type: DefaultPortal,\n props: {},\n key: '__default_portal',\n } as unknown;\n\n return {\n $$typeof: ELEMENT_TYPE,\n type: Fragment,\n props: {\n children:\n out === undefined || out === null\n ? [portalVNode]\n : [out, portalVNode],\n },\n } as ReturnType<ComponentInstance['fn']>;\n };\n\n Object.defineProperty(wrappedFn, 'name', {\n value: componentFn.name || 'Component',\n });\n\n return wrappedFn;\n}\n\nfunction cleanupRouteOwnership(instance: ComponentInstance): void {\n const cleanupErrors: unknown[] = [];\n const children = instance.target\n ? Array.from(instance.target.childNodes)\n : [];\n\n for (const child of children) {\n try {\n cleanupInstancesUnder(child, { strict: instance.cleanupStrict });\n } catch (error) {\n cleanupErrors.push(error);\n }\n }\n\n try {\n cleanupComponent(instance);\n } catch (error) {\n cleanupErrors.push(error);\n }\n\n if (cleanupErrors.length > 0) {\n throw new AggregateError(cleanupErrors, 'Route cleanup failed');\n }\n}\n\nfunction remountResolvedRoute(\n instance: ComponentInstance,\n resolved: ResolvedRoute,\n pathname: string,\n href: string\n): boolean {\n // The route handler IS the component function\n // It takes params as props and renders the route\n clearDefaultPortalForInstance(instance);\n cleanupRouteOwnership(instance);\n\n instance.fn = wrapRootRouteHandler(bindResolvedRouteHandler(resolved));\n instance.props = {};\n\n // Reset state to prevent leakage from previous route\n // Each route navigation starts completely fresh\n instance.stateValues = [];\n instance.expectedStateIndices = [];\n instance.firstRenderComplete = false;\n instance.stateIndexCheck = -1;\n // Increment generation to invalidate pending async evaluations from previous route\n instance.evaluationGeneration++;\n instance.notifyUpdate = null;\n instance.mountOperations = [];\n instance.commitOperations = [];\n instance.lifecycleSlots = [];\n instance.cleanupFns = [];\n instance._placeholder = undefined;\n instance.hasPendingUpdate = false;\n instance._currentRenderToken = undefined;\n instance.lastRenderToken = 0;\n instance._pendingReadSources = undefined;\n instance._lastReadSources = undefined;\n\n // Route-local async work should create a fresh abort controller lazily.\n instance.abortController = null;\n\n // Re-execute component against the existing host so reconciliation can\n // preserve any shared layout DOM between sibling routes.\n mountComponent(instance);\n currentPathname = pathname;\n currentHref = href;\n return true;\n}\n\nfunction rerenderResolvedRoute(\n instance: ComponentInstance,\n pathname: string,\n href: string\n): boolean {\n currentPathname = pathname;\n currentHref = href;\n instance._enqueueRun?.();\n return true;\n}\n\nfunction resolveAppRouteRequest(\n app: AppRegistration,\n pathname: string,\n href: string,\n signal: AbortSignal\n): RouteRequestResult | Promise<RouteRequestResult> {\n if (app.routes) {\n const resolved = resolveRouteFromRoutes(pathname, app.routes);\n if (!resolved) {\n return null;\n }\n\n return {\n kind: 'render',\n handler: resolved.handler,\n params: resolved.params,\n };\n }\n\n return resolveRouteRequest(href, {\n manifest: app.manifest,\n auth: app.auth,\n signal,\n });\n}\n\ntype AppNavigationTarget = {\n app: AppRegistration;\n resolved: RouteRequestResult;\n};\n\nfunction resolveNavigationTargetsForApps(\n pathname: string,\n href: string,\n signal: AbortSignal\n): AppNavigationTarget[] | Promise<AppNavigationTarget[]> {\n const apps = [...registeredApps];\n\n if (apps.length === 1) {\n const app = apps[0]!;\n const resolved = resolveAppRouteRequest(app, pathname, href, signal);\n if (isPromiseLike<RouteRequestResult>(resolved)) {\n return Promise.resolve(resolved).then((next) => [\n {\n app,\n resolved: next,\n },\n ]);\n }\n\n return [\n {\n app,\n resolved,\n },\n ];\n }\n\n const syncTargets: AppNavigationTarget[] = [];\n const pendingTargets: Array<Promise<AppNavigationTarget>> = [];\n\n for (const app of apps) {\n const resolved = resolveAppRouteRequest(app, pathname, href, signal);\n if (isPromiseLike<RouteRequestResult>(resolved)) {\n pendingTargets.push(\n Promise.resolve(resolved).then((next) => ({ app, resolved: next }))\n );\n continue;\n }\n\n syncTargets.push({ app, resolved });\n }\n\n if (pendingTargets.length === 0) {\n return syncTargets;\n }\n\n return Promise.all([\n ...syncTargets.map((target) => Promise.resolve(target)),\n ...pendingTargets,\n ]);\n}\n\nfunction applyNavigationTargets(\n path: string,\n options: NavigateOptions,\n redirectState: NavigationRedirectState,\n pathname: string,\n href: string,\n targets: AppNavigationTarget[]\n): void {\n const previousPathname = currentPathname;\n\n for (const target of targets) {\n const resolved = target.resolved;\n if (!resolved || resolved.kind !== 'redirect') {\n continue;\n }\n\n const redirectTarget = parseTargetUrl(resolved.to);\n const redirectHref = `${redirectTarget.pathname}${redirectTarget.search}${redirectTarget.hash}`;\n if (redirectHref === href) {\n if (isDevelopmentEnvironment()) {\n logger.warn(\n `Navigation guard redirected to the same path: ${redirectHref}`\n );\n }\n return;\n }\n\n if (redirectState.visited.has(redirectHref)) {\n throw new Error(\n `[Askr] Navigation redirect cycle detected at ${redirectHref}.`\n );\n }\n if (redirectState.redirects >= MAX_NAVIGATION_REDIRECTS) {\n throw new Error(\n `[Askr] Navigation redirect limit exceeded (${MAX_NAVIGATION_REDIRECTS}).`\n );\n }\n\n redirectState.visited.add(redirectHref);\n redirectState.redirects++;\n navigateWithRedirectState(\n redirectHref,\n {\n history: getRedirectHistoryMode(resolved.replace),\n },\n redirectState\n );\n return;\n }\n\n const matchedTargets = targets.filter((target) => target.resolved !== null);\n if (matchedTargets.length === 0) {\n if (isDevelopmentEnvironment()) {\n logger.warn(`No route found for path: ${path}`);\n }\n return;\n }\n\n saveScrollPosition(currentHref);\n\n const historyMethod =\n getNavigationHistoryMode(options) === 'replace'\n ? 'replaceState'\n : 'pushState';\n window.history[historyMethod]({ path: href }, '', href);\n syncRegisteredRouteSnapshot();\n\n for (const target of matchedTargets) {\n const resolved = target.resolved!;\n if (resolved.kind === 'redirect') {\n continue;\n }\n\n if (pathname === target.app.pathname && isRenderResult(resolved)) {\n rerenderResolvedRoute(target.app.instance, pathname, href);\n syncAppRegistrationLocation(target.app, pathname, href);\n continue;\n }\n\n remountResolvedRoute(\n target.app.instance,\n resolved.kind === 'deny'\n ? createDeniedResolvedRoute(resolved.status)\n : {\n handler: resolved.handler,\n params: resolved.params,\n },\n pathname,\n href\n );\n syncAppRegistrationLocation(target.app, pathname, href);\n }\n\n if (pathname !== previousPathname) {\n applyNavigationScroll(\n options.scroll ?? scrollRestorationOptions.navigation\n );\n }\n}\n\n/** Register the current app instance (called by createSPA/hydrateSPA). */\nexport function registerAppInstance(\n instance: ComponentInstance,\n path: string,\n source: AppNavigationSource = {}\n): void {\n const existingIndex = registeredApps.findIndex(\n (app) => app.instance === instance\n );\n const registration: AppRegistration = {\n instance,\n pathname: path,\n href: getWindowHref(),\n ...source,\n };\n if (existingIndex >= 0) {\n registeredApps[existingIndex] = registration;\n } else {\n registeredApps.push(registration);\n }\n\n currentInstance = instance;\n currentPathname = path;\n currentHref = getWindowHref();\n syncRegisteredRouteSnapshot();\n // Lock further route registrations after the app has started — but allow tests to register routes.\n // Enforce only in production to avoid breaking test infra which registers routes dynamically.\n if (isProductionEnvironment()) {\n lockRouteRegistration();\n }\n}\n\nexport function unregisterAppInstance(instance: ComponentInstance): void {\n const existingIndex = registeredApps.findIndex(\n (app) => app.instance === instance\n );\n if (existingIndex >= 0) {\n registeredApps.splice(existingIndex, 1);\n }\n syncRegisteredRouteSnapshot();\n\n if (currentInstance !== instance) {\n return;\n }\n\n const nextApp =\n registeredApps.length > 0\n ? registeredApps[registeredApps.length - 1]!\n : null;\n currentInstance = nextApp?.instance ?? null;\n if (nextApp) {\n currentPathname = nextApp.pathname;\n currentHref = nextApp.href;\n syncRegisteredRouteSnapshot();\n return;\n }\n\n activeRouteRequestId += 1;\n activeRouteRequestController?.abort();\n activeRouteRequestController = null;\n currentPathname = '/';\n currentHref = '/';\n if (typeof window === 'undefined') {\n syncCurrentRouteSnapshot('/', '', '', []);\n }\n}\n\n/**\n * Navigate to a new path\n * Updates URL, resolves route, and re-mounts app with new handler\n */\nexport function navigate(path: string, options: NavigateOptions = {}): void {\n if (typeof window === 'undefined') {\n return;\n }\n\n const initialTarget = parseTargetUrl(path);\n navigateWithRedirectState(path, options, {\n redirects: 0,\n visited: new Set([\n `${initialTarget.pathname}${initialTarget.search}${initialTarget.hash}`,\n ]),\n });\n}\n\ntype NavigationRedirectState = {\n redirects: number;\n visited: Set<string>;\n};\n\nfunction navigateWithRedirectState(\n path: string,\n options: NavigateOptions,\n redirectState: NavigationRedirectState\n): void {\n if (typeof window === 'undefined') {\n // SSR context\n return;\n }\n\n const request = beginRouteRequest();\n\n const target = parseTargetUrl(path);\n const pathname = target.pathname;\n const href = `${target.pathname}${target.search}${target.hash}`;\n const resolvedTargets = resolveNavigationTargetsForApps(\n pathname,\n href,\n request.signal\n );\n\n if (isPromiseLike(resolvedTargets)) {\n void Promise.resolve(resolvedTargets).then(\n (targets) => {\n if (isStaleRouteRequest(request.id)) {\n return;\n }\n\n try {\n applyNavigationTargets(\n path,\n options,\n redirectState,\n pathname,\n href,\n targets\n );\n } catch (error) {\n logger.error('[Askr] navigation failed:', error);\n }\n },\n (error) => {\n logger.error('[Askr] navigation failed:', error);\n }\n );\n return;\n }\n\n applyNavigationTargets(\n path,\n options,\n redirectState,\n pathname,\n href,\n resolvedTargets\n );\n}\n\n/**\n * Handle browser back/forward buttons\n */\nfunction handlePopState(_event: PopStateEvent): void {\n const request = beginRouteRequest();\n const previousHref = currentHref;\n const pathname = window.location.pathname;\n const href = `${window.location.pathname}${window.location.search}${window.location.hash}`;\n\n saveScrollPosition(previousHref);\n\n if (registeredApps.length === 0) {\n return;\n }\n\n const applyResolved = (targets: AppNavigationTarget[]) => {\n if (isStaleRouteRequest(request.id)) {\n return;\n }\n\n const matchedTargets = targets.filter((target) => target.resolved !== null);\n if (matchedTargets.length === 0) {\n if (isDevelopmentEnvironment()) {\n logger.warn(`No route found for path: ${pathname}`);\n }\n return;\n }\n\n for (const target of matchedTargets) {\n const resolved = target.resolved!;\n if (resolved.kind !== 'redirect') {\n continue;\n }\n\n navigate(resolved.to, {\n history: getRedirectHistoryMode(resolved.replace),\n });\n return;\n }\n\n syncRegisteredRouteSnapshot();\n\n for (const target of matchedTargets) {\n const resolved = target.resolved!;\n if (pathname === target.app.pathname && isRenderResult(resolved)) {\n rerenderResolvedRoute(target.app.instance, pathname, href);\n syncAppRegistrationLocation(target.app, pathname, href);\n continue;\n }\n\n if (resolved.kind === 'redirect') {\n continue;\n }\n\n remountResolvedRoute(\n target.app.instance,\n resolved.kind === 'deny'\n ? createDeniedResolvedRoute(resolved.status)\n : {\n handler: resolved.handler,\n params: resolved.params,\n },\n pathname,\n href\n );\n syncAppRegistrationLocation(target.app, pathname, href);\n }\n\n applyHistoryScroll(href, _event.state);\n };\n\n const resolvedTargets = resolveNavigationTargetsForApps(\n pathname,\n href,\n request.signal\n );\n\n if (isPromiseLike<AppNavigationTarget[]>(resolvedTargets)) {\n void Promise.resolve(resolvedTargets).then(\n (next) => {\n try {\n applyResolved(next);\n } catch (error) {\n logger.error('[Askr] popstate navigation failed:', error);\n }\n },\n (error) => {\n logger.error('[Askr] popstate navigation failed:', error);\n }\n );\n return;\n }\n\n applyResolved(resolvedTargets);\n}\n\n/**\n * Setup popstate listener for browser navigation\n */\nexport function initializeNavigation(): void {\n if (typeof window === 'undefined' || navigationInitialized) {\n return;\n }\n\n navigationInitialized = true;\n window.addEventListener('popstate', handlePopState);\n}\n\n/**\n * Cleanup navigation listeners\n */\nexport function cleanupNavigation(): void {\n activeRouteRequestId += 1;\n activeRouteRequestController?.abort();\n activeRouteRequestController = null;\n\n if (typeof window === 'undefined' || !navigationInitialized) {\n return;\n }\n\n navigationInitialized = false;\n window.removeEventListener('popstate', handlePopState);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"navigate.js","names":[],"sources":["../../src/router/navigate.ts"],"sourcesContent":["/**\n * Client-side navigation with History API\n */\n\nimport { isPromiseLike } from '../common/promise';\nimport { logger } from '../dev/logger';\nimport { saveScrollPosition } from './navigation-scroll';\nimport {\n configureNavigationRegistryHost,\n getCurrentHref,\n hasRegisteredApps,\n parseTargetUrl,\n} from './navigation-registry';\nimport {\n applyNavigationTargets,\n applyPopStateNavigationTargets,\n beginRouteRequest,\n cancelRouteRequests,\n isStaleRouteRequest,\n resolveNavigationTargetsForApps,\n type AppNavigationTarget,\n type NavigateOptions,\n type NavigationRedirectState,\n} from './navigation-targets';\n\nexport { configureScrollRestoration } from './navigation-scroll';\nexport type {\n HistoryScrollBehavior,\n NavigationScrollBehavior,\n ScrollRestorationOptions,\n} from './navigation-scroll';\nexport {\n registerAppInstance,\n unregisterAppInstance,\n} from './navigation-registry';\nexport { updateRouteQuery } from './route-query';\nexport type {\n RouteQueryParamInput,\n RouteQueryParamValue,\n RouteQueryUpdater,\n RouteQueryUpdates,\n UpdateRouteQueryOptions,\n} from './route-query';\nexport type { NavigateOptions };\n\nlet navigationInitialized = false;\n\nconfigureNavigationRegistryHost({\n cancelRouteRequests,\n});\n\nexport function navigate(path: string, options: NavigateOptions = {}): void {\n if (typeof window === 'undefined') {\n return;\n }\n\n const initialTarget = parseTargetUrl(path);\n navigateWithRedirectState(path, options, {\n redirects: 0,\n visited: new Set([\n `${initialTarget.pathname}${initialTarget.search}${initialTarget.hash}`,\n ]),\n });\n}\n\nfunction navigateWithRedirectState(\n path: string,\n options: NavigateOptions,\n redirectState: NavigationRedirectState\n): void {\n if (typeof window === 'undefined') {\n return;\n }\n\n const request = beginRouteRequest();\n\n const target = parseTargetUrl(path);\n const pathname = target.pathname;\n const href = `${target.pathname}${target.search}${target.hash}`;\n const resolvedTargets = resolveNavigationTargetsForApps(\n pathname,\n href,\n request.signal\n );\n\n if (isPromiseLike(resolvedTargets)) {\n void Promise.resolve(resolvedTargets).then(\n (targets) => {\n if (isStaleRouteRequest(request.id)) {\n return;\n }\n\n try {\n applyNavigationTargets(\n path,\n options,\n redirectState,\n pathname,\n href,\n targets,\n navigateWithRedirectState\n );\n } catch (error) {\n logger.error('[Askr] navigation failed:', error);\n }\n },\n (error) => {\n logger.error('[Askr] navigation failed:', error);\n }\n );\n return;\n }\n\n applyNavigationTargets(\n path,\n options,\n redirectState,\n pathname,\n href,\n resolvedTargets,\n navigateWithRedirectState\n );\n}\n\nfunction handlePopState(event: PopStateEvent): void {\n const request = beginRouteRequest();\n const previousHref = getCurrentHref();\n const pathname = window.location.pathname;\n const href = `${window.location.pathname}${window.location.search}${window.location.hash}`;\n\n saveScrollPosition(previousHref);\n\n if (!hasRegisteredApps()) {\n return;\n }\n\n const applyResolved = (targets: AppNavigationTarget[]) => {\n try {\n applyPopStateNavigationTargets(\n request.id,\n pathname,\n href,\n event.state,\n targets,\n navigate\n );\n } catch (error) {\n logger.error('[Askr] popstate navigation failed:', error);\n }\n };\n\n const resolvedTargets = resolveNavigationTargetsForApps(\n pathname,\n href,\n request.signal\n );\n\n if (isPromiseLike<AppNavigationTarget[]>(resolvedTargets)) {\n void Promise.resolve(resolvedTargets).then(\n (next) => {\n applyResolved(next);\n },\n (error) => {\n logger.error('[Askr] popstate navigation failed:', error);\n }\n );\n return;\n }\n\n applyResolved(resolvedTargets);\n}\n\nexport function initializeNavigation(): void {\n if (typeof window === 'undefined' || navigationInitialized) {\n return;\n }\n\n navigationInitialized = true;\n window.addEventListener('popstate', handlePopState);\n}\n\nexport function cleanupNavigation(): void {\n cancelRouteRequests();\n\n if (typeof window === 'undefined' || !navigationInitialized) {\n return;\n }\n\n navigationInitialized = false;\n window.removeEventListener('popstate', handlePopState);\n}\n"],"mappings":";;;;;;;;;;AA6CA,IAAI,wBAAwB;AAE5B,gCAAgC,EAC9B,oBACF,CAAC;AAED,SAAgB,SAAS,MAAc,UAA2B,CAAC,GAAS;CAC1E,IAAI,OAAO,WAAW,aACpB;CAGF,MAAM,gBAAgB,eAAe,IAAI;CACzC,0BAA0B,MAAM,SAAS;EACvC,WAAW;EACX,yBAAS,IAAI,IAAI,CACf,GAAG,cAAc,WAAW,cAAc,SAAS,cAAc,MACnE,CAAC;CACH,CAAC;AACH;AAEA,SAAS,0BACP,MACA,SACA,eACM;CACN,IAAI,OAAO,WAAW,aACpB;CAGF,MAAM,UAAU,kBAAkB;CAElC,MAAM,SAAS,eAAe,IAAI;CAClC,MAAM,WAAW,OAAO;CACxB,MAAM,OAAO,GAAG,OAAO,WAAW,OAAO,SAAS,OAAO;CACzD,MAAM,kBAAkB,gCACtB,UACA,MACA,QAAQ,MACV;CAEA,IAAI,cAAc,eAAe,GAAG;EAClC,AAAK,QAAQ,QAAQ,eAAe,CAAC,CAAC,MACnC,YAAY;GACX,IAAI,oBAAoB,QAAQ,EAAE,GAChC;GAGF,IAAI;IACF,uBACE,MACA,SACA,eACA,UACA,MACA,SACA,yBACF;GACF,SAAS,OAAO;IACd,OAAO,MAAM,6BAA6B,KAAK;GACjD;EACF,IACC,UAAU;GACT,OAAO,MAAM,6BAA6B,KAAK;EACjD,CACF;EACA;CACF;CAEA,uBACE,MACA,SACA,eACA,UACA,MACA,iBACA,yBACF;AACF;AAEA,SAAS,eAAe,OAA4B;CAClD,MAAM,UAAU,kBAAkB;CAClC,MAAM,eAAe,eAAe;CACpC,MAAM,WAAW,OAAO,SAAS;CACjC,MAAM,OAAO,GAAG,OAAO,SAAS,WAAW,OAAO,SAAS,SAAS,OAAO,SAAS;CAEpF,mBAAmB,YAAY;CAE/B,IAAI,CAAC,kBAAkB,GACrB;CAGF,MAAM,iBAAiB,YAAmC;EACxD,IAAI;GACF,+BACE,QAAQ,IACR,UACA,MACA,MAAM,OACN,SACA,QACF;EACF,SAAS,OAAO;GACd,OAAO,MAAM,sCAAsC,KAAK;EAC1D;CACF;CAEA,MAAM,kBAAkB,gCACtB,UACA,MACA,QAAQ,MACV;CAEA,IAAI,cAAqC,eAAe,GAAG;EACzD,AAAK,QAAQ,QAAQ,eAAe,CAAC,CAAC,MACnC,SAAS;GACR,cAAc,IAAI;EACpB,IACC,UAAU;GACT,OAAO,MAAM,sCAAsC,KAAK;EAC1D,CACF;EACA;CACF;CAEA,cAAc,eAAe;AAC/B;AAEA,SAAgB,uBAA6B;CAC3C,IAAI,OAAO,WAAW,eAAe,uBACnC;CAGF,wBAAwB;CACxB,OAAO,iBAAiB,YAAY,cAAc;AACpD"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ComponentInstance } from "../runtime/component-internal.js";
|
|
2
|
+
import { Route, RouteAuthOptions, RouteManifest } from "../common/router.js";
|
|
3
|
+
|
|
4
|
+
//#region src/router/navigation-registry.d.ts
|
|
5
|
+
type AppNavigationSource = {
|
|
6
|
+
manifest?: RouteManifest;
|
|
7
|
+
routes?: readonly Route[];
|
|
8
|
+
auth?: RouteAuthOptions;
|
|
9
|
+
};
|
|
10
|
+
type AppRegistration = AppNavigationSource & {
|
|
11
|
+
instance: ComponentInstance;
|
|
12
|
+
pathname: string;
|
|
13
|
+
href: string;
|
|
14
|
+
};
|
|
15
|
+
type NavigationRegistryHost = {
|
|
16
|
+
cancelRouteRequests(): void;
|
|
17
|
+
};
|
|
18
|
+
declare function configureNavigationRegistryHost(host: NavigationRegistryHost): void;
|
|
19
|
+
declare function getCurrentPathname(): string;
|
|
20
|
+
declare function getCurrentHref(): string;
|
|
21
|
+
declare function setCurrentRouteLocation(pathname: string, href: string): void;
|
|
22
|
+
declare function getWindowHref(): string;
|
|
23
|
+
declare function parseTargetUrl(path: string): URL;
|
|
24
|
+
declare function getRegisteredAppsSnapshot(): AppRegistration[];
|
|
25
|
+
declare function hasRegisteredApps(): boolean;
|
|
26
|
+
declare function syncAppRegistrationLocation(app: AppRegistration, pathname: string, href: string): void;
|
|
27
|
+
declare function syncRegisteredRouteSnapshot(): void;
|
|
28
|
+
declare function registerAppInstance(instance: ComponentInstance, path: string, source?: AppNavigationSource): void;
|
|
29
|
+
declare function unregisterAppInstance(instance: ComponentInstance): void;
|
|
30
|
+
//#endregion
|
|
31
|
+
export { AppNavigationSource, AppRegistration };
|
|
32
|
+
//# sourceMappingURL=navigation-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation-registry.d.ts","names":[],"sources":["../../src/router/navigation-registry.ts"],"mappings":";;;;KASY,mBAAA;EACV,QAAA,GAAW,aAAA;EACX,MAAA,YAAkB,KAAA;EAClB,IAAA,GAAO,gBAAA;AAAA;AAAA,KAGG,eAAA,GAAkB,mBAAA;EAC5B,QAAA,EAAU,iBAAiB;EAC3B,QAAA;EACA,IAAA;AAAA;AAAA,KAGG,sBAAA;EACH,mBAAmB;AAAA;AAAA,iBAUL,+BAAA,CACd,IAA4B,EAAtB,sBAAsB;AAAA,iBAKd,kBAAA;AAAA,iBAIA,cAAA;AAAA,iBAIA,uBAAA,CAAwB,QAAA,UAAkB,IAAY;AAAA,iBAKtD,aAAA;AAAA,iBAQA,cAAA,CAAe,IAAA,WAAe,GAAG;AAAA,iBAiBjC,yBAAA,IAA6B,eAAe;AAAA,iBAI5C,iBAAA;AAAA,iBAIA,2BAAA,CACd,GAAA,EAAK,eAAe,EACpB,QAAA,UACA,IAAA;AAAA,iBA+Bc,2BAAA;AAAA,iBAcA,mBAAA,CACd,QAAA,EAAU,iBAAA,EACV,IAAA,UACA,MAAA,GAAQ,mBAAwB;AAAA,iBA0BlB,qBAAA,CAAsB,QAA2B,EAAjB,iBAAiB"}
|