@rangojs/router 0.0.0-experimental.14 → 0.0.0-experimental.141
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/AGENTS.md +17 -0
- package/README.md +432 -7
- package/dist/bin/rango.js +2073 -213
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +7258 -2714
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +140 -67
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +329 -0
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +487 -0
- package/skills/caching/SKILL.md +357 -25
- package/skills/comparison/SKILL.md +50 -0
- package/skills/comparison/agents/openai.yaml +4 -0
- package/skills/comparison/references/framework-comparison.md +837 -0
- package/skills/composability/SKILL.md +246 -0
- package/skills/css/SKILL.md +76 -0
- package/skills/debug-manifest/SKILL.md +16 -10
- package/skills/document-cache/SKILL.md +87 -62
- package/skills/fonts/SKILL.md +6 -4
- package/skills/handler-use/SKILL.md +364 -0
- package/skills/hooks/SKILL.md +557 -79
- package/skills/host-router/SKILL.md +320 -0
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +207 -15
- package/skills/layout/SKILL.md +146 -6
- package/skills/links/SKILL.md +304 -25
- package/skills/loader/SKILL.md +616 -54
- package/skills/middleware/SKILL.md +217 -37
- package/skills/migrate-nextjs/SKILL.md +611 -0
- package/skills/migrate-react-router/SKILL.md +927 -0
- package/skills/mime-routes/SKILL.md +42 -11
- package/skills/observability/SKILL.md +194 -0
- package/skills/parallel/SKILL.md +284 -3
- package/skills/ppr/SKILL.md +293 -0
- package/skills/prerender/SKILL.md +437 -52
- package/skills/rango/SKILL.md +369 -22
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +263 -121
- package/skills/route/SKILL.md +350 -21
- package/skills/router-setup/SKILL.md +246 -33
- package/skills/scripts/SKILL.md +179 -0
- package/skills/server-actions/SKILL.md +775 -0
- package/skills/shell-manifest/SKILL.md +185 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/tailwind/SKILL.md +27 -3
- package/skills/testing/SKILL.md +126 -222
- package/skills/testing/bindings.md +103 -0
- package/skills/testing/cache-prerender.md +127 -0
- package/skills/testing/client-components.md +124 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +91 -0
- package/skills/testing/handles.md +131 -0
- package/skills/testing/loader.md +128 -0
- package/skills/testing/middleware.md +99 -0
- package/skills/testing/render-handler.md +122 -0
- package/skills/testing/response-routes.md +95 -0
- package/skills/testing/reverse-and-types.md +85 -0
- package/skills/testing/server-actions.md +107 -0
- package/skills/testing/server-tree.md +128 -0
- package/skills/testing/setup.md +123 -0
- package/skills/theme/SKILL.md +9 -8
- package/skills/typesafety/SKILL.md +532 -103
- package/skills/use-cache/SKILL.md +367 -0
- package/skills/vercel/SKILL.md +128 -0
- package/skills/view-transitions/SKILL.md +337 -0
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +116 -0
- package/src/__internal.ts +77 -44
- package/src/bin/rango.ts +312 -15
- package/src/browser/action-coordinator.ts +114 -0
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +39 -0
- package/src/browser/app-version.ts +14 -0
- package/src/browser/connection-warmup.ts +134 -0
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +293 -202
- package/src/browser/history-state.ts +101 -0
- package/src/browser/index.ts +3 -3
- package/src/browser/intercept-utils.ts +52 -0
- package/src/browser/invalidate-client-cache.ts +52 -0
- package/src/browser/link-interceptor.ts +24 -4
- package/src/browser/logging.ts +11 -0
- package/src/browser/merge-segment-loaders.ts +20 -12
- package/src/browser/navigation-bridge.ts +385 -576
- package/src/browser/navigation-client.ts +245 -75
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +184 -118
- package/src/browser/navigation-transaction.ts +247 -0
- package/src/browser/network-error-handler.ts +88 -0
- package/src/browser/partial-update.ts +412 -364
- package/src/browser/prefetch/cache.ts +359 -0
- package/src/browser/prefetch/fetch.ts +452 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +48 -0
- package/src/browser/prefetch/queue.ts +209 -0
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +194 -0
- package/src/browser/react/Link.tsx +275 -68
- package/src/browser/react/NavigationProvider.tsx +265 -109
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/context.ts +11 -0
- package/src/browser/react/filter-segment-order.ts +70 -0
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +272 -60
- package/src/browser/react/location-state.ts +90 -20
- package/src/browser/react/mount-context.ts +6 -1
- package/src/browser/react/nonce-context.ts +23 -0
- package/src/browser/react/shallow-equal.ts +27 -0
- package/src/browser/react/use-action.ts +35 -66
- package/src/browser/react/use-handle.ts +39 -126
- package/src/browser/react/use-href.tsx +8 -1
- package/src/browser/react/use-link-status.ts +39 -13
- package/src/browser/react/use-navigation.ts +53 -69
- package/src/browser/react/use-params.ts +75 -0
- package/src/browser/react/use-pathname.ts +47 -0
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +98 -0
- package/src/browser/react/use-search-params.ts +51 -0
- package/src/browser/react/use-segments.ts +72 -99
- package/src/browser/response-adapter.ts +164 -0
- package/src/browser/rsc-router.tsx +300 -72
- package/src/browser/scroll-restoration.ts +138 -50
- package/src/browser/segment-reconciler.ts +243 -0
- package/src/browser/segment-structure-assert.ts +17 -1
- package/src/browser/server-action-bridge.ts +668 -613
- package/src/browser/types.ts +223 -51
- package/src/browser/validate-redirect-origin.ts +56 -0
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +252 -161
- package/src/build/generate-route-types.ts +41 -1038
- package/src/build/index.ts +12 -7
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +225 -42
- package/src/build/route-types/ast-helpers.ts +25 -0
- package/src/build/route-types/ast-route-extraction.ts +105 -0
- package/src/build/route-types/codegen.ts +113 -0
- package/src/build/route-types/include-resolution.ts +812 -0
- package/src/build/route-types/param-extraction.ts +51 -0
- package/src/build/route-types/per-module-writer.ts +144 -0
- package/src/build/route-types/router-processing.ts +695 -0
- package/src/build/route-types/scan-filter.ts +85 -0
- package/src/build/route-types/source-scan.ts +216 -0
- package/src/build/runtime-discovery.ts +223 -0
- package/src/cache/background-task.ts +34 -0
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-key-utils.ts +60 -0
- package/src/cache/cache-policy.ts +199 -0
- package/src/cache/cache-runtime.ts +525 -0
- package/src/cache/cache-scope.ts +298 -332
- package/src/cache/cache-tag.ts +103 -0
- package/src/cache/cf/cf-base64.ts +33 -0
- package/src/cache/cf/cf-cache-constants.ts +127 -0
- package/src/cache/cf/cf-cache-store.ts +2508 -158
- package/src/cache/cf/cf-cache-types.ts +349 -0
- package/src/cache/cf/cf-kv-utils.ts +46 -0
- package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
- package/src/cache/cf/index.ts +17 -17
- package/src/cache/document-cache.ts +199 -92
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +111 -0
- package/src/cache/index.ts +24 -35
- package/src/cache/memory-segment-store.ts +363 -30
- package/src/cache/profile-registry.ts +88 -0
- package/src/cache/read-through-swr.ts +178 -0
- package/src/cache/segment-codec.ts +248 -0
- package/src/cache/shell-snapshot.ts +368 -0
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/taint.ts +153 -0
- package/src/cache/types.ts +222 -211
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +1113 -0
- package/src/client.rsc.tsx +43 -21
- package/src/client.tsx +131 -347
- package/src/cloudflare/index.ts +11 -0
- package/src/cloudflare/tracing.ts +109 -0
- package/src/component-utils.ts +23 -4
- package/src/components/DefaultDocument.tsx +13 -3
- package/src/context-var.ts +168 -0
- package/src/debug.ts +19 -9
- package/src/decode-loader-results.ts +52 -0
- package/src/defer.ts +185 -0
- package/src/deps/ssr.ts +0 -1
- package/src/encode-kv.ts +49 -0
- package/src/errors.ts +106 -10
- package/src/escape-script.ts +52 -0
- package/src/handle.ts +110 -35
- package/src/handles/MetaTags.tsx +83 -59
- package/src/handles/Scripts.tsx +183 -0
- package/src/handles/breadcrumbs.ts +93 -0
- package/src/handles/deferred-resolution.ts +127 -0
- package/src/handles/is-thenable.ts +18 -0
- package/src/handles/meta.ts +44 -53
- package/src/handles/script.ts +244 -0
- package/src/host/cookie-handler.ts +20 -65
- package/src/host/errors.ts +21 -30
- package/src/host/index.ts +13 -9
- package/src/host/pattern-matcher.ts +50 -79
- package/src/host/router.ts +151 -121
- package/src/host/testing.ts +45 -32
- package/src/host/types.ts +52 -11
- package/src/host/utils.ts +2 -2
- package/src/href-client.ts +192 -57
- package/src/index.rsc.ts +173 -35
- package/src/index.ts +241 -73
- package/src/internal-debug.ts +9 -2
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +31 -99
- package/src/loader.ts +30 -12
- package/src/missing-id-error.ts +68 -0
- package/src/outlet-context.ts +1 -1
- package/src/outlet-provider.tsx +41 -0
- package/src/prerender/param-hash.ts +16 -14
- package/src/prerender/store.ts +121 -21
- package/src/prerender.ts +460 -26
- package/src/redirect-origin.ts +100 -0
- package/src/regex-escape.ts +8 -0
- package/src/render-error-thrower.tsx +20 -0
- package/src/response-utils.ts +62 -0
- package/src/reverse.ts +198 -128
- package/src/root-error-boundary.tsx +42 -48
- package/src/route-content-wrapper.tsx +22 -77
- package/src/route-definition/dsl-helpers.ts +1116 -0
- package/src/route-definition/helper-factories.ts +88 -0
- package/src/route-definition/helpers-types.ts +505 -0
- package/src/route-definition/index.ts +54 -0
- package/src/route-definition/redirect.ts +134 -0
- package/src/route-definition/resolve-handler-use.ts +160 -0
- package/src/route-definition/use-item-types.ts +29 -0
- package/src/route-definition.ts +1 -1481
- package/src/route-map-builder.ts +82 -144
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +71 -45
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +263 -0
- package/src/router/debug-manifest.ts +72 -0
- package/src/router/error-handling.ts +54 -27
- package/src/router/find-match.ts +245 -0
- package/src/router/handler-context.ts +377 -125
- package/src/router/instrument.ts +350 -0
- package/src/router/intercept-resolution.ts +59 -28
- package/src/router/lazy-includes.ts +254 -0
- package/src/router/loader-resolution.ts +421 -157
- package/src/router/logging.ts +106 -6
- package/src/router/manifest.ts +131 -57
- package/src/router/match-api.ts +167 -246
- package/src/router/match-context.ts +4 -24
- package/src/router/match-handlers.ts +440 -0
- package/src/router/match-middleware/background-revalidation.ts +117 -93
- package/src/router/match-middleware/cache-lookup.ts +297 -150
- package/src/router/match-middleware/cache-store.ts +123 -51
- package/src/router/match-middleware/intercept-resolution.ts +44 -43
- package/src/router/match-middleware/segment-resolution.ts +64 -22
- package/src/router/match-pipelines.ts +11 -87
- package/src/router/match-result.ts +121 -50
- package/src/router/metrics.ts +219 -28
- package/src/router/middleware-types.ts +93 -0
- package/src/router/middleware.ts +505 -441
- package/src/router/navigation-snapshot.ts +133 -0
- package/src/router/params-util.ts +23 -0
- package/src/router/parse-pattern.ts +115 -0
- package/src/router/pattern-matching.ts +311 -142
- package/src/router/prefetch-cache-ttl.ts +51 -0
- package/src/router/prefetch-limits.ts +37 -0
- package/src/router/prerender-match.ts +547 -0
- package/src/router/preview-match.ts +102 -0
- package/src/router/request-classification.ts +278 -0
- package/src/router/revalidation.ts +203 -62
- package/src/router/route-snapshot.ts +246 -0
- package/src/router/router-context.ts +45 -48
- package/src/router/router-interfaces.ts +554 -0
- package/src/router/router-options.ts +779 -0
- package/src/router/router-registry.ts +21 -0
- package/src/router/segment-resolution/fresh.ts +772 -0
- package/src/router/segment-resolution/helpers.ts +348 -0
- package/src/router/segment-resolution/loader-cache.ts +250 -0
- package/src/router/segment-resolution/loader-mask.ts +44 -0
- package/src/router/segment-resolution/revalidation.ts +1331 -0
- package/src/router/segment-resolution/static-store.ts +81 -0
- package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
- package/src/router/segment-resolution/view-transition-default.ts +56 -0
- package/src/router/segment-resolution.ts +25 -1354
- package/src/router/segment-wrappers.ts +292 -0
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +75 -0
- package/src/router/telemetry-otel.ts +261 -0
- package/src/router/telemetry.ts +377 -0
- package/src/router/timeout.ts +128 -0
- package/src/router/tracing.ts +206 -0
- package/src/router/trie-matching.ts +240 -61
- package/src/router/types.ts +23 -70
- package/src/router/url-params.ts +57 -0
- package/src/router.ts +781 -2378
- package/src/rsc/full-payload.ts +70 -0
- package/src/rsc/handler-context.ts +46 -0
- package/src/rsc/handler.ts +905 -1142
- package/src/rsc/helpers.ts +275 -19
- package/src/rsc/index.ts +2 -25
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/loader-fetch.ts +305 -0
- package/src/rsc/manifest-init.ts +77 -0
- package/src/rsc/nonce.ts +14 -0
- package/src/rsc/origin-guard.ts +155 -0
- package/src/rsc/progressive-enhancement.ts +502 -0
- package/src/rsc/redirect-guard.ts +99 -0
- package/src/rsc/response-cache-serve.ts +238 -0
- package/src/rsc/response-error.ts +104 -0
- package/src/rsc/response-route-handler.ts +257 -0
- package/src/rsc/rsc-rendering.ts +527 -0
- package/src/rsc/runtime-warnings.ts +55 -0
- package/src/rsc/server-action.ts +522 -0
- package/src/rsc/shell-capture.ts +897 -0
- package/src/rsc/shell-serve.ts +124 -0
- package/src/rsc/ssr-setup.ts +144 -0
- package/src/rsc/transition-gate.ts +89 -0
- package/src/rsc/types.ts +95 -12
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +99 -82
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +149 -0
- package/src/segment-system.tsx +349 -134
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +459 -85
- package/src/server/cookie-parse.ts +32 -0
- package/src/server/cookie-store.ts +310 -0
- package/src/server/fetchable-loader-store.ts +11 -6
- package/src/server/handle-store.ts +123 -42
- package/src/server/loader-registry.ts +51 -100
- package/src/server/request-context.ts +848 -157
- package/src/server.ts +15 -8
- package/src/ssr/index.tsx +443 -135
- package/src/ssr/ssr-root.tsx +228 -0
- package/src/static-handler.ts +45 -18
- package/src/testing/cache-status.ts +162 -0
- package/src/testing/collect-handle.ts +46 -0
- package/src/testing/dispatch.ts +701 -0
- package/src/testing/dom.entry.ts +22 -0
- package/src/testing/e2e/fixture.ts +188 -0
- package/src/testing/e2e/index.ts +128 -0
- package/src/testing/e2e/matchers.ts +35 -0
- package/src/testing/e2e/page-helpers.ts +272 -0
- package/src/testing/e2e/parity.ts +387 -0
- package/src/testing/e2e/server.ts +195 -0
- package/src/testing/flight-matchers.ts +97 -0
- package/src/testing/flight-normalize.ts +11 -0
- package/src/testing/flight-runtime.d.ts +57 -0
- package/src/testing/flight-tree.ts +682 -0
- package/src/testing/flight.entry.ts +52 -0
- package/src/testing/flight.ts +257 -0
- package/src/testing/generated-routes.ts +199 -0
- package/src/testing/index.ts +105 -0
- package/src/testing/internal/context.ts +371 -0
- package/src/testing/internal/flight-client-globals.ts +30 -0
- package/src/testing/internal/seed-vars.ts +54 -0
- package/src/testing/render-handler.ts +357 -0
- package/src/testing/render-route.tsx +584 -0
- package/src/testing/run-loader.ts +385 -0
- package/src/testing/run-middleware.ts +205 -0
- package/src/testing/run-transition-when.ts +164 -0
- package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
- package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
- package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
- package/src/testing/vitest-stubs/version.ts +5 -0
- package/src/testing/vitest.ts +305 -0
- package/src/theme/ThemeProvider.tsx +76 -98
- package/src/theme/ThemeScript.tsx +12 -14
- package/src/theme/constants.ts +57 -15
- package/src/theme/index.ts +3 -20
- package/src/theme/theme-context.ts +5 -35
- package/src/theme/theme-script.ts +43 -39
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +123 -0
- package/src/types/cache-types.ts +207 -0
- package/src/types/error-types.ts +132 -0
- package/src/types/global-namespace.ts +113 -0
- package/src/types/handler-context.ts +839 -0
- package/src/types/index.ts +81 -0
- package/src/types/loader-types.ts +212 -0
- package/src/types/request-scope.ts +112 -0
- package/src/types/route-config.ts +138 -0
- package/src/types/route-entry.ts +114 -0
- package/src/types/segments.ts +271 -0
- package/src/types.ts +1 -1795
- package/src/urls/include-helper.ts +162 -0
- package/src/urls/include-provider.ts +71 -0
- package/src/urls/index.ts +44 -0
- package/src/urls/path-helper-types.ts +413 -0
- package/src/urls/path-helper.ts +280 -0
- package/src/urls/pattern-types.ts +160 -0
- package/src/urls/response-types.ts +109 -0
- package/src/urls/type-extraction.ts +316 -0
- package/src/urls/urls-function.ts +80 -0
- package/src/urls.ts +1 -1341
- package/src/use-loader.tsx +406 -141
- package/src/vercel/index.ts +11 -0
- package/src/vercel/tracing.ts +88 -0
- package/src/vite/debug.ts +185 -0
- package/src/vite/discovery/bundle-postprocess.ts +182 -0
- package/src/vite/discovery/discover-routers.ts +389 -0
- package/src/vite/discovery/discovery-errors.ts +255 -0
- package/src/vite/discovery/gate-state.ts +171 -0
- package/src/vite/discovery/prerender-collection.ts +467 -0
- package/src/vite/discovery/route-types-writer.ts +214 -0
- package/src/vite/discovery/self-gen-tracking.ts +73 -0
- package/src/vite/discovery/state.ts +161 -0
- package/src/vite/discovery/virtual-module-codegen.ts +183 -0
- package/src/vite/index.ts +23 -2255
- package/src/vite/inject-client-debug.ts +36 -0
- package/src/vite/plugin-types.ts +303 -0
- package/src/vite/plugins/cjs-to-esm.ts +90 -0
- package/src/vite/plugins/client-ref-dedup.ts +120 -0
- package/src/vite/plugins/client-ref-hashing.ts +118 -0
- package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
- package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
- package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +88 -110
- package/src/vite/{expose-id-utils.ts → plugins/expose-id-utils.ts} +89 -79
- package/src/vite/plugins/expose-ids/export-analysis.ts +363 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +130 -0
- package/src/vite/plugins/expose-ids/loader-transform.ts +64 -0
- package/src/vite/plugins/expose-ids/router-transform.ts +199 -0
- package/src/vite/plugins/expose-ids/types.ts +45 -0
- package/src/vite/plugins/expose-internal-ids.ts +805 -0
- package/src/vite/plugins/performance-tracks.ts +89 -0
- package/src/vite/plugins/refresh-cmd.ts +127 -0
- package/src/vite/plugins/use-cache-transform.ts +313 -0
- package/src/vite/plugins/vercel-output.ts +384 -0
- package/src/vite/plugins/version-injector.ts +94 -0
- package/src/vite/plugins/version-plugin.ts +263 -0
- package/src/vite/plugins/virtual-entries.ts +234 -0
- package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
- package/src/vite/rango.ts +560 -0
- package/src/vite/router-discovery.ts +1638 -0
- package/src/vite/{ast-handler-extract.ts → utils/ast-handler-extract.ts} +200 -37
- package/src/vite/utils/banner.ts +36 -0
- package/src/vite/utils/bundle-analysis.ts +132 -0
- package/src/vite/utils/client-chunks.ts +184 -0
- package/src/vite/utils/directive-prologue.ts +40 -0
- package/src/vite/utils/forward-user-plugins.ts +171 -0
- package/src/vite/utils/manifest-utils.ts +15 -0
- package/src/vite/utils/package-resolution.ts +89 -0
- package/src/vite/utils/prerender-utils.ts +249 -0
- package/src/vite/utils/shared-utils.ts +269 -0
- package/CLAUDE.md +0 -43
- package/dist/vite/index.named-routes.gen.ts +0 -103
- package/src/browser/lru-cache.ts +0 -69
- package/src/browser/react/use-client-cache.ts +0 -56
- package/src/browser/request-controller.ts +0 -164
- package/src/browser/shallow.ts +0 -35
- package/src/cache/memory-store.ts +0 -253
- package/src/handles/index.ts +0 -6
- package/src/href-context.ts +0 -33
- package/src/network-error-thrower.tsx +0 -21
- package/src/router.gen.ts +0 -6
- package/src/static-handler.gen.ts +0 -5
- package/src/urls.gen.ts +0 -8
- package/src/vite/expose-internal-ids.ts +0 -1167
- package/src/vite/package-resolution.ts +0 -125
- package/src/vite/virtual-entries.ts +0 -114
- /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
|
@@ -23,7 +23,7 @@ function ShopLayout() {
|
|
|
23
23
|
);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
export const urlpatterns = urls(({ path, layout, intercept, loader }) => [
|
|
26
|
+
export const urlpatterns = urls(({ path, layout, intercept, loader, loading }) => [
|
|
27
27
|
layout(<ShopLayout />, () => [
|
|
28
28
|
// Intercept product detail - shows modal during soft navigation
|
|
29
29
|
intercept(
|
|
@@ -45,11 +45,11 @@ export const urlpatterns = urls(({ path, layout, intercept, loader }) => [
|
|
|
45
45
|
|
|
46
46
|
## Navigation Behavior
|
|
47
47
|
|
|
48
|
-
| Navigation Type
|
|
49
|
-
|
|
48
|
+
| Navigation Type | What Renders |
|
|
49
|
+
| ------------------------------ | ---------------------------------------------------- |
|
|
50
50
|
| Click link `/shop/product/abc` | `<ProductModal />` in `@modal`, background preserved |
|
|
51
|
-
| Direct URL `/shop/product/abc` | Full `<ProductPage />` page
|
|
52
|
-
| Browser back
|
|
51
|
+
| Direct URL `/shop/product/abc` | Full `<ProductPage />` page |
|
|
52
|
+
| Browser back | Close modal, restore previous state |
|
|
53
53
|
|
|
54
54
|
## Intercept with Layout
|
|
55
55
|
|
|
@@ -68,18 +68,115 @@ intercept(
|
|
|
68
68
|
)
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
-
##
|
|
71
|
+
## Intercept Middleware
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
Intercepts support their own middleware chain via the use callback. The full chain for an intercept request is:
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
global mw (router.use) -> route mw (urls middleware()) -> intercept mw -> intercept handler -> intercept loaders
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
intercept(
|
|
81
|
+
"@modal",
|
|
82
|
+
"product",
|
|
83
|
+
<ProductModal />,
|
|
84
|
+
() => [
|
|
85
|
+
middleware(async (ctx, next) => {
|
|
86
|
+
// Runs only for this intercept, after global and route middleware
|
|
87
|
+
ctx.set("interceptSource", "modal");
|
|
88
|
+
await next();
|
|
89
|
+
}),
|
|
90
|
+
loader(ProductLoader),
|
|
91
|
+
]
|
|
92
|
+
)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The intercept handler can read context variables set by all upstream middleware layers (global, route, and intercept-specific).
|
|
96
|
+
|
|
97
|
+
Handler/layout `ctx.set()` data follows the same rule as elsewhere:
|
|
98
|
+
intercepts see data produced in the current render pass, but partial
|
|
99
|
+
action revalidation only recomputes segments that actually revalidate.
|
|
100
|
+
If an intercept depends on data established by an outer layout/handler,
|
|
101
|
+
revalidate that outer segment too or reload/guard the data inside the
|
|
102
|
+
intercept.
|
|
103
|
+
|
|
104
|
+
### Revalidation Contracts for Intercept Dependencies
|
|
105
|
+
|
|
106
|
+
Use named revalidation contracts on both the outer producer and the intercept
|
|
107
|
+
consumer when they share `ctx.set()` data:
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
import * as ProductActions from "./actions/product";
|
|
111
|
+
|
|
112
|
+
export const revalidateProductShell = (ctx) =>
|
|
113
|
+
ctx.isAction(ProductActions) || undefined;
|
|
114
|
+
|
|
115
|
+
layout(ProductLayout, () => [
|
|
116
|
+
revalidate(revalidateProductShell), // producer reruns
|
|
117
|
+
intercept("@modal", "product", <ProductModal />, () => [
|
|
118
|
+
revalidate(revalidateProductShell), // consumer reruns
|
|
119
|
+
loader(ProductLoader),
|
|
120
|
+
]),
|
|
121
|
+
]);
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Compose multiple contracts if the intercept depends on multiple upstream
|
|
125
|
+
domains.
|
|
126
|
+
|
|
127
|
+
Helper handoff style keeps intercept trees terse:
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
import { revalidate } from "@rangojs/router";
|
|
131
|
+
|
|
132
|
+
export const revalidateProduct = () => [
|
|
133
|
+
revalidate(revalidateProductShell),
|
|
134
|
+
];
|
|
135
|
+
|
|
136
|
+
layout(ProductLayout, () => [
|
|
137
|
+
revalidateProduct(),
|
|
138
|
+
intercept("@modal", "product", <ProductModal />, () => [
|
|
139
|
+
revalidateProduct(),
|
|
140
|
+
loader(ProductLoader),
|
|
141
|
+
]),
|
|
142
|
+
]);
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Conditional Intercept with the `when` config
|
|
146
|
+
|
|
147
|
+
Only intercept based on navigation context. `when` is the 4th argument
|
|
148
|
+
(an `InterceptConfig` object); the other use-items go in the 5th-argument
|
|
149
|
+
callback.
|
|
74
150
|
|
|
75
151
|
```typescript
|
|
76
152
|
intercept(
|
|
77
153
|
"@modal",
|
|
78
154
|
"product",
|
|
79
155
|
<ProductModal />,
|
|
156
|
+
// Only intercept when coming from a different section
|
|
157
|
+
{ when: ({ from }) => !from.pathname.startsWith("/shop/product/") },
|
|
158
|
+
() => [
|
|
159
|
+
loader(ProductLoader),
|
|
160
|
+
]
|
|
161
|
+
)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
`when` is a match-time selector receiving `{ from, to, params, segments, ... }`.
|
|
165
|
+
Pass an array of predicates for AND logic (all must return true). Omit `when`
|
|
166
|
+
entirely and the intercept always activates.
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
intercept(
|
|
170
|
+
"@modal",
|
|
171
|
+
"product",
|
|
172
|
+
<ProductModal />,
|
|
173
|
+
{
|
|
174
|
+
when: [
|
|
175
|
+
({ from }) => from.pathname.startsWith("/shop"),
|
|
176
|
+
({ params }) => params.slug !== "featured",
|
|
177
|
+
],
|
|
178
|
+
},
|
|
80
179
|
() => [
|
|
81
|
-
// Only intercept when coming from a different section
|
|
82
|
-
when(({ from }) => !from.pathname.startsWith("/shop/product/")),
|
|
83
180
|
loader(ProductLoader),
|
|
84
181
|
]
|
|
85
182
|
)
|
|
@@ -106,15 +203,15 @@ Use navigation to close:
|
|
|
106
203
|
|
|
107
204
|
```typescript
|
|
108
205
|
"use client";
|
|
109
|
-
import {
|
|
206
|
+
import { useRouter } from "@rangojs/router/client";
|
|
110
207
|
|
|
111
208
|
function ModalWrapper({ children }) {
|
|
112
|
-
const
|
|
209
|
+
const router = useRouter();
|
|
113
210
|
|
|
114
211
|
return (
|
|
115
|
-
<div className="modal-overlay" onClick={
|
|
212
|
+
<div className="modal-overlay" onClick={() => router.back()}>
|
|
116
213
|
<div className="modal" onClick={(e) => e.stopPropagation()}>
|
|
117
|
-
<button onClick={
|
|
214
|
+
<button onClick={() => router.back()}>Close</button>
|
|
118
215
|
{children}
|
|
119
216
|
</div>
|
|
120
217
|
</div>
|
|
@@ -122,6 +219,82 @@ function ModalWrapper({ children }) {
|
|
|
122
219
|
}
|
|
123
220
|
```
|
|
124
221
|
|
|
222
|
+
## Interaction with View Transitions
|
|
223
|
+
|
|
224
|
+
A layout that owns the `@modal` slot can also configure `transition()` for page
|
|
225
|
+
fades — opening a modal does **not** fire the layout's view transition. Rango
|
|
226
|
+
narrows the layout's `<ViewTransition>` wrap to the layout's default outlet
|
|
227
|
+
content, so `<ParallelOutlet />` (the slot where the modal mounts) is a sibling
|
|
228
|
+
of the wrap, not inside its subtree. Form actions submitted from inside an open
|
|
229
|
+
modal also commit without firing the underlying layout's transition, and the
|
|
230
|
+
modal subtree identity is preserved across revalidation (no remount,
|
|
231
|
+
`useActionState` survives). Closing the modal restores the page without a
|
|
232
|
+
stray transition.
|
|
233
|
+
|
|
234
|
+
For a modal-only morph (e.g. when intercepted URLs change while the modal
|
|
235
|
+
stays open), use an element-level React `<ViewTransition>` inside the modal
|
|
236
|
+
component — `transition()` accepted on `intercept()` via the DSL is not
|
|
237
|
+
applied to slot rendering today.
|
|
238
|
+
|
|
239
|
+
Caveat: route-level `transition()` wraps the route component itself, so a
|
|
240
|
+
`<ParallelOutlet />` rendered directly inside that route component would still
|
|
241
|
+
be inside the route's VT subtree. Mount the slot in a layout instead when you
|
|
242
|
+
combine intercept modals with route-level transitions.
|
|
243
|
+
|
|
244
|
+
See [skills/view-transitions](../view-transitions/SKILL.md) for the full
|
|
245
|
+
contract and direction-aware examples.
|
|
246
|
+
|
|
247
|
+
## Interaction with Prerender
|
|
248
|
+
|
|
249
|
+
When the target route of an intercept uses `Prerender`, the intercept handler is
|
|
250
|
+
also resolved at build time and stored alongside the main pre-rendered segments.
|
|
251
|
+
This means intercept navigations to pre-rendered routes are served from the
|
|
252
|
+
prerender store without executing handler code at runtime.
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
// The detail route is pre-rendered
|
|
256
|
+
export const ProductDetail = Prerender(
|
|
257
|
+
async () => [{ slug: "shoes" }, { slug: "jacket" }],
|
|
258
|
+
async (ctx) => <ProductPage slug={ctx.params.slug} />,
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
// urls.tsx
|
|
262
|
+
layout(ShopLayout, () => [
|
|
263
|
+
path("/:slug", ProductDetail, { name: "detail" }, () => [
|
|
264
|
+
loader(ProductLoader),
|
|
265
|
+
]),
|
|
266
|
+
|
|
267
|
+
// This intercept is also pre-rendered at build time
|
|
268
|
+
intercept(
|
|
269
|
+
"@modal",
|
|
270
|
+
".detail",
|
|
271
|
+
<ProductModal />,
|
|
272
|
+
{ when: ({ from }) => from.pathname.startsWith("/shop") },
|
|
273
|
+
() => [loader(ProductLoader)],
|
|
274
|
+
),
|
|
275
|
+
])
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Build-time behavior:
|
|
279
|
+
|
|
280
|
+
- The intercept handler (`<ProductModal />`) is resolved with BuildContext
|
|
281
|
+
- Result is stored under the key `"detail/paramHash/i"` (intercept variant)
|
|
282
|
+
- `when` config conditions are skipped at build time (all intercepts pre-rendered unconditionally)
|
|
283
|
+
- `when` is still evaluated at runtime by the intercept-resolution middleware
|
|
284
|
+
|
|
285
|
+
Runtime behavior:
|
|
286
|
+
|
|
287
|
+
- Intercept navigation: prerender store serves the `/i` variant (frozen handler + fresh loaders)
|
|
288
|
+
- Direct navigation: prerender store serves the main variant (full page)
|
|
289
|
+
- If no intercept prerender entry exists, falls through to live intercept resolution
|
|
290
|
+
|
|
291
|
+
Loaders inside the intercept always run fresh at request time, same as regular
|
|
292
|
+
pre-rendered routes.
|
|
293
|
+
|
|
294
|
+
During action-driven partial revalidation, this same partial rule applies:
|
|
295
|
+
refreshing the intercept does not implicitly rebuild non-revalidated outer
|
|
296
|
+
segments.
|
|
297
|
+
|
|
125
298
|
## Complete Example
|
|
126
299
|
|
|
127
300
|
```typescript
|
|
@@ -158,7 +331,6 @@ export const shopPatterns = urls(({
|
|
|
158
331
|
intercept,
|
|
159
332
|
loader,
|
|
160
333
|
loading,
|
|
161
|
-
when,
|
|
162
334
|
}) => [
|
|
163
335
|
layout(<ShopLayout />, () => [
|
|
164
336
|
parallel({
|
|
@@ -170,8 +342,8 @@ export const shopPatterns = urls(({
|
|
|
170
342
|
"@modal",
|
|
171
343
|
"product", // Route name (without prefix)
|
|
172
344
|
<ProductModalContent />,
|
|
345
|
+
{ when: ({ from }) => !from.pathname.startsWith("/shop/product/") },
|
|
173
346
|
() => [
|
|
174
|
-
when(({ from }) => !from.pathname.startsWith("/shop/product/")),
|
|
175
347
|
layout(<ModalWrapper />),
|
|
176
348
|
loading(<ProductModalSkeleton />),
|
|
177
349
|
loader(ProductLoader, () => [cache()]),
|
|
@@ -188,3 +360,23 @@ export const shopPatterns = urls(({
|
|
|
188
360
|
]),
|
|
189
361
|
]);
|
|
190
362
|
```
|
|
363
|
+
|
|
364
|
+
## Handler-attached `.use`
|
|
365
|
+
|
|
366
|
+
Intercept handlers can carry their own middleware, loaders, loading state, error/notFound boundaries, and even nested `layout`/`route` defaults via `.use` — useful for self-contained modal components that travel with their own data and chrome. (Conditional activation is set via the `when` config on the mount-site `intercept()` call, not inside `.use`.)
|
|
367
|
+
|
|
368
|
+
```typescript
|
|
369
|
+
const QuickViewModal: Handler = async (ctx) => {
|
|
370
|
+
const product = await ctx.use(ProductLoader);
|
|
371
|
+
return <QuickView product={product} />;
|
|
372
|
+
};
|
|
373
|
+
QuickViewModal.use = () => [
|
|
374
|
+
loader(ProductLoader),
|
|
375
|
+
loading(<QuickViewSkeleton />),
|
|
376
|
+
layout(<ModalChrome />),
|
|
377
|
+
];
|
|
378
|
+
|
|
379
|
+
intercept("@modal", "product", QuickViewModal);
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
Explicit `use()` at the mount site merges with `handler.use` (handler defaults first, explicit second). See [skills/handler-use](../handler-use/SKILL.md) for merge order and the per-mount-site allowed-types table.
|
package/skills/layout/SKILL.md
CHANGED
|
@@ -45,9 +45,7 @@ layout(<ShopLayout />, () => [
|
|
|
45
45
|
### Component Function
|
|
46
46
|
|
|
47
47
|
```typescript
|
|
48
|
-
layout(ShopLayout, () => [
|
|
49
|
-
path("/shop", ShopIndex, { name: "shop" }),
|
|
50
|
-
])
|
|
48
|
+
layout(ShopLayout, () => [path("/shop", ShopIndex, { name: "shop" })]);
|
|
51
49
|
```
|
|
52
50
|
|
|
53
51
|
### Handler with Context
|
|
@@ -117,6 +115,8 @@ function ShopLayout() {
|
|
|
117
115
|
}
|
|
118
116
|
```
|
|
119
117
|
|
|
118
|
+
A layout's `transition()` config wraps the content that flows through `<Outlet />` — not the layout chrome itself, and not sibling `<ParallelOutlet />` slots. Stacking transitions across nested layouts collapses around the deepest default outlet content. See [skills/view-transitions](../view-transitions/SKILL.md) for the full wrap rules and intercept-modal interaction.
|
|
119
|
+
|
|
120
120
|
## Named Outlets
|
|
121
121
|
|
|
122
122
|
For parallel routes, use named outlets:
|
|
@@ -141,9 +141,69 @@ function DashboardLayout() {
|
|
|
141
141
|
}
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
+
## Orphan Layout (inside route)
|
|
145
|
+
|
|
146
|
+
A layout as a child of `path()` wraps the route content and can read
|
|
147
|
+
data set by the route handler via `ctx.get()`. The handler always
|
|
148
|
+
executes before its children.
|
|
149
|
+
|
|
150
|
+
This is the recommended way to pass handler data downward, and it is
|
|
151
|
+
safe under partial action revalidation with zero configuration: orphan
|
|
152
|
+
layouts (and their parallels) belong to the route entry, and on an
|
|
153
|
+
action the whole entry re-runs together by default — route segment,
|
|
154
|
+
loaders, and `belongsToRoute` children all seed revalidate-true, with
|
|
155
|
+
handler-first ordering preserved. Producer and consumer cannot desync
|
|
156
|
+
unless you narrow one side with a predicate that returns a hard `false`
|
|
157
|
+
(then put the same contract on both — see "Revalidation Contracts").
|
|
158
|
+
|
|
159
|
+
Data from an **outer** handler or layout entry is the opposite case:
|
|
160
|
+
outer entries do not revalidate on actions by default (parent-chain
|
|
161
|
+
skip). If an orphan layout depends on data established above its own
|
|
162
|
+
route entry, that outer segment must share a revalidation contract, or
|
|
163
|
+
the orphan must guard/reload the data independently. See `/rango` →
|
|
164
|
+
"Passing data down the tree" for the full safest-first ladder.
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
import { Outlet, ParallelOutlet } from "@rangojs/router/client";
|
|
168
|
+
|
|
169
|
+
urls(({ path, layout, parallel }) => [
|
|
170
|
+
path("/product/:slug", (ctx) => {
|
|
171
|
+
const product = await fetchProduct(ctx.params.slug);
|
|
172
|
+
ctx.set("product", product);
|
|
173
|
+
return <ProductPage product={product} />;
|
|
174
|
+
}, { name: "product" }, () => [
|
|
175
|
+
layout((ctx) => {
|
|
176
|
+
const product = ctx.get("product");
|
|
177
|
+
return (
|
|
178
|
+
<div>
|
|
179
|
+
<Breadcrumb name={product?.name} />
|
|
180
|
+
<Outlet />
|
|
181
|
+
<ParallelOutlet name="@related" />
|
|
182
|
+
</div>
|
|
183
|
+
);
|
|
184
|
+
}, () => [
|
|
185
|
+
parallel({
|
|
186
|
+
"@related": (ctx) => {
|
|
187
|
+
const product = ctx.get("product");
|
|
188
|
+
return <RelatedProducts category={product?.category} />;
|
|
189
|
+
},
|
|
190
|
+
}),
|
|
191
|
+
]),
|
|
192
|
+
]),
|
|
193
|
+
])
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Orphan layouts can call `ctx.get()` to read data set by their parent
|
|
197
|
+
handler. They can also call `ctx.set()`, though the primary pattern is
|
|
198
|
+
for route handlers and middleware to write context variables and for
|
|
199
|
+
orphan layouts to read them.
|
|
200
|
+
|
|
144
201
|
## Layout Revalidation
|
|
145
202
|
|
|
146
|
-
|
|
203
|
+
Standalone `layout()` entries don't revalidate by default — on an action,
|
|
204
|
+
parent-chain segments are skipped unless a `revalidate()` opts them in.
|
|
205
|
+
(Orphan layouts inside a `path()` are the opposite: they ride along with
|
|
206
|
+
the route entry by default.) Control with `revalidate()`:
|
|
147
207
|
|
|
148
208
|
```typescript
|
|
149
209
|
layout(<ShopLayout />, () => [
|
|
@@ -154,18 +214,76 @@ layout(<ShopLayout />, () => [
|
|
|
154
214
|
])
|
|
155
215
|
|
|
156
216
|
// Or revalidate based on conditions
|
|
217
|
+
import * as CartActions from "./actions/cart";
|
|
218
|
+
|
|
157
219
|
layout(<CartLayout />, () => [
|
|
158
|
-
revalidate((
|
|
220
|
+
revalidate((ctx) => ctx.isAction(CartActions) || undefined),
|
|
159
221
|
|
|
160
222
|
path("/cart", CartPage, { name: "cart" }),
|
|
161
223
|
])
|
|
162
224
|
```
|
|
163
225
|
|
|
226
|
+
If child segments read data that was established by this layout or by a
|
|
227
|
+
route handler above them, revalidate the outer segment too. Partial
|
|
228
|
+
revalidation does not re-run non-revalidated ancestors just to rebuild
|
|
229
|
+
their `ctx.set()` state.
|
|
230
|
+
|
|
231
|
+
### Revalidation Contracts
|
|
232
|
+
|
|
233
|
+
Contracts are the tool for cross-entry sharing — the bottom rung of the
|
|
234
|
+
data-passing ladder (`/rango` → "Passing data down the tree"). Before
|
|
235
|
+
writing one, check whether the producer can move down a rung: into the
|
|
236
|
+
consumer's own entry as an orphan layout, into middleware, or into a
|
|
237
|
+
loader. When the data genuinely must flow from an outer entry, define
|
|
238
|
+
named revalidation functions and reuse them on both producer and
|
|
239
|
+
consumer segments:
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
// revalidation-contracts.ts
|
|
243
|
+
import { addToCart } from "./actions/cart";
|
|
244
|
+
|
|
245
|
+
export const revalidateCartData = (ctx) => ctx.isAction(addToCart) || undefined;
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
layout(<CartLayout />, () => [
|
|
250
|
+
revalidate(revalidateCartData), // producer
|
|
251
|
+
path("/cart", CartPage, { name: "cart" }, () => [
|
|
252
|
+
revalidate(revalidateCartData), // consumer
|
|
253
|
+
]),
|
|
254
|
+
]);
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
If a segment depends on multiple upstream domains, compose multiple
|
|
258
|
+
contracts (`revalidateAuthData`, `revalidateCartData`, and so on).
|
|
259
|
+
|
|
260
|
+
You can also package them as importable handoff helpers:
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
// revalidation-contracts.ts
|
|
264
|
+
import { revalidate } from "@rangojs/router";
|
|
265
|
+
import * as AuthActions from "./actions/auth";
|
|
266
|
+
|
|
267
|
+
export const revalidateAuthData = (ctx) =>
|
|
268
|
+
ctx.isAction(AuthActions) || undefined;
|
|
269
|
+
export const revalidateAuth = () => [revalidate(revalidateAuthData)];
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
layout(<ShellLayout />, () => [
|
|
274
|
+
revalidateAuth(),
|
|
275
|
+
path("/account", AccountPage, { name: "account" }, () => [
|
|
276
|
+
revalidateAuth(),
|
|
277
|
+
]),
|
|
278
|
+
]);
|
|
279
|
+
```
|
|
280
|
+
|
|
164
281
|
## Complete Example
|
|
165
282
|
|
|
166
283
|
```typescript
|
|
167
284
|
import { urls } from "@rangojs/router";
|
|
168
285
|
import { Outlet, ParallelOutlet } from "@rangojs/router/client";
|
|
286
|
+
import * as CartActions from "./actions/cart";
|
|
169
287
|
|
|
170
288
|
function ShopLayout() {
|
|
171
289
|
return (
|
|
@@ -195,7 +313,7 @@ export const shopPatterns = urls(({ path, layout, parallel, loader, revalidate }
|
|
|
195
313
|
}, () => [
|
|
196
314
|
// Layout loaders
|
|
197
315
|
loader(CartLoader, () => [
|
|
198
|
-
revalidate((
|
|
316
|
+
revalidate((ctx) => ctx.isAction(CartActions) || undefined),
|
|
199
317
|
]),
|
|
200
318
|
|
|
201
319
|
// Parallel routes
|
|
@@ -211,3 +329,25 @@ export const shopPatterns = urls(({ path, layout, parallel, loader, revalidate }
|
|
|
211
329
|
]),
|
|
212
330
|
]);
|
|
213
331
|
```
|
|
332
|
+
|
|
333
|
+
## Handler-attached `.use`
|
|
334
|
+
|
|
335
|
+
Layout handlers can carry their own middleware, default parallels, and includes via `.use` so a layout becomes a self-contained unit reusable across mount sites.
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
const AdminLayout: Handler = (ctx) => {
|
|
339
|
+
const user = ctx.get(CurrentUser);
|
|
340
|
+
return <Admin user={user} />;
|
|
341
|
+
};
|
|
342
|
+
AdminLayout.use = () => [
|
|
343
|
+
middleware(requireAdmin),
|
|
344
|
+
parallel({ "@adminNotifs": AdminNotifsSlot }),
|
|
345
|
+
];
|
|
346
|
+
|
|
347
|
+
// Mount site declares structure only; defaults travel with the layout.
|
|
348
|
+
layout(AdminLayout, () => [
|
|
349
|
+
path("/admin", AdminIndex, { name: "admin.index" }),
|
|
350
|
+
]);
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
Allowed item types in a layout's `.use` mirror the layout `use()` callback (the broadest set). Explicit `use()` at the mount site merges with `handler.use` (handler defaults first, explicit second). See [skills/handler-use](../handler-use/SKILL.md) for merge order and per-mount-site allowed types.
|