react-router 7.15.1 → 8.0.0-pre.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -2
- package/dist/development/dom-export.d.ts +6 -172
- package/dist/development/dom-export.js +12 -1007
- package/dist/development/index-react-server-client.d.ts +7 -4
- package/dist/development/index-react-server-client.js +8 -52
- package/dist/development/index-react-server.d.ts +1645 -1635
- package/dist/development/index-react-server.js +2880 -3642
- package/dist/development/index.d.ts +43 -1469
- package/dist/development/index.js +37 -2621
- package/dist/development/lib/actions.js +62 -0
- package/dist/development/lib/components.d.ts +1022 -0
- package/dist/development/lib/components.js +835 -0
- package/dist/development/lib/context.d.ts +83 -0
- package/dist/development/lib/context.js +41 -0
- package/dist/development/lib/dom/dom.d.ts +119 -0
- package/dist/development/lib/dom/dom.js +143 -0
- package/dist/development/lib/dom/lib.d.ts +2042 -0
- package/dist/development/lib/dom/lib.js +1259 -0
- package/dist/development/lib/dom/server.d.ts +138 -0
- package/dist/development/lib/dom/server.js +301 -0
- package/dist/development/lib/dom/ssr/components.d.ts +196 -0
- package/dist/development/lib/dom/ssr/components.js +579 -0
- package/dist/development/lib/dom/ssr/data.js +29 -0
- package/dist/development/lib/dom/ssr/entry.d.ts +59 -0
- package/dist/development/lib/dom/ssr/errorBoundaries.d.ts +27 -0
- package/dist/development/lib/dom/ssr/errorBoundaries.js +83 -0
- package/dist/development/lib/dom/ssr/errors.d.ts +7 -0
- package/dist/development/lib/dom/ssr/errors.js +36 -0
- package/dist/development/lib/dom/ssr/fallback.js +28 -0
- package/dist/development/lib/dom/ssr/fog-of-war.d.ts +12 -0
- package/dist/development/lib/dom/ssr/fog-of-war.js +170 -0
- package/dist/development/lib/dom/ssr/hydration.d.ts +32 -0
- package/dist/development/lib/dom/ssr/hydration.js +29 -0
- package/dist/development/lib/dom/ssr/invariant.js +16 -0
- package/dist/development/lib/dom/ssr/links.js +170 -0
- package/dist/development/lib/dom/ssr/markup.js +24 -0
- package/dist/development/lib/dom/ssr/routeModules.d.ts +206 -0
- package/dist/development/lib/dom/ssr/routeModules.js +31 -0
- package/dist/development/lib/dom/ssr/routes-test-stub.d.ts +62 -0
- package/dist/development/lib/dom/ssr/routes-test-stub.js +108 -0
- package/dist/development/lib/dom/ssr/routes.d.ts +33 -0
- package/dist/development/lib/dom/ssr/routes.js +303 -0
- package/dist/development/lib/dom/ssr/server.d.ts +45 -0
- package/dist/development/lib/dom/ssr/server.js +68 -0
- package/dist/development/lib/dom/ssr/single-fetch.d.ts +14 -0
- package/dist/development/lib/dom/ssr/single-fetch.js +346 -0
- package/dist/development/lib/dom-export/dom-router-provider.d.ts +9 -0
- package/dist/development/lib/dom-export/dom-router-provider.js +22 -0
- package/dist/development/lib/dom-export/hydrated-router.d.ts +125 -0
- package/dist/development/lib/dom-export/hydrated-router.js +153 -0
- package/dist/development/lib/errors.js +29 -0
- package/dist/development/lib/hooks.d.ts +947 -0
- package/dist/development/lib/hooks.js +1386 -0
- package/dist/development/lib/href.d.ts +20 -0
- package/dist/development/lib/href.js +50 -0
- package/dist/development/lib/router/history.d.ts +258 -0
- package/dist/development/lib/router/history.js +371 -0
- package/dist/development/lib/router/instrumentation.d.ts +86 -0
- package/dist/development/lib/router/instrumentation.js +213 -0
- package/dist/development/lib/router/links.d.ts +113 -0
- package/dist/development/lib/router/router.d.ts +663 -0
- package/dist/development/lib/router/router.js +2981 -0
- package/dist/development/lib/router/utils.d.ts +942 -0
- package/dist/development/lib/router/utils.js +791 -0
- package/dist/development/lib/rsc/browser.d.ts +137 -0
- package/dist/development/lib/rsc/browser.js +599 -0
- package/dist/development/lib/rsc/errorBoundaries.d.ts +11 -0
- package/dist/development/lib/rsc/errorBoundaries.js +90 -0
- package/dist/development/lib/rsc/html-stream/browser.d.ts +48 -0
- package/dist/development/lib/rsc/html-stream/browser.js +74 -0
- package/dist/development/lib/rsc/html-stream/server.js +78 -0
- package/dist/development/lib/rsc/route-modules.js +27 -0
- package/dist/development/lib/rsc/server.rsc.d.ts +219 -0
- package/dist/development/lib/rsc/server.ssr.d.ts +129 -0
- package/dist/development/lib/rsc/server.ssr.js +388 -0
- package/dist/development/lib/server-runtime/build.d.ts +66 -0
- package/dist/development/lib/server-runtime/cookies.d.ts +66 -0
- package/dist/development/lib/server-runtime/cookies.js +139 -0
- package/dist/development/lib/server-runtime/crypto.js +43 -0
- package/dist/development/lib/server-runtime/data.d.ts +13 -0
- package/dist/development/lib/server-runtime/data.js +25 -0
- package/dist/development/lib/server-runtime/dev.d.ts +9 -0
- package/dist/development/lib/server-runtime/dev.js +26 -0
- package/dist/development/lib/server-runtime/entry.js +20 -0
- package/dist/development/lib/server-runtime/errors.js +95 -0
- package/dist/development/lib/server-runtime/headers.js +73 -0
- package/dist/development/lib/server-runtime/invariant.js +19 -0
- package/dist/development/lib/server-runtime/mode.d.ts +12 -0
- package/dist/development/lib/server-runtime/mode.js +25 -0
- package/dist/development/lib/server-runtime/routeMatching.js +28 -0
- package/dist/development/lib/server-runtime/routes.d.ts +13 -0
- package/dist/development/lib/server-runtime/routes.js +74 -0
- package/dist/development/lib/server-runtime/server.d.ts +10 -0
- package/dist/development/lib/server-runtime/server.js +351 -0
- package/dist/development/lib/server-runtime/serverHandoff.js +17 -0
- package/dist/development/lib/server-runtime/sessions/cookieStorage.d.ts +25 -0
- package/dist/development/lib/server-runtime/sessions/cookieStorage.js +45 -0
- package/dist/development/lib/server-runtime/sessions/memoryStorage.d.ts +23 -0
- package/dist/development/lib/server-runtime/sessions/memoryStorage.js +52 -0
- package/dist/development/lib/server-runtime/sessions.d.ts +145 -0
- package/dist/development/lib/server-runtime/sessions.js +98 -0
- package/dist/development/lib/server-runtime/single-fetch.d.ts +7 -0
- package/dist/development/lib/server-runtime/single-fetch.js +215 -0
- package/dist/development/lib/server-runtime/urls.js +31 -0
- package/dist/development/lib/server-runtime/warnings.js +20 -0
- package/dist/development/lib/types/future.d.ts +9 -0
- package/dist/development/lib/types/internal.d.ts +26 -177
- package/dist/development/lib/types/internal.js +3 -2
- package/dist/{production/register-Bsscfj79.d.ts → development/lib/types/register.d.ts} +9 -15
- package/dist/development/lib/types/route-data.d.ts +113 -0
- package/dist/development/lib/types/route-module-annotations.d.ts +149 -0
- package/dist/development/lib/types/route-module.d.ts +19 -0
- package/dist/development/lib/types/serializes-to.d.ts +13 -0
- package/dist/development/lib/types/utils.d.ts +11 -0
- package/dist/development/vendor/turbo-stream-v2/flatten.js +159 -0
- package/dist/development/vendor/turbo-stream-v2/turbo-stream.js +178 -0
- package/dist/development/vendor/turbo-stream-v2/unflatten.js +198 -0
- package/dist/development/vendor/turbo-stream-v2/utils.js +47 -0
- package/dist/production/dom-export.d.ts +6 -172
- package/dist/production/dom-export.js +12 -1007
- package/dist/production/index-react-server-client.d.ts +7 -4
- package/dist/production/index-react-server-client.js +8 -52
- package/dist/production/index-react-server.d.ts +1645 -1635
- package/dist/production/index-react-server.js +2871 -3642
- package/dist/production/index.d.ts +43 -1469
- package/dist/production/index.js +37 -2621
- package/dist/production/lib/actions.js +62 -0
- package/dist/production/lib/components.d.ts +1022 -0
- package/dist/production/lib/components.js +835 -0
- package/dist/production/lib/context.d.ts +83 -0
- package/dist/production/lib/context.js +41 -0
- package/dist/production/lib/dom/dom.d.ts +119 -0
- package/dist/production/lib/dom/dom.js +143 -0
- package/dist/production/lib/dom/lib.d.ts +2042 -0
- package/dist/production/lib/dom/lib.js +1259 -0
- package/dist/production/lib/dom/server.d.ts +138 -0
- package/dist/production/lib/dom/server.js +301 -0
- package/dist/production/lib/dom/ssr/components.d.ts +196 -0
- package/dist/production/lib/dom/ssr/components.js +579 -0
- package/dist/production/lib/dom/ssr/data.js +29 -0
- package/dist/production/lib/dom/ssr/entry.d.ts +59 -0
- package/dist/production/lib/dom/ssr/errorBoundaries.d.ts +27 -0
- package/dist/production/lib/dom/ssr/errorBoundaries.js +83 -0
- package/dist/production/lib/dom/ssr/errors.d.ts +7 -0
- package/dist/production/lib/dom/ssr/errors.js +36 -0
- package/dist/production/lib/dom/ssr/fallback.js +21 -0
- package/dist/production/lib/dom/ssr/fog-of-war.d.ts +12 -0
- package/dist/production/lib/dom/ssr/fog-of-war.js +170 -0
- package/dist/production/lib/dom/ssr/hydration.d.ts +32 -0
- package/dist/production/lib/dom/ssr/hydration.js +29 -0
- package/dist/production/lib/dom/ssr/invariant.js +16 -0
- package/dist/production/lib/dom/ssr/links.js +170 -0
- package/dist/production/lib/dom/ssr/markup.js +24 -0
- package/dist/production/lib/dom/ssr/routeModules.d.ts +206 -0
- package/dist/production/lib/dom/ssr/routeModules.js +31 -0
- package/dist/production/lib/dom/ssr/routes-test-stub.d.ts +62 -0
- package/dist/production/lib/dom/ssr/routes-test-stub.js +108 -0
- package/dist/production/lib/dom/ssr/routes.d.ts +33 -0
- package/dist/production/lib/dom/ssr/routes.js +303 -0
- package/dist/production/lib/dom/ssr/server.d.ts +45 -0
- package/dist/production/lib/dom/ssr/server.js +68 -0
- package/dist/production/lib/dom/ssr/single-fetch.d.ts +14 -0
- package/dist/production/lib/dom/ssr/single-fetch.js +346 -0
- package/dist/production/lib/dom-export/dom-router-provider.d.ts +9 -0
- package/dist/production/lib/dom-export/dom-router-provider.js +22 -0
- package/dist/production/lib/dom-export/hydrated-router.d.ts +125 -0
- package/dist/production/lib/dom-export/hydrated-router.js +153 -0
- package/dist/production/lib/errors.js +29 -0
- package/dist/production/lib/hooks.d.ts +947 -0
- package/dist/production/lib/hooks.js +1371 -0
- package/dist/production/lib/href.d.ts +20 -0
- package/dist/production/lib/href.js +50 -0
- package/dist/production/lib/router/history.d.ts +258 -0
- package/dist/production/lib/router/history.js +371 -0
- package/dist/production/lib/router/instrumentation.d.ts +86 -0
- package/dist/production/lib/router/instrumentation.js +213 -0
- package/dist/production/lib/router/links.d.ts +113 -0
- package/dist/production/lib/router/router.d.ts +663 -0
- package/dist/production/lib/router/router.js +2981 -0
- package/dist/production/lib/router/utils.d.ts +942 -0
- package/dist/production/lib/router/utils.js +782 -0
- package/dist/production/lib/rsc/browser.d.ts +137 -0
- package/dist/production/lib/rsc/browser.js +599 -0
- package/dist/production/lib/rsc/errorBoundaries.d.ts +11 -0
- package/dist/production/lib/rsc/errorBoundaries.js +90 -0
- package/dist/production/lib/rsc/html-stream/browser.d.ts +48 -0
- package/dist/production/lib/rsc/html-stream/browser.js +74 -0
- package/dist/production/lib/rsc/html-stream/server.js +78 -0
- package/dist/production/lib/rsc/route-modules.js +27 -0
- package/dist/production/lib/rsc/server.rsc.d.ts +219 -0
- package/dist/production/lib/rsc/server.ssr.d.ts +129 -0
- package/dist/production/lib/rsc/server.ssr.js +388 -0
- package/dist/production/lib/server-runtime/build.d.ts +66 -0
- package/dist/production/lib/server-runtime/cookies.d.ts +66 -0
- package/dist/production/lib/server-runtime/cookies.js +139 -0
- package/dist/production/lib/server-runtime/crypto.js +43 -0
- package/dist/production/lib/server-runtime/data.d.ts +13 -0
- package/dist/production/lib/server-runtime/data.js +25 -0
- package/dist/production/lib/server-runtime/dev.d.ts +9 -0
- package/dist/production/lib/server-runtime/dev.js +26 -0
- package/dist/production/lib/server-runtime/entry.js +20 -0
- package/dist/production/lib/server-runtime/errors.js +95 -0
- package/dist/production/lib/server-runtime/headers.js +73 -0
- package/dist/production/lib/server-runtime/invariant.js +19 -0
- package/dist/production/lib/server-runtime/mode.d.ts +12 -0
- package/dist/production/lib/server-runtime/mode.js +25 -0
- package/dist/production/lib/server-runtime/routeMatching.js +28 -0
- package/dist/production/lib/server-runtime/routes.d.ts +13 -0
- package/dist/production/lib/server-runtime/routes.js +74 -0
- package/dist/production/lib/server-runtime/server.d.ts +10 -0
- package/dist/production/lib/server-runtime/server.js +351 -0
- package/dist/production/lib/server-runtime/serverHandoff.js +17 -0
- package/dist/production/lib/server-runtime/sessions/cookieStorage.d.ts +25 -0
- package/dist/production/lib/server-runtime/sessions/cookieStorage.js +45 -0
- package/dist/production/lib/server-runtime/sessions/memoryStorage.d.ts +23 -0
- package/dist/production/lib/server-runtime/sessions/memoryStorage.js +52 -0
- package/dist/production/lib/server-runtime/sessions.d.ts +145 -0
- package/dist/production/lib/server-runtime/sessions.js +98 -0
- package/dist/production/lib/server-runtime/single-fetch.d.ts +7 -0
- package/dist/production/lib/server-runtime/single-fetch.js +215 -0
- package/dist/production/lib/server-runtime/urls.js +31 -0
- package/dist/production/lib/server-runtime/warnings.js +20 -0
- package/dist/production/lib/types/future.d.ts +9 -0
- package/dist/production/lib/types/internal.d.ts +26 -177
- package/dist/production/lib/types/internal.js +3 -2
- package/dist/{development/register-Bsscfj79.d.ts → production/lib/types/register.d.ts} +9 -15
- package/dist/production/lib/types/route-data.d.ts +113 -0
- package/dist/production/lib/types/route-module-annotations.d.ts +149 -0
- package/dist/production/lib/types/route-module.d.ts +19 -0
- package/dist/production/lib/types/serializes-to.d.ts +13 -0
- package/dist/production/lib/types/utils.d.ts +11 -0
- package/dist/production/vendor/turbo-stream-v2/flatten.js +159 -0
- package/dist/production/vendor/turbo-stream-v2/turbo-stream.js +178 -0
- package/dist/production/vendor/turbo-stream-v2/unflatten.js +198 -0
- package/dist/production/vendor/turbo-stream-v2/utils.js +47 -0
- package/docs/explanation/backend-for-frontend.md +50 -0
- package/docs/explanation/code-splitting.md +77 -0
- package/docs/explanation/concurrency.md +135 -0
- package/docs/explanation/form-vs-fetcher.md +292 -0
- package/docs/explanation/hot-module-replacement.md +137 -0
- package/docs/explanation/hydration.md +14 -0
- package/docs/explanation/index-query-param.md +86 -0
- package/docs/explanation/index.md +4 -0
- package/docs/explanation/lazy-route-discovery.md +78 -0
- package/docs/explanation/location.md +6 -0
- package/docs/explanation/progressive-enhancement.md +150 -0
- package/docs/explanation/race-conditions.md +88 -0
- package/docs/explanation/react-transitions.md +160 -0
- package/docs/explanation/route-matching.md +7 -0
- package/docs/explanation/server-client-execution.md +4 -0
- package/docs/explanation/sessions-and-cookies.md +465 -0
- package/docs/explanation/special-files.md +16 -0
- package/docs/explanation/state-management.md +524 -0
- package/docs/explanation/styling.md +87 -0
- package/docs/explanation/type-safety.md +82 -0
- package/docs/how-to/accessibility.md +44 -0
- package/docs/how-to/client-data.md +199 -0
- package/docs/how-to/data-strategy.md +317 -0
- package/docs/how-to/error-boundary.md +231 -0
- package/docs/how-to/error-reporting.md +134 -0
- package/docs/how-to/fetchers.md +307 -0
- package/docs/how-to/file-route-conventions.md +410 -0
- package/docs/how-to/file-uploads.md +217 -0
- package/docs/how-to/form-validation.md +120 -0
- package/docs/how-to/headers.md +164 -0
- package/docs/how-to/index.md +4 -0
- package/docs/how-to/instrumentation.md +556 -0
- package/docs/how-to/meta.md +40 -0
- package/docs/how-to/middleware.md +728 -0
- package/docs/how-to/navigation-blocking.md +233 -0
- package/docs/how-to/optimize-revalidation.md +12 -0
- package/docs/how-to/pre-rendering.md +225 -0
- package/docs/how-to/presets.md +103 -0
- package/docs/how-to/react-server-components.md +899 -0
- package/docs/how-to/resource-routes.md +126 -0
- package/docs/how-to/route-module-type-safety.md +100 -0
- package/docs/how-to/search-params.md +4 -0
- package/docs/how-to/security.md +30 -0
- package/docs/how-to/server-bundles.md +66 -0
- package/docs/how-to/spa.md +120 -0
- package/docs/how-to/status.md +63 -0
- package/docs/how-to/suspense.md +132 -0
- package/docs/how-to/using-handle.md +117 -0
- package/docs/how-to/view-transitions.md +237 -0
- package/docs/how-to/webhook.md +50 -0
- package/docs/index.md +39 -0
- package/docs/start/data/actions.md +138 -0
- package/docs/start/data/custom.md +198 -0
- package/docs/start/data/data-loading.md +44 -0
- package/docs/start/data/index.md +4 -0
- package/docs/start/data/installation.md +52 -0
- package/docs/start/data/navigating.md +12 -0
- package/docs/start/data/pending-ui.md +12 -0
- package/docs/start/data/route-object.md +248 -0
- package/docs/start/data/routing.md +281 -0
- package/docs/start/data/testing.md +8 -0
- package/docs/start/declarative/index.md +4 -0
- package/docs/start/declarative/installation.md +43 -0
- package/docs/start/declarative/navigating.md +133 -0
- package/docs/start/declarative/routing.md +237 -0
- package/docs/start/declarative/url-values.md +65 -0
- package/docs/start/framework/actions.md +175 -0
- package/docs/start/framework/data-loading.md +201 -0
- package/docs/start/framework/deploying.md +96 -0
- package/docs/start/framework/index.md +4 -0
- package/docs/start/framework/installation.md +42 -0
- package/docs/start/framework/navigating.md +182 -0
- package/docs/start/framework/pending-ui.md +142 -0
- package/docs/start/framework/rendering.md +59 -0
- package/docs/start/framework/route-module.md +527 -0
- package/docs/start/framework/routing.md +362 -0
- package/docs/start/framework/testing.md +133 -0
- package/docs/start/index.md +4 -0
- package/docs/start/modes.md +201 -0
- package/docs/upgrading/component-routes.md +363 -0
- package/docs/upgrading/future.md +31 -0
- package/docs/upgrading/index.md +4 -0
- package/docs/upgrading/remix.md +403 -0
- package/docs/upgrading/router-provider.md +442 -0
- package/docs/upgrading/v6.md +379 -0
- package/package.json +44 -87
- package/dist/development/browser-3AnU12UI.d.mts +0 -318
- package/dist/development/browser-BOdXz9dK.d.ts +0 -318
- package/dist/development/chunk-4N6VE7H7.mjs +0 -11528
- package/dist/development/chunk-4YRVXM2U.js +0 -188
- package/dist/development/chunk-66UKHEGQ.js +0 -1362
- package/dist/development/chunk-D6LUOGOQ.js +0 -10229
- package/dist/development/chunk-RJYABSBD.mjs +0 -2585
- package/dist/development/context-ByvtofY2.d.mts +0 -1771
- package/dist/development/data-BVUf681J.d.mts +0 -1732
- package/dist/development/data-BqZ2x964.d.ts +0 -1732
- package/dist/development/dom-export.d.mts +0 -172
- package/dist/development/dom-export.mjs +0 -1008
- package/dist/development/index-react-server-client-BS5F89FR.d.ts +0 -3655
- package/dist/development/index-react-server-client-DY04-103.d.mts +0 -2600
- package/dist/development/index-react-server-client.d.mts +0 -4
- package/dist/development/index-react-server-client.mjs +0 -59
- package/dist/development/index-react-server.d.mts +0 -2703
- package/dist/development/index-react-server.mjs +0 -3780
- package/dist/development/index.d.mts +0 -1472
- package/dist/development/index.mjs +0 -277
- package/dist/development/instrumentation-cRWWLfsU.d.ts +0 -715
- package/dist/development/lib/types/internal.d.mts +0 -184
- package/dist/development/lib/types/internal.mjs +0 -10
- package/dist/development/register-Df8okEea.d.mts +0 -30
- package/dist/production/browser-3AnU12UI.d.mts +0 -318
- package/dist/production/browser-BOdXz9dK.d.ts +0 -318
- package/dist/production/chunk-6S4627ZB.mjs +0 -2585
- package/dist/production/chunk-HUBUW7R3.js +0 -10229
- package/dist/production/chunk-JAKZPQZC.mjs +0 -11528
- package/dist/production/chunk-PNZCCTKT.js +0 -1362
- package/dist/production/chunk-Y6IFXO7V.js +0 -188
- package/dist/production/context-ByvtofY2.d.mts +0 -1771
- package/dist/production/data-BVUf681J.d.mts +0 -1732
- package/dist/production/data-BqZ2x964.d.ts +0 -1732
- package/dist/production/dom-export.d.mts +0 -172
- package/dist/production/dom-export.mjs +0 -1008
- package/dist/production/index-react-server-client-BS5F89FR.d.ts +0 -3655
- package/dist/production/index-react-server-client-DY04-103.d.mts +0 -2600
- package/dist/production/index-react-server-client.d.mts +0 -4
- package/dist/production/index-react-server-client.mjs +0 -59
- package/dist/production/index-react-server.d.mts +0 -2703
- package/dist/production/index-react-server.mjs +0 -3780
- package/dist/production/index.d.mts +0 -1472
- package/dist/production/index.mjs +0 -277
- package/dist/production/instrumentation-cRWWLfsU.d.ts +0 -715
- package/dist/production/lib/types/internal.d.mts +0 -184
- package/dist/production/lib/types/internal.mjs +0 -10
- package/dist/production/register-Df8okEea.d.mts +0 -30
|
@@ -0,0 +1,1259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* react-router v8.0.0-pre.0
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) Remix Software Inc.
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE.md file in the root directory of this source tree.
|
|
8
|
+
*
|
|
9
|
+
* @license MIT
|
|
10
|
+
*/
|
|
11
|
+
import { createBrowserHistory, createHashHistory, createPath, invariant, warning } from "../router/history.js";
|
|
12
|
+
import { ErrorResponseImpl, defaultMapRouteProperties, joinPaths, matchPath, parseToInfo, resolveTo, stripBasename } from "../router/utils.js";
|
|
13
|
+
import { IDLE_FETCHER, createRouter } from "../router/router.js";
|
|
14
|
+
import { DataRouterContext, DataRouterStateContext, FetchersContext, NavigationContext, RouteContext, ViewTransitionContext } from "../context.js";
|
|
15
|
+
import { useBlocker, useHref, useLocation, useMatches, useNavigate, useNavigation, useResolvedPath, useRouteId } from "../hooks.js";
|
|
16
|
+
import { Router, hydrationRouteProperties } from "../components.js";
|
|
17
|
+
import { createSearchParams, getFormSubmissionInfo, getSearchParamsForLocation, shouldProcessLinkClick } from "./dom.js";
|
|
18
|
+
import { escapeHtml } from "./ssr/markup.js";
|
|
19
|
+
import { FrameworkContext, PrefetchPageLinks, mergeRefs, usePrefetchBehavior } from "./ssr/components.js";
|
|
20
|
+
import * as React$1 from "react";
|
|
21
|
+
//#region lib/dom/lib.tsx
|
|
22
|
+
const isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
|
|
23
|
+
try {
|
|
24
|
+
if (isBrowser) window.__reactRouterVersion = "8.0.0-pre.0";
|
|
25
|
+
} catch (e) {}
|
|
26
|
+
/**
|
|
27
|
+
* Create a new {@link DataRouter| data router} that manages the application
|
|
28
|
+
* path via [`history.pushState`](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState)
|
|
29
|
+
* and [`history.replaceState`](https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState).
|
|
30
|
+
*
|
|
31
|
+
* @public
|
|
32
|
+
* @category Data Routers
|
|
33
|
+
* @mode data
|
|
34
|
+
* @param routes Application routes
|
|
35
|
+
* @param opts Options
|
|
36
|
+
* @param {DOMRouterOpts.basename} opts.basename n/a
|
|
37
|
+
* @param {DOMRouterOpts.dataStrategy} opts.dataStrategy n/a
|
|
38
|
+
* @param {DOMRouterOpts.future} opts.future n/a
|
|
39
|
+
* @param {DOMRouterOpts.getContext} opts.getContext n/a
|
|
40
|
+
* @param {DOMRouterOpts.hydrationData} opts.hydrationData n/a
|
|
41
|
+
* @param {DOMRouterOpts.instrumentations} opts.instrumentations n/a
|
|
42
|
+
* @param {DOMRouterOpts.patchRoutesOnNavigation} opts.patchRoutesOnNavigation n/a
|
|
43
|
+
* @param {DOMRouterOpts.window} opts.window n/a
|
|
44
|
+
* @returns An initialized {@link DataRouter| data router} to pass to {@link RouterProvider | `<RouterProvider>`}
|
|
45
|
+
*/
|
|
46
|
+
function createBrowserRouter(routes, opts) {
|
|
47
|
+
return createRouter({
|
|
48
|
+
basename: opts?.basename,
|
|
49
|
+
getContext: opts?.getContext,
|
|
50
|
+
future: opts?.future,
|
|
51
|
+
history: createBrowserHistory({ window: opts?.window }),
|
|
52
|
+
hydrationData: opts?.hydrationData || parseHydrationData(),
|
|
53
|
+
routes,
|
|
54
|
+
mapRouteProperties: defaultMapRouteProperties,
|
|
55
|
+
hydrationRouteProperties,
|
|
56
|
+
dataStrategy: opts?.dataStrategy,
|
|
57
|
+
patchRoutesOnNavigation: opts?.patchRoutesOnNavigation,
|
|
58
|
+
window: opts?.window,
|
|
59
|
+
instrumentations: opts?.instrumentations
|
|
60
|
+
}).initialize();
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Create a new {@link DataRouter| data router} that manages the application
|
|
64
|
+
* path via the URL [`hash`](https://developer.mozilla.org/en-US/docs/Web/API/URL/hash).
|
|
65
|
+
*
|
|
66
|
+
* @public
|
|
67
|
+
* @category Data Routers
|
|
68
|
+
* @mode data
|
|
69
|
+
* @param routes Application routes
|
|
70
|
+
* @param opts Options
|
|
71
|
+
* @param {DOMRouterOpts.basename} opts.basename n/a
|
|
72
|
+
* @param {DOMRouterOpts.future} opts.future n/a
|
|
73
|
+
* @param {DOMRouterOpts.getContext} opts.getContext n/a
|
|
74
|
+
* @param {DOMRouterOpts.hydrationData} opts.hydrationData n/a
|
|
75
|
+
* @param {DOMRouterOpts.instrumentations} opts.instrumentations n/a
|
|
76
|
+
* @param {DOMRouterOpts.dataStrategy} opts.dataStrategy n/a
|
|
77
|
+
* @param {DOMRouterOpts.patchRoutesOnNavigation} opts.patchRoutesOnNavigation n/a
|
|
78
|
+
* @param {DOMRouterOpts.window} opts.window n/a
|
|
79
|
+
* @returns An initialized {@link DataRouter| data router} to pass to {@link RouterProvider | `<RouterProvider>`}
|
|
80
|
+
*/
|
|
81
|
+
function createHashRouter(routes, opts) {
|
|
82
|
+
return createRouter({
|
|
83
|
+
basename: opts?.basename,
|
|
84
|
+
getContext: opts?.getContext,
|
|
85
|
+
future: opts?.future,
|
|
86
|
+
history: createHashHistory({ window: opts?.window }),
|
|
87
|
+
hydrationData: opts?.hydrationData || parseHydrationData(),
|
|
88
|
+
routes,
|
|
89
|
+
mapRouteProperties: defaultMapRouteProperties,
|
|
90
|
+
hydrationRouteProperties,
|
|
91
|
+
dataStrategy: opts?.dataStrategy,
|
|
92
|
+
patchRoutesOnNavigation: opts?.patchRoutesOnNavigation,
|
|
93
|
+
window: opts?.window,
|
|
94
|
+
instrumentations: opts?.instrumentations
|
|
95
|
+
}).initialize();
|
|
96
|
+
}
|
|
97
|
+
function parseHydrationData() {
|
|
98
|
+
let state = window?.__staticRouterHydrationData;
|
|
99
|
+
if (state && state.errors) state = {
|
|
100
|
+
...state,
|
|
101
|
+
errors: deserializeErrors(state.errors)
|
|
102
|
+
};
|
|
103
|
+
return state;
|
|
104
|
+
}
|
|
105
|
+
function deserializeErrors(errors) {
|
|
106
|
+
if (!errors) return null;
|
|
107
|
+
let entries = Object.entries(errors);
|
|
108
|
+
let serialized = {};
|
|
109
|
+
for (let [key, val] of entries) if (val && val.__type === "RouteErrorResponse") serialized[key] = new ErrorResponseImpl(val.status, val.statusText, val.data, val.internal === true);
|
|
110
|
+
else if (val && val.__type === "Error") {
|
|
111
|
+
if (val.__subType) {
|
|
112
|
+
let ErrorConstructor = window[val.__subType];
|
|
113
|
+
if (typeof ErrorConstructor === "function") try {
|
|
114
|
+
let error = new ErrorConstructor(val.message);
|
|
115
|
+
error.stack = "";
|
|
116
|
+
serialized[key] = error;
|
|
117
|
+
} catch (e) {}
|
|
118
|
+
}
|
|
119
|
+
if (serialized[key] == null) {
|
|
120
|
+
let error = new Error(val.message);
|
|
121
|
+
error.stack = "";
|
|
122
|
+
serialized[key] = error;
|
|
123
|
+
}
|
|
124
|
+
} else serialized[key] = val;
|
|
125
|
+
return serialized;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* A declarative {@link Router | `<Router>`} using the browser [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History)
|
|
129
|
+
* API for client-side routing.
|
|
130
|
+
*
|
|
131
|
+
* @public
|
|
132
|
+
* @category Declarative Routers
|
|
133
|
+
* @mode declarative
|
|
134
|
+
* @param props Props
|
|
135
|
+
* @param {BrowserRouterProps.basename} props.basename n/a
|
|
136
|
+
* @param {BrowserRouterProps.children} props.children n/a
|
|
137
|
+
* @param {BrowserRouterProps.useTransitions} props.useTransitions n/a
|
|
138
|
+
* @param {BrowserRouterProps.window} props.window n/a
|
|
139
|
+
* @returns A declarative {@link Router | `<Router>`} using the browser [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History)
|
|
140
|
+
* API for client-side routing.
|
|
141
|
+
*/
|
|
142
|
+
function BrowserRouter({ basename, children, useTransitions, window }) {
|
|
143
|
+
let historyRef = React$1.useRef(null);
|
|
144
|
+
if (historyRef.current == null) historyRef.current = createBrowserHistory({
|
|
145
|
+
window,
|
|
146
|
+
v5Compat: true
|
|
147
|
+
});
|
|
148
|
+
let history = historyRef.current;
|
|
149
|
+
let [state, setStateImpl] = React$1.useState({
|
|
150
|
+
action: history.action,
|
|
151
|
+
location: history.location
|
|
152
|
+
});
|
|
153
|
+
let setState = React$1.useCallback((newState) => {
|
|
154
|
+
if (useTransitions === false) setStateImpl(newState);
|
|
155
|
+
else React$1.startTransition(() => setStateImpl(newState));
|
|
156
|
+
}, [useTransitions]);
|
|
157
|
+
React$1.useLayoutEffect(() => history.listen(setState), [history, setState]);
|
|
158
|
+
return /* @__PURE__ */ React$1.createElement(Router, {
|
|
159
|
+
basename,
|
|
160
|
+
children,
|
|
161
|
+
location: state.location,
|
|
162
|
+
navigationType: state.action,
|
|
163
|
+
navigator: history,
|
|
164
|
+
useTransitions
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* A declarative {@link Router | `<Router>`} that stores the location in the
|
|
169
|
+
* [`hash`](https://developer.mozilla.org/en-US/docs/Web/API/URL/hash) portion
|
|
170
|
+
* of the URL so it is not sent to the server.
|
|
171
|
+
*
|
|
172
|
+
* @public
|
|
173
|
+
* @category Declarative Routers
|
|
174
|
+
* @mode declarative
|
|
175
|
+
* @param props Props
|
|
176
|
+
* @param {HashRouterProps.basename} props.basename n/a
|
|
177
|
+
* @param {HashRouterProps.children} props.children n/a
|
|
178
|
+
* @param {HashRouterProps.useTransitions} props.useTransitions n/a
|
|
179
|
+
* @param {HashRouterProps.window} props.window n/a
|
|
180
|
+
* @returns A declarative {@link Router | `<Router>`} using the URL [`hash`](https://developer.mozilla.org/en-US/docs/Web/API/URL/hash)
|
|
181
|
+
* for client-side routing.
|
|
182
|
+
*/
|
|
183
|
+
function HashRouter({ basename, children, useTransitions, window }) {
|
|
184
|
+
let historyRef = React$1.useRef(null);
|
|
185
|
+
if (historyRef.current == null) historyRef.current = createHashHistory({
|
|
186
|
+
window,
|
|
187
|
+
v5Compat: true
|
|
188
|
+
});
|
|
189
|
+
let history = historyRef.current;
|
|
190
|
+
let [state, setStateImpl] = React$1.useState({
|
|
191
|
+
action: history.action,
|
|
192
|
+
location: history.location
|
|
193
|
+
});
|
|
194
|
+
let setState = React$1.useCallback((newState) => {
|
|
195
|
+
if (useTransitions === false) setStateImpl(newState);
|
|
196
|
+
else React$1.startTransition(() => setStateImpl(newState));
|
|
197
|
+
}, [useTransitions]);
|
|
198
|
+
React$1.useLayoutEffect(() => history.listen(setState), [history, setState]);
|
|
199
|
+
return /* @__PURE__ */ React$1.createElement(Router, {
|
|
200
|
+
basename,
|
|
201
|
+
children,
|
|
202
|
+
location: state.location,
|
|
203
|
+
navigationType: state.action,
|
|
204
|
+
navigator: history,
|
|
205
|
+
useTransitions
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* A declarative {@link Router | `<Router>`} that accepts a pre-instantiated
|
|
210
|
+
* `history` object.
|
|
211
|
+
* It's important to note that using your own `history` object is highly discouraged
|
|
212
|
+
* and may add two versions of the `history` library to your bundles unless you use
|
|
213
|
+
* the same version of the `history` library that React Router uses internally.
|
|
214
|
+
*
|
|
215
|
+
* @name unstable_HistoryRouter
|
|
216
|
+
* @public
|
|
217
|
+
* @category Declarative Routers
|
|
218
|
+
* @mode declarative
|
|
219
|
+
* @param props Props
|
|
220
|
+
* @param {HistoryRouterProps.basename} props.basename n/a
|
|
221
|
+
* @param {HistoryRouterProps.children} props.children n/a
|
|
222
|
+
* @param {HistoryRouterProps.history} props.history n/a
|
|
223
|
+
* @param {HistoryRouterProps.useTransitions} props.useTransitions n/a
|
|
224
|
+
* @returns A declarative {@link Router | `<Router>`} using the provided history
|
|
225
|
+
* implementation for client-side routing.
|
|
226
|
+
*/
|
|
227
|
+
function HistoryRouter({ basename, children, history, useTransitions }) {
|
|
228
|
+
let [state, setStateImpl] = React$1.useState({
|
|
229
|
+
action: history.action,
|
|
230
|
+
location: history.location
|
|
231
|
+
});
|
|
232
|
+
let setState = React$1.useCallback((newState) => {
|
|
233
|
+
if (useTransitions === false) setStateImpl(newState);
|
|
234
|
+
else React$1.startTransition(() => setStateImpl(newState));
|
|
235
|
+
}, [useTransitions]);
|
|
236
|
+
React$1.useLayoutEffect(() => history.listen(setState), [history, setState]);
|
|
237
|
+
return /* @__PURE__ */ React$1.createElement(Router, {
|
|
238
|
+
basename,
|
|
239
|
+
children,
|
|
240
|
+
location: state.location,
|
|
241
|
+
navigationType: state.action,
|
|
242
|
+
navigator: history,
|
|
243
|
+
useTransitions
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
HistoryRouter.displayName = "unstable_HistoryRouter";
|
|
247
|
+
const ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
|
|
248
|
+
/**
|
|
249
|
+
* A progressively enhanced [`<a href>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a)
|
|
250
|
+
* wrapper to enable navigation with client-side routing.
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* import { Link } from "react-router";
|
|
254
|
+
*
|
|
255
|
+
* <Link to="/dashboard">Dashboard</Link>;
|
|
256
|
+
*
|
|
257
|
+
* <Link
|
|
258
|
+
* to={{
|
|
259
|
+
* pathname: "/some/path",
|
|
260
|
+
* search: "?query=string",
|
|
261
|
+
* hash: "#hash",
|
|
262
|
+
* }}
|
|
263
|
+
* />;
|
|
264
|
+
*
|
|
265
|
+
* @public
|
|
266
|
+
* @category Components
|
|
267
|
+
* @param {LinkProps.discover} props.discover [modes: framework] n/a
|
|
268
|
+
* @param {LinkProps.prefetch} props.prefetch [modes: framework] n/a
|
|
269
|
+
* @param {LinkProps.preventScrollReset} props.preventScrollReset [modes: framework, data] n/a
|
|
270
|
+
* @param {LinkProps.relative} props.relative n/a
|
|
271
|
+
* @param {LinkProps.reloadDocument} props.reloadDocument n/a
|
|
272
|
+
* @param {LinkProps.replace} props.replace n/a
|
|
273
|
+
* @param {LinkProps.state} props.state n/a
|
|
274
|
+
* @param {LinkProps.to} props.to n/a
|
|
275
|
+
* @param {LinkProps.viewTransition} props.viewTransition [modes: framework, data] n/a
|
|
276
|
+
* @param {LinkProps.defaultShouldRevalidate} props.defaultShouldRevalidate n/a
|
|
277
|
+
* @param {LinkProps.mask} props.mask [modes: framework, data] n/a
|
|
278
|
+
*/
|
|
279
|
+
const Link = React$1.forwardRef(function LinkWithRef({ onClick, discover = "render", prefetch = "none", relative, reloadDocument, replace, mask, state, target, to, preventScrollReset, viewTransition, defaultShouldRevalidate, ...rest }, forwardedRef) {
|
|
280
|
+
let { basename, navigator, useTransitions } = React$1.useContext(NavigationContext);
|
|
281
|
+
let isAbsolute = typeof to === "string" && ABSOLUTE_URL_REGEX.test(to);
|
|
282
|
+
let parsed = parseToInfo(to, basename);
|
|
283
|
+
to = parsed.to;
|
|
284
|
+
let href = useHref(to, { relative });
|
|
285
|
+
let location = useLocation();
|
|
286
|
+
let maskedHref = null;
|
|
287
|
+
if (mask) {
|
|
288
|
+
let resolved = resolveTo(mask, [], location.mask ? location.mask.pathname : "/", true);
|
|
289
|
+
if (basename !== "/") resolved.pathname = resolved.pathname === "/" ? basename : joinPaths([basename, resolved.pathname]);
|
|
290
|
+
maskedHref = navigator.createHref(resolved);
|
|
291
|
+
}
|
|
292
|
+
let [shouldPrefetch, prefetchRef, prefetchHandlers] = usePrefetchBehavior(prefetch, rest);
|
|
293
|
+
let internalOnClick = useLinkClickHandler(to, {
|
|
294
|
+
replace,
|
|
295
|
+
mask,
|
|
296
|
+
state,
|
|
297
|
+
target,
|
|
298
|
+
preventScrollReset,
|
|
299
|
+
relative,
|
|
300
|
+
viewTransition,
|
|
301
|
+
defaultShouldRevalidate,
|
|
302
|
+
useTransitions
|
|
303
|
+
});
|
|
304
|
+
function handleClick(event) {
|
|
305
|
+
if (onClick) onClick(event);
|
|
306
|
+
if (!event.defaultPrevented) internalOnClick(event);
|
|
307
|
+
}
|
|
308
|
+
let isSpaLink = !(parsed.isExternal || reloadDocument);
|
|
309
|
+
let link = /* @__PURE__ */ React$1.createElement("a", {
|
|
310
|
+
...rest,
|
|
311
|
+
...prefetchHandlers,
|
|
312
|
+
href: (isSpaLink ? maskedHref : void 0) || parsed.absoluteURL || href,
|
|
313
|
+
onClick: isSpaLink ? handleClick : onClick,
|
|
314
|
+
ref: mergeRefs(forwardedRef, prefetchRef),
|
|
315
|
+
target,
|
|
316
|
+
"data-discover": !isAbsolute && discover === "render" ? "true" : void 0
|
|
317
|
+
});
|
|
318
|
+
return shouldPrefetch && !isAbsolute ? /* @__PURE__ */ React$1.createElement(React$1.Fragment, null, link, /* @__PURE__ */ React$1.createElement(PrefetchPageLinks, { page: href })) : link;
|
|
319
|
+
});
|
|
320
|
+
Link.displayName = "Link";
|
|
321
|
+
/**
|
|
322
|
+
* Wraps {@link Link | `<Link>`} with additional props for styling active and
|
|
323
|
+
* pending states.
|
|
324
|
+
*
|
|
325
|
+
* - Automatically applies classes to the link based on its `active` and `pending`
|
|
326
|
+
* states, see {@link NavLinkProps.className}
|
|
327
|
+
* - Note that `pending` is only available with Framework and Data modes.
|
|
328
|
+
* - Automatically applies `aria-current="page"` to the link when the link is active.
|
|
329
|
+
* See [`aria-current`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-current)
|
|
330
|
+
* on MDN.
|
|
331
|
+
* - States are additionally available through the className, style, and children
|
|
332
|
+
* render props. See {@link NavLinkRenderProps}.
|
|
333
|
+
*
|
|
334
|
+
* @example
|
|
335
|
+
* <NavLink to="/message">Messages</NavLink>
|
|
336
|
+
*
|
|
337
|
+
* // Using render props
|
|
338
|
+
* <NavLink
|
|
339
|
+
* to="/messages"
|
|
340
|
+
* className={({ isActive, isPending }) =>
|
|
341
|
+
* isPending ? "pending" : isActive ? "active" : ""
|
|
342
|
+
* }
|
|
343
|
+
* >
|
|
344
|
+
* Messages
|
|
345
|
+
* </NavLink>
|
|
346
|
+
*
|
|
347
|
+
* @public
|
|
348
|
+
* @category Components
|
|
349
|
+
* @param {NavLinkProps.caseSensitive} props.caseSensitive n/a
|
|
350
|
+
* @param {NavLinkProps.children} props.children n/a
|
|
351
|
+
* @param {NavLinkProps.className} props.className n/a
|
|
352
|
+
* @param {NavLinkProps.discover} props.discover [modes: framework] n/a
|
|
353
|
+
* @param {NavLinkProps.end} props.end n/a
|
|
354
|
+
* @param {NavLinkProps.prefetch} props.prefetch [modes: framework] n/a
|
|
355
|
+
* @param {NavLinkProps.preventScrollReset} props.preventScrollReset [modes: framework, data] n/a
|
|
356
|
+
* @param {NavLinkProps.relative} props.relative n/a
|
|
357
|
+
* @param {NavLinkProps.reloadDocument} props.reloadDocument n/a
|
|
358
|
+
* @param {NavLinkProps.replace} props.replace n/a
|
|
359
|
+
* @param {NavLinkProps.state} props.state n/a
|
|
360
|
+
* @param {NavLinkProps.style} props.style n/a
|
|
361
|
+
* @param {NavLinkProps.to} props.to n/a
|
|
362
|
+
* @param {NavLinkProps.viewTransition} props.viewTransition [modes: framework, data] n/a
|
|
363
|
+
*/
|
|
364
|
+
const NavLink = React$1.forwardRef(function NavLinkWithRef({ "aria-current": ariaCurrentProp = "page", caseSensitive = false, className: classNameProp = "", end = false, style: styleProp, to, viewTransition, children, ...rest }, ref) {
|
|
365
|
+
let path = useResolvedPath(to, { relative: rest.relative });
|
|
366
|
+
let location = useLocation();
|
|
367
|
+
let routerState = React$1.useContext(DataRouterStateContext);
|
|
368
|
+
let { navigator, basename } = React$1.useContext(NavigationContext);
|
|
369
|
+
let isTransitioning = routerState != null && useViewTransitionState(path) && viewTransition === true;
|
|
370
|
+
let toPathname = navigator.encodeLocation ? navigator.encodeLocation(path).pathname : path.pathname;
|
|
371
|
+
let locationPathname = location.pathname;
|
|
372
|
+
let nextLocationPathname = routerState && routerState.navigation && routerState.navigation.location ? routerState.navigation.location.pathname : null;
|
|
373
|
+
if (!caseSensitive) {
|
|
374
|
+
locationPathname = locationPathname.toLowerCase();
|
|
375
|
+
nextLocationPathname = nextLocationPathname ? nextLocationPathname.toLowerCase() : null;
|
|
376
|
+
toPathname = toPathname.toLowerCase();
|
|
377
|
+
}
|
|
378
|
+
if (nextLocationPathname && basename) nextLocationPathname = stripBasename(nextLocationPathname, basename) || nextLocationPathname;
|
|
379
|
+
const endSlashPosition = toPathname !== "/" && toPathname.endsWith("/") ? toPathname.length - 1 : toPathname.length;
|
|
380
|
+
let isActive = locationPathname === toPathname || !end && locationPathname.startsWith(toPathname) && locationPathname.charAt(endSlashPosition) === "/";
|
|
381
|
+
let isPending = nextLocationPathname != null && (nextLocationPathname === toPathname || !end && nextLocationPathname.startsWith(toPathname) && nextLocationPathname.charAt(toPathname.length) === "/");
|
|
382
|
+
let renderProps = {
|
|
383
|
+
isActive,
|
|
384
|
+
isPending,
|
|
385
|
+
isTransitioning
|
|
386
|
+
};
|
|
387
|
+
let ariaCurrent = isActive ? ariaCurrentProp : void 0;
|
|
388
|
+
let className;
|
|
389
|
+
if (typeof classNameProp === "function") className = classNameProp(renderProps);
|
|
390
|
+
else className = [
|
|
391
|
+
classNameProp,
|
|
392
|
+
isActive ? "active" : null,
|
|
393
|
+
isPending ? "pending" : null,
|
|
394
|
+
isTransitioning ? "transitioning" : null
|
|
395
|
+
].filter(Boolean).join(" ");
|
|
396
|
+
let style = typeof styleProp === "function" ? styleProp(renderProps) : styleProp;
|
|
397
|
+
return /* @__PURE__ */ React$1.createElement(Link, {
|
|
398
|
+
...rest,
|
|
399
|
+
"aria-current": ariaCurrent,
|
|
400
|
+
className,
|
|
401
|
+
ref,
|
|
402
|
+
style,
|
|
403
|
+
to,
|
|
404
|
+
viewTransition
|
|
405
|
+
}, typeof children === "function" ? children(renderProps) : children);
|
|
406
|
+
});
|
|
407
|
+
NavLink.displayName = "NavLink";
|
|
408
|
+
/**
|
|
409
|
+
* A progressively enhanced HTML [`<form>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form)
|
|
410
|
+
* that submits data to actions via [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/fetch),
|
|
411
|
+
* activating pending states in {@link useNavigation} which enables advanced
|
|
412
|
+
* user interfaces beyond a basic HTML [`<form>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form).
|
|
413
|
+
* After a form's `action` completes, all data on the page is automatically
|
|
414
|
+
* revalidated to keep the UI in sync with the data.
|
|
415
|
+
*
|
|
416
|
+
* Because it uses the HTML form API, server rendered pages are interactive at a
|
|
417
|
+
* basic level before JavaScript loads. Instead of React Router managing the
|
|
418
|
+
* submission, the browser manages the submission as well as the pending states
|
|
419
|
+
* (like the spinning favicon). After JavaScript loads, React Router takes over
|
|
420
|
+
* enabling web application user experiences.
|
|
421
|
+
*
|
|
422
|
+
* `Form` is most useful for submissions that should also change the URL or
|
|
423
|
+
* otherwise add an entry to the browser history stack. For forms that shouldn't
|
|
424
|
+
* manipulate the browser [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History)
|
|
425
|
+
* stack, use {@link FetcherWithComponents.Form | `<fetcher.Form>`}.
|
|
426
|
+
*
|
|
427
|
+
* @example
|
|
428
|
+
* import { Form } from "react-router";
|
|
429
|
+
*
|
|
430
|
+
* function NewEvent() {
|
|
431
|
+
* return (
|
|
432
|
+
* <Form action="/events" method="post">
|
|
433
|
+
* <input name="title" type="text" />
|
|
434
|
+
* <input name="description" type="text" />
|
|
435
|
+
* </Form>
|
|
436
|
+
* );
|
|
437
|
+
* }
|
|
438
|
+
*
|
|
439
|
+
* @public
|
|
440
|
+
* @category Components
|
|
441
|
+
* @mode framework
|
|
442
|
+
* @mode data
|
|
443
|
+
* @param {FormProps.action} action n/a
|
|
444
|
+
* @param {FormProps.discover} discover n/a
|
|
445
|
+
* @param {FormProps.encType} encType n/a
|
|
446
|
+
* @param {FormProps.fetcherKey} fetcherKey n/a
|
|
447
|
+
* @param {FormProps.method} method n/a
|
|
448
|
+
* @param {FormProps.navigate} navigate n/a
|
|
449
|
+
* @param {FormProps.preventScrollReset} preventScrollReset n/a
|
|
450
|
+
* @param {FormProps.relative} relative n/a
|
|
451
|
+
* @param {FormProps.reloadDocument} reloadDocument n/a
|
|
452
|
+
* @param {FormProps.replace} replace n/a
|
|
453
|
+
* @param {FormProps.state} state n/a
|
|
454
|
+
* @param {FormProps.viewTransition} viewTransition n/a
|
|
455
|
+
* @param {FormProps.defaultShouldRevalidate} defaultShouldRevalidate n/a
|
|
456
|
+
* @returns A progressively enhanced [`<form>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form) component
|
|
457
|
+
*/
|
|
458
|
+
const Form = React$1.forwardRef(({ discover = "render", fetcherKey, navigate, reloadDocument, replace, state, method = "get", action, onSubmit, relative, preventScrollReset, viewTransition, defaultShouldRevalidate, ...props }, forwardedRef) => {
|
|
459
|
+
let { useTransitions } = React$1.useContext(NavigationContext);
|
|
460
|
+
let submit = useSubmit();
|
|
461
|
+
let formAction = useFormAction(action, { relative });
|
|
462
|
+
let formMethod = method.toLowerCase() === "get" ? "get" : "post";
|
|
463
|
+
let isAbsolute = typeof action === "string" && ABSOLUTE_URL_REGEX.test(action);
|
|
464
|
+
let submitHandler = (event) => {
|
|
465
|
+
onSubmit && onSubmit(event);
|
|
466
|
+
if (event.defaultPrevented) return;
|
|
467
|
+
event.preventDefault();
|
|
468
|
+
let submitter = event.nativeEvent.submitter;
|
|
469
|
+
let submitMethod = submitter?.getAttribute("formmethod") || method;
|
|
470
|
+
let doSubmit = () => submit(submitter || event.currentTarget, {
|
|
471
|
+
fetcherKey,
|
|
472
|
+
method: submitMethod,
|
|
473
|
+
navigate,
|
|
474
|
+
replace,
|
|
475
|
+
state,
|
|
476
|
+
relative,
|
|
477
|
+
preventScrollReset,
|
|
478
|
+
viewTransition,
|
|
479
|
+
defaultShouldRevalidate
|
|
480
|
+
});
|
|
481
|
+
if (useTransitions && navigate !== false) React$1.startTransition(() => doSubmit());
|
|
482
|
+
else doSubmit();
|
|
483
|
+
};
|
|
484
|
+
return /* @__PURE__ */ React$1.createElement("form", {
|
|
485
|
+
ref: forwardedRef,
|
|
486
|
+
method: formMethod,
|
|
487
|
+
action: formAction,
|
|
488
|
+
onSubmit: reloadDocument ? onSubmit : submitHandler,
|
|
489
|
+
...props,
|
|
490
|
+
"data-discover": !isAbsolute && discover === "render" ? "true" : void 0
|
|
491
|
+
});
|
|
492
|
+
});
|
|
493
|
+
Form.displayName = "Form";
|
|
494
|
+
/**
|
|
495
|
+
* Emulates the browser's scroll restoration on location changes. Apps should only render one of these, right before the {@link Scripts} component.
|
|
496
|
+
*
|
|
497
|
+
* ```tsx
|
|
498
|
+
* import { ScrollRestoration } from "react-router";
|
|
499
|
+
*
|
|
500
|
+
* export default function Root() {
|
|
501
|
+
* return (
|
|
502
|
+
* <html>
|
|
503
|
+
* <body>
|
|
504
|
+
* <ScrollRestoration />
|
|
505
|
+
* <Scripts />
|
|
506
|
+
* </body>
|
|
507
|
+
* </html>
|
|
508
|
+
* );
|
|
509
|
+
* }
|
|
510
|
+
* ```
|
|
511
|
+
*
|
|
512
|
+
* This component renders an inline `<script>` to prevent scroll flashing. The `nonce` prop will be passed down to the script tag to allow CSP nonce usage.
|
|
513
|
+
*
|
|
514
|
+
* ```tsx
|
|
515
|
+
* <ScrollRestoration nonce={cspNonce} />
|
|
516
|
+
* ```
|
|
517
|
+
*
|
|
518
|
+
* @public
|
|
519
|
+
* @category Components
|
|
520
|
+
* @mode framework
|
|
521
|
+
* @mode data
|
|
522
|
+
* @param props Props
|
|
523
|
+
* @param {ScrollRestorationProps.getKey} props.getKey n/a
|
|
524
|
+
* @param {ScriptsProps.nonce} props.nonce n/a
|
|
525
|
+
* @param {ScrollRestorationProps.storageKey} props.storageKey n/a
|
|
526
|
+
* @returns A [`<script>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script)
|
|
527
|
+
* tag that restores scroll positions on navigation.
|
|
528
|
+
*/
|
|
529
|
+
function ScrollRestoration({ getKey, storageKey, ...props }) {
|
|
530
|
+
let remixContext = React$1.useContext(FrameworkContext);
|
|
531
|
+
let { basename } = React$1.useContext(NavigationContext);
|
|
532
|
+
let location = useLocation();
|
|
533
|
+
let matches = useMatches();
|
|
534
|
+
useScrollRestoration({
|
|
535
|
+
getKey,
|
|
536
|
+
storageKey
|
|
537
|
+
});
|
|
538
|
+
let ssrKey = React$1.useMemo(() => {
|
|
539
|
+
if (!remixContext || !getKey) return null;
|
|
540
|
+
let userKey = getScrollRestorationKey(location, matches, basename, getKey);
|
|
541
|
+
return userKey !== location.key ? userKey : null;
|
|
542
|
+
}, []);
|
|
543
|
+
if (!remixContext || remixContext.isSpaMode) return null;
|
|
544
|
+
let restoreScroll = ((storageKey, restoreKey) => {
|
|
545
|
+
if (!window.history.state || !window.history.state.key) {
|
|
546
|
+
let key = Math.random().toString(32).slice(2);
|
|
547
|
+
window.history.replaceState({ key }, "");
|
|
548
|
+
}
|
|
549
|
+
try {
|
|
550
|
+
let storedY = JSON.parse(sessionStorage.getItem(storageKey) || "{}")[restoreKey || window.history.state.key];
|
|
551
|
+
if (typeof storedY === "number") window.scrollTo(0, storedY);
|
|
552
|
+
} catch (error) {
|
|
553
|
+
console.error(error);
|
|
554
|
+
sessionStorage.removeItem(storageKey);
|
|
555
|
+
}
|
|
556
|
+
}).toString();
|
|
557
|
+
return /* @__PURE__ */ React$1.createElement("script", {
|
|
558
|
+
...props,
|
|
559
|
+
suppressHydrationWarning: true,
|
|
560
|
+
dangerouslySetInnerHTML: { __html: `(${restoreScroll})(${escapeHtml(JSON.stringify(storageKey || SCROLL_RESTORATION_STORAGE_KEY))}, ${escapeHtml(JSON.stringify(ssrKey))})` }
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
ScrollRestoration.displayName = "ScrollRestoration";
|
|
564
|
+
function getDataRouterConsoleError(hookName) {
|
|
565
|
+
return `${hookName} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`;
|
|
566
|
+
}
|
|
567
|
+
function useDataRouterContext(hookName) {
|
|
568
|
+
let ctx = React$1.useContext(DataRouterContext);
|
|
569
|
+
invariant(ctx, getDataRouterConsoleError(hookName));
|
|
570
|
+
return ctx;
|
|
571
|
+
}
|
|
572
|
+
function useDataRouterState(hookName) {
|
|
573
|
+
let state = React$1.useContext(DataRouterStateContext);
|
|
574
|
+
invariant(state, getDataRouterConsoleError(hookName));
|
|
575
|
+
return state;
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* Handles the click behavior for router {@link Link | `<Link>`} components.This
|
|
579
|
+
* is useful if you need to create custom {@link Link | `<Link>`} components with
|
|
580
|
+
* the same click behavior we use in our exported {@link Link | `<Link>`}.
|
|
581
|
+
*
|
|
582
|
+
* @public
|
|
583
|
+
* @category Hooks
|
|
584
|
+
* @param to The URL to navigate to, can be a string or a partial {@link Path}.
|
|
585
|
+
* @param options Options
|
|
586
|
+
* @param options.preventScrollReset Whether to prevent the scroll position from
|
|
587
|
+
* being reset to the top of the viewport on completion of the navigation when
|
|
588
|
+
* using the {@link ScrollRestoration} component. Defaults to `false`.
|
|
589
|
+
* @param options.relative The {@link RelativeRoutingType | relative routing type}
|
|
590
|
+
* to use for the link. Defaults to `"route"`.
|
|
591
|
+
* @param options.replace Whether to replace the current [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History)
|
|
592
|
+
* entry instead of pushing a new one. Defaults to `false`.
|
|
593
|
+
* @param options.state The state to add to the [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History)
|
|
594
|
+
* entry for this navigation. Defaults to `undefined`.
|
|
595
|
+
* @param options.target The target attribute for the link. Defaults to `undefined`.
|
|
596
|
+
* @param options.viewTransition Enables a [View Transition](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API)
|
|
597
|
+
* for this navigation. To apply specific styles during the transition, see
|
|
598
|
+
* {@link useViewTransitionState}. Defaults to `false`.
|
|
599
|
+
* @param options.defaultShouldRevalidate Specify the default revalidation
|
|
600
|
+
* behavior for the navigation. Defaults to `true`.
|
|
601
|
+
* @param options.mask Masked location to display in the browser instead
|
|
602
|
+
* of the router location. Defaults to `undefined`.
|
|
603
|
+
* @param options.useTransitions Wraps the navigation in
|
|
604
|
+
* [`React.startTransition`](https://react.dev/reference/react/startTransition)
|
|
605
|
+
* for concurrent rendering. Defaults to `false`.
|
|
606
|
+
* @returns A click handler function that can be used in a custom {@link Link} component.
|
|
607
|
+
*/
|
|
608
|
+
function useLinkClickHandler(to, { target, replace: replaceProp, mask, state, preventScrollReset, relative, viewTransition, defaultShouldRevalidate, useTransitions } = {}) {
|
|
609
|
+
let navigate = useNavigate();
|
|
610
|
+
let location = useLocation();
|
|
611
|
+
let path = useResolvedPath(to, { relative });
|
|
612
|
+
return React$1.useCallback((event) => {
|
|
613
|
+
if (shouldProcessLinkClick(event, target)) {
|
|
614
|
+
event.preventDefault();
|
|
615
|
+
let replace = replaceProp !== void 0 ? replaceProp : createPath(location) === createPath(path);
|
|
616
|
+
let doNavigate = () => navigate(to, {
|
|
617
|
+
replace,
|
|
618
|
+
mask,
|
|
619
|
+
state,
|
|
620
|
+
preventScrollReset,
|
|
621
|
+
relative,
|
|
622
|
+
viewTransition,
|
|
623
|
+
defaultShouldRevalidate
|
|
624
|
+
});
|
|
625
|
+
if (useTransitions) React$1.startTransition(() => doNavigate());
|
|
626
|
+
else doNavigate();
|
|
627
|
+
}
|
|
628
|
+
}, [
|
|
629
|
+
location,
|
|
630
|
+
navigate,
|
|
631
|
+
path,
|
|
632
|
+
replaceProp,
|
|
633
|
+
mask,
|
|
634
|
+
state,
|
|
635
|
+
target,
|
|
636
|
+
to,
|
|
637
|
+
preventScrollReset,
|
|
638
|
+
relative,
|
|
639
|
+
viewTransition,
|
|
640
|
+
defaultShouldRevalidate,
|
|
641
|
+
useTransitions
|
|
642
|
+
]);
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Returns a tuple of the current URL's [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)
|
|
646
|
+
* and a function to update them. Setting the search params causes a navigation.
|
|
647
|
+
*
|
|
648
|
+
* ```tsx
|
|
649
|
+
* import { useSearchParams } from "react-router";
|
|
650
|
+
*
|
|
651
|
+
* export function SomeComponent() {
|
|
652
|
+
* const [searchParams, setSearchParams] = useSearchParams();
|
|
653
|
+
* // ...
|
|
654
|
+
* }
|
|
655
|
+
* ```
|
|
656
|
+
*
|
|
657
|
+
* ### `setSearchParams` function
|
|
658
|
+
*
|
|
659
|
+
* The second element of the tuple is a function that can be used to update the
|
|
660
|
+
* search params. It accepts the same types as `defaultInit` and will cause a
|
|
661
|
+
* navigation to the new URL.
|
|
662
|
+
*
|
|
663
|
+
* ```tsx
|
|
664
|
+
* let [searchParams, setSearchParams] = useSearchParams();
|
|
665
|
+
*
|
|
666
|
+
* // a search param string
|
|
667
|
+
* setSearchParams("?tab=1");
|
|
668
|
+
*
|
|
669
|
+
* // a shorthand object
|
|
670
|
+
* setSearchParams({ tab: "1" });
|
|
671
|
+
*
|
|
672
|
+
* // object keys can be arrays for multiple values on the key
|
|
673
|
+
* setSearchParams({ brand: ["nike", "reebok"] });
|
|
674
|
+
*
|
|
675
|
+
* // an array of tuples
|
|
676
|
+
* setSearchParams([["tab", "1"]]);
|
|
677
|
+
*
|
|
678
|
+
* // a `URLSearchParams` object
|
|
679
|
+
* setSearchParams(new URLSearchParams("?tab=1"));
|
|
680
|
+
* ```
|
|
681
|
+
*
|
|
682
|
+
* It also supports a function callback like React's
|
|
683
|
+
* [`setState`](https://react.dev/reference/react/useState#setstate):
|
|
684
|
+
*
|
|
685
|
+
* ```tsx
|
|
686
|
+
* setSearchParams((searchParams) => {
|
|
687
|
+
* searchParams.set("tab", "2");
|
|
688
|
+
* return searchParams;
|
|
689
|
+
* });
|
|
690
|
+
* ```
|
|
691
|
+
*
|
|
692
|
+
* <docs-warning>The function callback version of `setSearchParams` does not support
|
|
693
|
+
* the [queueing](https://react.dev/reference/react/useState#setstate-parameters)
|
|
694
|
+
* logic that React's `setState` implements. Multiple calls to `setSearchParams`
|
|
695
|
+
* in the same tick will not build on the prior value. If you need this behavior,
|
|
696
|
+
* you can use `setState` manually.</docs-warning>
|
|
697
|
+
*
|
|
698
|
+
* ### Notes
|
|
699
|
+
*
|
|
700
|
+
* Note that `searchParams` is a stable reference, so you can reliably use it
|
|
701
|
+
* as a dependency in React's [`useEffect`](https://react.dev/reference/react/useEffect)
|
|
702
|
+
* hooks.
|
|
703
|
+
*
|
|
704
|
+
* ```tsx
|
|
705
|
+
* useEffect(() => {
|
|
706
|
+
* console.log(searchParams.get("tab"));
|
|
707
|
+
* }, [searchParams]);
|
|
708
|
+
* ```
|
|
709
|
+
*
|
|
710
|
+
* However, this also means it's mutable. If you change the object without
|
|
711
|
+
* calling `setSearchParams`, its values will change between renders if some
|
|
712
|
+
* other state causes the component to re-render and URL will not reflect the
|
|
713
|
+
* values.
|
|
714
|
+
*
|
|
715
|
+
* @public
|
|
716
|
+
* @category Hooks
|
|
717
|
+
* @param defaultInit
|
|
718
|
+
* You can initialize the search params with a default value, though it **will
|
|
719
|
+
* not** change the URL on the first render.
|
|
720
|
+
*
|
|
721
|
+
* ```tsx
|
|
722
|
+
* // a search param string
|
|
723
|
+
* useSearchParams("?tab=1");
|
|
724
|
+
*
|
|
725
|
+
* // a shorthand object
|
|
726
|
+
* useSearchParams({ tab: "1" });
|
|
727
|
+
*
|
|
728
|
+
* // object keys can be arrays for multiple values on the key
|
|
729
|
+
* useSearchParams({ brand: ["nike", "reebok"] });
|
|
730
|
+
*
|
|
731
|
+
* // an array of tuples
|
|
732
|
+
* useSearchParams([["tab", "1"]]);
|
|
733
|
+
*
|
|
734
|
+
* // a `URLSearchParams` object
|
|
735
|
+
* useSearchParams(new URLSearchParams("?tab=1"));
|
|
736
|
+
* ```
|
|
737
|
+
* @returns A tuple of the current [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)
|
|
738
|
+
* and a function to update them.
|
|
739
|
+
*/
|
|
740
|
+
function useSearchParams(defaultInit) {
|
|
741
|
+
warning(typeof URLSearchParams !== "undefined", "You cannot use the `useSearchParams` hook in a browser that does not support the URLSearchParams API. If you need to support Internet Explorer 11, we recommend you load a polyfill such as https://github.com/ungap/url-search-params.");
|
|
742
|
+
let defaultSearchParamsRef = React$1.useRef(createSearchParams(defaultInit));
|
|
743
|
+
let hasSetSearchParamsRef = React$1.useRef(false);
|
|
744
|
+
let location = useLocation();
|
|
745
|
+
let searchParams = React$1.useMemo(() => getSearchParamsForLocation(location.search, hasSetSearchParamsRef.current ? null : defaultSearchParamsRef.current), [location.search]);
|
|
746
|
+
let navigate = useNavigate();
|
|
747
|
+
return [searchParams, React$1.useCallback((nextInit, navigateOptions) => {
|
|
748
|
+
const newSearchParams = createSearchParams(typeof nextInit === "function" ? nextInit(new URLSearchParams(searchParams)) : nextInit);
|
|
749
|
+
hasSetSearchParamsRef.current = true;
|
|
750
|
+
navigate("?" + newSearchParams, navigateOptions);
|
|
751
|
+
}, [navigate, searchParams])];
|
|
752
|
+
}
|
|
753
|
+
let fetcherId = 0;
|
|
754
|
+
let getUniqueFetcherId = () => `__${String(++fetcherId)}__`;
|
|
755
|
+
/**
|
|
756
|
+
* The imperative version of {@link Form | `<Form>`} that lets you submit a form
|
|
757
|
+
* from code instead of a user interaction.
|
|
758
|
+
*
|
|
759
|
+
* @example
|
|
760
|
+
* import { useSubmit } from "react-router";
|
|
761
|
+
*
|
|
762
|
+
* function SomeComponent() {
|
|
763
|
+
* const submit = useSubmit();
|
|
764
|
+
* return (
|
|
765
|
+
* <Form onChange={(event) => submit(event.currentTarget)} />
|
|
766
|
+
* );
|
|
767
|
+
* }
|
|
768
|
+
*
|
|
769
|
+
* @public
|
|
770
|
+
* @category Hooks
|
|
771
|
+
* @mode framework
|
|
772
|
+
* @mode data
|
|
773
|
+
* @returns A function that can be called to submit a {@link Form} imperatively.
|
|
774
|
+
*/
|
|
775
|
+
function useSubmit() {
|
|
776
|
+
let { router } = useDataRouterContext("useSubmit");
|
|
777
|
+
let { basename } = React$1.useContext(NavigationContext);
|
|
778
|
+
let currentRouteId = useRouteId();
|
|
779
|
+
let routerFetch = router.fetch;
|
|
780
|
+
let routerNavigate = router.navigate;
|
|
781
|
+
return React$1.useCallback(async (target, options = {}) => {
|
|
782
|
+
let { action, method, encType, formData, body } = getFormSubmissionInfo(target, basename);
|
|
783
|
+
if (options.navigate === false) await routerFetch(options.fetcherKey || getUniqueFetcherId(), currentRouteId, options.action || action, {
|
|
784
|
+
defaultShouldRevalidate: options.defaultShouldRevalidate,
|
|
785
|
+
preventScrollReset: options.preventScrollReset,
|
|
786
|
+
formData,
|
|
787
|
+
body,
|
|
788
|
+
formMethod: options.method || method,
|
|
789
|
+
formEncType: options.encType || encType,
|
|
790
|
+
flushSync: options.flushSync
|
|
791
|
+
});
|
|
792
|
+
else await routerNavigate(options.action || action, {
|
|
793
|
+
defaultShouldRevalidate: options.defaultShouldRevalidate,
|
|
794
|
+
preventScrollReset: options.preventScrollReset,
|
|
795
|
+
formData,
|
|
796
|
+
body,
|
|
797
|
+
formMethod: options.method || method,
|
|
798
|
+
formEncType: options.encType || encType,
|
|
799
|
+
replace: options.replace,
|
|
800
|
+
state: options.state,
|
|
801
|
+
fromRouteId: currentRouteId,
|
|
802
|
+
flushSync: options.flushSync,
|
|
803
|
+
viewTransition: options.viewTransition
|
|
804
|
+
});
|
|
805
|
+
}, [
|
|
806
|
+
routerFetch,
|
|
807
|
+
routerNavigate,
|
|
808
|
+
basename,
|
|
809
|
+
currentRouteId
|
|
810
|
+
]);
|
|
811
|
+
}
|
|
812
|
+
/**
|
|
813
|
+
* Resolves the URL to the closest route in the component hierarchy instead of
|
|
814
|
+
* the current URL of the app.
|
|
815
|
+
*
|
|
816
|
+
* This is used internally by {@link Form} to resolve the `action` to the closest
|
|
817
|
+
* route, but can be used generically as well.
|
|
818
|
+
*
|
|
819
|
+
* ```ts
|
|
820
|
+
* import { useFormAction } from "react-router";
|
|
821
|
+
*
|
|
822
|
+
* function SomeComponent() {
|
|
823
|
+
* // closest route URL
|
|
824
|
+
* let action = useFormAction();
|
|
825
|
+
*
|
|
826
|
+
* // closest route URL + "destroy"
|
|
827
|
+
* let destroyAction = useFormAction("destroy");
|
|
828
|
+
* }
|
|
829
|
+
* ```
|
|
830
|
+
*
|
|
831
|
+
* <docs-info>This hook adds a `basename` if your app specifies one, so that it
|
|
832
|
+
* can be used with raw `<form>` elements in a progressively enhanced way. If
|
|
833
|
+
* you are using this to provide an `action` to `<Form>` or `fetcher.submit`, you
|
|
834
|
+
* will need to remove the `basename` since both of those will prepend it
|
|
835
|
+
* internally.</docs-info>
|
|
836
|
+
*
|
|
837
|
+
*
|
|
838
|
+
* @public
|
|
839
|
+
* @category Hooks
|
|
840
|
+
* @mode framework
|
|
841
|
+
* @mode data
|
|
842
|
+
* @param action The action to append to the closest route URL. Defaults to the
|
|
843
|
+
* closest route URL.
|
|
844
|
+
* @param options Options
|
|
845
|
+
* @param options.relative The relative routing type to use when resolving the
|
|
846
|
+
* action. Defaults to `"route"`.
|
|
847
|
+
* @returns The resolved action URL.
|
|
848
|
+
*/
|
|
849
|
+
function useFormAction(action, { relative } = {}) {
|
|
850
|
+
let { basename } = React$1.useContext(NavigationContext);
|
|
851
|
+
let routeContext = React$1.useContext(RouteContext);
|
|
852
|
+
invariant(routeContext, "useFormAction must be used inside a RouteContext");
|
|
853
|
+
let [match] = routeContext.matches.slice(-1);
|
|
854
|
+
let path = { ...useResolvedPath(action ? action : ".", { relative }) };
|
|
855
|
+
let location = useLocation();
|
|
856
|
+
if (action == null) {
|
|
857
|
+
path.search = location.search;
|
|
858
|
+
let params = new URLSearchParams(path.search);
|
|
859
|
+
let indexValues = params.getAll("index");
|
|
860
|
+
if (indexValues.some((v) => v === "")) {
|
|
861
|
+
params.delete("index");
|
|
862
|
+
indexValues.filter((v) => v).forEach((v) => params.append("index", v));
|
|
863
|
+
let qs = params.toString();
|
|
864
|
+
path.search = qs ? `?${qs}` : "";
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
if ((!action || action === ".") && match.route.index) path.search = path.search ? path.search.replace(/^\?/, "?index&") : "?index";
|
|
868
|
+
if (basename !== "/") path.pathname = path.pathname === "/" ? basename : joinPaths([basename, path.pathname]);
|
|
869
|
+
return createPath(path);
|
|
870
|
+
}
|
|
871
|
+
/**
|
|
872
|
+
* Useful for creating complex, dynamic user interfaces that require multiple,
|
|
873
|
+
* concurrent data interactions without causing a navigation.
|
|
874
|
+
*
|
|
875
|
+
* Fetchers track their own, independent state and can be used to load data, submit
|
|
876
|
+
* forms, and generally interact with [`action`](../../start/framework/route-module#action)
|
|
877
|
+
* and [`loader`](../../start/framework/route-module#loader) functions.
|
|
878
|
+
*
|
|
879
|
+
* @example
|
|
880
|
+
* import { useFetcher } from "react-router"
|
|
881
|
+
*
|
|
882
|
+
* function SomeComponent() {
|
|
883
|
+
* let fetcher = useFetcher()
|
|
884
|
+
*
|
|
885
|
+
* // states are available on the fetcher
|
|
886
|
+
* fetcher.state // "idle" | "loading" | "submitting"
|
|
887
|
+
* fetcher.data // the data returned from the action or loader
|
|
888
|
+
*
|
|
889
|
+
* // render a form
|
|
890
|
+
* <fetcher.Form method="post" />
|
|
891
|
+
*
|
|
892
|
+
* // load data
|
|
893
|
+
* fetcher.load("/some/route")
|
|
894
|
+
*
|
|
895
|
+
* // submit data
|
|
896
|
+
* fetcher.submit(someFormRef, { method: "post" })
|
|
897
|
+
* fetcher.submit(someData, {
|
|
898
|
+
* method: "post",
|
|
899
|
+
* encType: "application/json"
|
|
900
|
+
* })
|
|
901
|
+
*
|
|
902
|
+
* // reset fetcher
|
|
903
|
+
* fetcher.reset()
|
|
904
|
+
* }
|
|
905
|
+
*
|
|
906
|
+
* @public
|
|
907
|
+
* @category Hooks
|
|
908
|
+
* @mode framework
|
|
909
|
+
* @mode data
|
|
910
|
+
* @param options Options
|
|
911
|
+
* @param options.key A unique key to identify the fetcher.
|
|
912
|
+
*
|
|
913
|
+
*
|
|
914
|
+
* By default, `useFetcher` generates a unique fetcher scoped to that component.
|
|
915
|
+
* If you want to identify a fetcher with your own key such that you can access
|
|
916
|
+
* it from elsewhere in your app, you can do that with the `key` option:
|
|
917
|
+
*
|
|
918
|
+
* ```tsx
|
|
919
|
+
* function SomeComp() {
|
|
920
|
+
* let fetcher = useFetcher({ key: "my-key" })
|
|
921
|
+
* // ...
|
|
922
|
+
* }
|
|
923
|
+
*
|
|
924
|
+
* // Somewhere else
|
|
925
|
+
* function AnotherComp() {
|
|
926
|
+
* // this will be the same fetcher, sharing the state across the app
|
|
927
|
+
* let fetcher = useFetcher({ key: "my-key" });
|
|
928
|
+
* // ...
|
|
929
|
+
* }
|
|
930
|
+
* ```
|
|
931
|
+
* @returns A {@link FetcherWithComponents} object that contains the fetcher's state, data, and components for submitting forms and loading data.
|
|
932
|
+
*/
|
|
933
|
+
function useFetcher({ key } = {}) {
|
|
934
|
+
let { router } = useDataRouterContext("useFetcher");
|
|
935
|
+
let state = useDataRouterState("useFetcher");
|
|
936
|
+
let fetcherData = React$1.useContext(FetchersContext);
|
|
937
|
+
let route = React$1.useContext(RouteContext);
|
|
938
|
+
let routeId = route.matches[route.matches.length - 1]?.route.id;
|
|
939
|
+
invariant(fetcherData, `useFetcher must be used inside a FetchersContext`);
|
|
940
|
+
invariant(route, `useFetcher must be used inside a RouteContext`);
|
|
941
|
+
invariant(routeId != null, `useFetcher can only be used on routes that contain a unique "id"`);
|
|
942
|
+
let defaultKey = React$1.useId();
|
|
943
|
+
let [fetcherKey, setFetcherKey] = React$1.useState(key || defaultKey);
|
|
944
|
+
if (key && key !== fetcherKey) setFetcherKey(key);
|
|
945
|
+
let { deleteFetcher, getFetcher, resetFetcher, fetch: routerFetch } = router;
|
|
946
|
+
React$1.useEffect(() => {
|
|
947
|
+
getFetcher(fetcherKey);
|
|
948
|
+
return () => deleteFetcher(fetcherKey);
|
|
949
|
+
}, [
|
|
950
|
+
deleteFetcher,
|
|
951
|
+
getFetcher,
|
|
952
|
+
fetcherKey
|
|
953
|
+
]);
|
|
954
|
+
let load = React$1.useCallback(async (href, opts) => {
|
|
955
|
+
invariant(routeId, "No routeId available for fetcher.load()");
|
|
956
|
+
await routerFetch(fetcherKey, routeId, href, opts);
|
|
957
|
+
}, [
|
|
958
|
+
fetcherKey,
|
|
959
|
+
routeId,
|
|
960
|
+
routerFetch
|
|
961
|
+
]);
|
|
962
|
+
let submitImpl = useSubmit();
|
|
963
|
+
let submit = React$1.useCallback(async (target, opts) => {
|
|
964
|
+
await submitImpl(target, {
|
|
965
|
+
...opts,
|
|
966
|
+
navigate: false,
|
|
967
|
+
fetcherKey
|
|
968
|
+
});
|
|
969
|
+
}, [fetcherKey, submitImpl]);
|
|
970
|
+
let reset = React$1.useCallback((opts) => resetFetcher(fetcherKey, opts), [resetFetcher, fetcherKey]);
|
|
971
|
+
let FetcherForm = React$1.useMemo(() => {
|
|
972
|
+
let FetcherForm = React$1.forwardRef((props, ref) => {
|
|
973
|
+
return /* @__PURE__ */ React$1.createElement(Form, {
|
|
974
|
+
...props,
|
|
975
|
+
navigate: false,
|
|
976
|
+
fetcherKey,
|
|
977
|
+
ref
|
|
978
|
+
});
|
|
979
|
+
});
|
|
980
|
+
FetcherForm.displayName = "fetcher.Form";
|
|
981
|
+
return FetcherForm;
|
|
982
|
+
}, [fetcherKey]);
|
|
983
|
+
let fetcher = state.fetchers.get(fetcherKey) || IDLE_FETCHER;
|
|
984
|
+
let data = fetcherData.get(fetcherKey);
|
|
985
|
+
return React$1.useMemo(() => ({
|
|
986
|
+
Form: FetcherForm,
|
|
987
|
+
submit,
|
|
988
|
+
load,
|
|
989
|
+
reset,
|
|
990
|
+
...fetcher,
|
|
991
|
+
data
|
|
992
|
+
}), [
|
|
993
|
+
FetcherForm,
|
|
994
|
+
submit,
|
|
995
|
+
load,
|
|
996
|
+
reset,
|
|
997
|
+
fetcher,
|
|
998
|
+
data
|
|
999
|
+
]);
|
|
1000
|
+
}
|
|
1001
|
+
/**
|
|
1002
|
+
* Returns an array of all in-flight {@link Fetcher}s. This is useful for components
|
|
1003
|
+
* throughout the app that didn't create the fetchers but want to use their submissions
|
|
1004
|
+
* to participate in optimistic UI.
|
|
1005
|
+
*
|
|
1006
|
+
* @example
|
|
1007
|
+
* import { useFetchers } from "react-router";
|
|
1008
|
+
*
|
|
1009
|
+
* function SomeComponent() {
|
|
1010
|
+
* const fetchers = useFetchers();
|
|
1011
|
+
* fetchers[0].formData; // FormData
|
|
1012
|
+
* fetchers[0].state; // etc.
|
|
1013
|
+
* // ...
|
|
1014
|
+
* }
|
|
1015
|
+
*
|
|
1016
|
+
* @public
|
|
1017
|
+
* @category Hooks
|
|
1018
|
+
* @mode framework
|
|
1019
|
+
* @mode data
|
|
1020
|
+
* @returns An array of all in-flight {@link Fetcher}s, each with a unique `key`
|
|
1021
|
+
* property.
|
|
1022
|
+
*/
|
|
1023
|
+
function useFetchers() {
|
|
1024
|
+
let state = useDataRouterState("useFetchers");
|
|
1025
|
+
return React$1.useMemo(() => Array.from(state.fetchers.entries()).map(([key, fetcher]) => ({
|
|
1026
|
+
...fetcher,
|
|
1027
|
+
key
|
|
1028
|
+
})), [state.fetchers]);
|
|
1029
|
+
}
|
|
1030
|
+
const SCROLL_RESTORATION_STORAGE_KEY = "react-router-scroll-positions";
|
|
1031
|
+
let savedScrollPositions = {};
|
|
1032
|
+
function getScrollRestorationKey(location, matches, basename, getKey) {
|
|
1033
|
+
let key = null;
|
|
1034
|
+
if (getKey) if (basename !== "/") key = getKey({
|
|
1035
|
+
...location,
|
|
1036
|
+
pathname: stripBasename(location.pathname, basename) || location.pathname
|
|
1037
|
+
}, matches);
|
|
1038
|
+
else key = getKey(location, matches);
|
|
1039
|
+
if (key == null) key = location.key;
|
|
1040
|
+
return key;
|
|
1041
|
+
}
|
|
1042
|
+
/**
|
|
1043
|
+
* When rendered inside a {@link RouterProvider}, will restore scroll positions
|
|
1044
|
+
* on navigations
|
|
1045
|
+
*
|
|
1046
|
+
* <!--
|
|
1047
|
+
* Not marked `@public` because we only export as UNSAFE_ and therefore we don't
|
|
1048
|
+
* maintain an .md file for this hook
|
|
1049
|
+
* -->
|
|
1050
|
+
*
|
|
1051
|
+
* @name UNSAFE_useScrollRestoration
|
|
1052
|
+
* @category Hooks
|
|
1053
|
+
* @mode framework
|
|
1054
|
+
* @mode data
|
|
1055
|
+
* @param options Options
|
|
1056
|
+
* @param options.getKey A function that returns a key to use for scroll restoration.
|
|
1057
|
+
* This is useful for custom scroll restoration logic, such as using only the pathname
|
|
1058
|
+
* so that subsequent navigations to prior paths will restore the scroll. Defaults
|
|
1059
|
+
* to `location.key`.
|
|
1060
|
+
* @param options.storageKey The key to use for storing scroll positions in
|
|
1061
|
+
* `sessionStorage`. Defaults to `"react-router-scroll-positions"`.
|
|
1062
|
+
* @returns {void}
|
|
1063
|
+
*/
|
|
1064
|
+
function useScrollRestoration({ getKey, storageKey } = {}) {
|
|
1065
|
+
let { router } = useDataRouterContext("useScrollRestoration");
|
|
1066
|
+
let { restoreScrollPosition, preventScrollReset } = useDataRouterState("useScrollRestoration");
|
|
1067
|
+
let { basename } = React$1.useContext(NavigationContext);
|
|
1068
|
+
let location = useLocation();
|
|
1069
|
+
let matches = useMatches();
|
|
1070
|
+
let navigation = useNavigation();
|
|
1071
|
+
React$1.useEffect(() => {
|
|
1072
|
+
window.history.scrollRestoration = "manual";
|
|
1073
|
+
return () => {
|
|
1074
|
+
window.history.scrollRestoration = "auto";
|
|
1075
|
+
};
|
|
1076
|
+
}, []);
|
|
1077
|
+
usePageHide(React$1.useCallback(() => {
|
|
1078
|
+
if (navigation.state === "idle") {
|
|
1079
|
+
let key = getScrollRestorationKey(location, matches, basename, getKey);
|
|
1080
|
+
savedScrollPositions[key] = window.scrollY;
|
|
1081
|
+
}
|
|
1082
|
+
try {
|
|
1083
|
+
sessionStorage.setItem(storageKey || SCROLL_RESTORATION_STORAGE_KEY, JSON.stringify(savedScrollPositions));
|
|
1084
|
+
} catch (error) {
|
|
1085
|
+
warning(false, `Failed to save scroll positions in sessionStorage, <ScrollRestoration /> will not work properly (${error}).`);
|
|
1086
|
+
}
|
|
1087
|
+
window.history.scrollRestoration = "auto";
|
|
1088
|
+
}, [
|
|
1089
|
+
navigation.state,
|
|
1090
|
+
getKey,
|
|
1091
|
+
basename,
|
|
1092
|
+
location,
|
|
1093
|
+
matches,
|
|
1094
|
+
storageKey
|
|
1095
|
+
]));
|
|
1096
|
+
if (typeof document !== "undefined") {
|
|
1097
|
+
React$1.useLayoutEffect(() => {
|
|
1098
|
+
try {
|
|
1099
|
+
let sessionPositions = sessionStorage.getItem(storageKey || SCROLL_RESTORATION_STORAGE_KEY);
|
|
1100
|
+
if (sessionPositions) savedScrollPositions = JSON.parse(sessionPositions);
|
|
1101
|
+
} catch (e) {}
|
|
1102
|
+
}, [storageKey]);
|
|
1103
|
+
React$1.useLayoutEffect(() => {
|
|
1104
|
+
let disableScrollRestoration = router?.enableScrollRestoration(savedScrollPositions, () => window.scrollY, getKey ? (location, matches) => getScrollRestorationKey(location, matches, basename, getKey) : void 0);
|
|
1105
|
+
return () => disableScrollRestoration && disableScrollRestoration();
|
|
1106
|
+
}, [
|
|
1107
|
+
router,
|
|
1108
|
+
basename,
|
|
1109
|
+
getKey
|
|
1110
|
+
]);
|
|
1111
|
+
React$1.useLayoutEffect(() => {
|
|
1112
|
+
if (restoreScrollPosition === false) return;
|
|
1113
|
+
if (typeof restoreScrollPosition === "number") {
|
|
1114
|
+
window.scrollTo(0, restoreScrollPosition);
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
try {
|
|
1118
|
+
if (location.hash) {
|
|
1119
|
+
let el = document.getElementById(decodeURIComponent(location.hash.slice(1)));
|
|
1120
|
+
if (el) {
|
|
1121
|
+
el.scrollIntoView();
|
|
1122
|
+
return;
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
} catch {
|
|
1126
|
+
warning(false, `"${location.hash.slice(1)}" is not a decodable element ID. The view will not scroll to it.`);
|
|
1127
|
+
}
|
|
1128
|
+
if (preventScrollReset === true) return;
|
|
1129
|
+
window.scrollTo(0, 0);
|
|
1130
|
+
}, [
|
|
1131
|
+
location,
|
|
1132
|
+
restoreScrollPosition,
|
|
1133
|
+
preventScrollReset
|
|
1134
|
+
]);
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
/**
|
|
1138
|
+
* Set up a callback to be fired on [Window's `beforeunload` event](https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event).
|
|
1139
|
+
*
|
|
1140
|
+
* @public
|
|
1141
|
+
* @category Hooks
|
|
1142
|
+
* @param callback The callback to be called when the [`beforeunload` event](https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event)
|
|
1143
|
+
* is fired.
|
|
1144
|
+
* @param options Options
|
|
1145
|
+
* @param options.capture If `true`, the event will be captured during the capture
|
|
1146
|
+
* phase. Defaults to `false`.
|
|
1147
|
+
* @returns {void}
|
|
1148
|
+
*/
|
|
1149
|
+
function useBeforeUnload(callback, options) {
|
|
1150
|
+
let { capture } = options || {};
|
|
1151
|
+
React$1.useEffect(() => {
|
|
1152
|
+
let opts = capture != null ? { capture } : void 0;
|
|
1153
|
+
window.addEventListener("beforeunload", callback, opts);
|
|
1154
|
+
return () => {
|
|
1155
|
+
window.removeEventListener("beforeunload", callback, opts);
|
|
1156
|
+
};
|
|
1157
|
+
}, [callback, capture]);
|
|
1158
|
+
}
|
|
1159
|
+
function usePageHide(callback, options) {
|
|
1160
|
+
let { capture } = options || {};
|
|
1161
|
+
React$1.useEffect(() => {
|
|
1162
|
+
let opts = capture != null ? { capture } : void 0;
|
|
1163
|
+
window.addEventListener("pagehide", callback, opts);
|
|
1164
|
+
return () => {
|
|
1165
|
+
window.removeEventListener("pagehide", callback, opts);
|
|
1166
|
+
};
|
|
1167
|
+
}, [callback, capture]);
|
|
1168
|
+
}
|
|
1169
|
+
/**
|
|
1170
|
+
* Wrapper around {@link useBlocker} to show a [`window.confirm`](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm)
|
|
1171
|
+
* prompt to users instead of building a custom UI with {@link useBlocker}.
|
|
1172
|
+
*
|
|
1173
|
+
* The `unstable_` flag will not be removed because this technique has a lot of
|
|
1174
|
+
* rough edges and behaves very differently (and incorrectly sometimes) across
|
|
1175
|
+
* browsers if users click addition back/forward navigations while the
|
|
1176
|
+
* confirmation is open. Use at your own risk.
|
|
1177
|
+
*
|
|
1178
|
+
* @example
|
|
1179
|
+
* function ImportantForm() {
|
|
1180
|
+
* let [value, setValue] = React.useState("");
|
|
1181
|
+
*
|
|
1182
|
+
* // Block navigating elsewhere when data has been entered into the input
|
|
1183
|
+
* unstable_usePrompt({
|
|
1184
|
+
* message: "Are you sure?",
|
|
1185
|
+
* when: ({ currentLocation, nextLocation }) =>
|
|
1186
|
+
* value !== "" &&
|
|
1187
|
+
* currentLocation.pathname !== nextLocation.pathname,
|
|
1188
|
+
* });
|
|
1189
|
+
*
|
|
1190
|
+
* return (
|
|
1191
|
+
* <Form method="post">
|
|
1192
|
+
* <label>
|
|
1193
|
+
* Enter some important data:
|
|
1194
|
+
* <input
|
|
1195
|
+
* name="data"
|
|
1196
|
+
* value={value}
|
|
1197
|
+
* onChange={(e) => setValue(e.target.value)}
|
|
1198
|
+
* />
|
|
1199
|
+
* </label>
|
|
1200
|
+
* <button type="submit">Save</button>
|
|
1201
|
+
* </Form>
|
|
1202
|
+
* );
|
|
1203
|
+
* }
|
|
1204
|
+
*
|
|
1205
|
+
* @name unstable_usePrompt
|
|
1206
|
+
* @public
|
|
1207
|
+
* @category Hooks
|
|
1208
|
+
* @mode framework
|
|
1209
|
+
* @mode data
|
|
1210
|
+
* @param options Options
|
|
1211
|
+
* @param options.message The message to show in the confirmation dialog.
|
|
1212
|
+
* @param options.when A boolean or a function that returns a boolean indicating
|
|
1213
|
+
* whether to block the navigation. If a function is provided, it will receive an
|
|
1214
|
+
* object with `currentLocation` and `nextLocation` properties.
|
|
1215
|
+
* @returns {void}
|
|
1216
|
+
*/
|
|
1217
|
+
function usePrompt({ when, message }) {
|
|
1218
|
+
let blocker = useBlocker(when);
|
|
1219
|
+
React$1.useEffect(() => {
|
|
1220
|
+
if (blocker.state === "blocked") if (window.confirm(message)) setTimeout(blocker.proceed, 0);
|
|
1221
|
+
else blocker.reset();
|
|
1222
|
+
}, [blocker, message]);
|
|
1223
|
+
React$1.useEffect(() => {
|
|
1224
|
+
if (blocker.state === "blocked" && !when) blocker.reset();
|
|
1225
|
+
}, [blocker, when]);
|
|
1226
|
+
}
|
|
1227
|
+
/**
|
|
1228
|
+
* This hook returns `true` when there is an active [View Transition](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API)
|
|
1229
|
+
* and the specified location matches either side of the navigation (the URL you are
|
|
1230
|
+
* navigating **to** or the URL you are navigating **from**). This can be used to apply finer-grained styles to
|
|
1231
|
+
* elements to further customize the view transition. This requires that view
|
|
1232
|
+
* transitions have been enabled for the given navigation via {@link LinkProps.viewTransition}
|
|
1233
|
+
* (or the `Form`, `submit`, or `navigate` call)
|
|
1234
|
+
*
|
|
1235
|
+
* @public
|
|
1236
|
+
* @category Hooks
|
|
1237
|
+
* @mode framework
|
|
1238
|
+
* @mode data
|
|
1239
|
+
* @param to The {@link To} location to compare against the active transition's current
|
|
1240
|
+
* and next URLs.
|
|
1241
|
+
* @param options Options
|
|
1242
|
+
* @param options.relative The relative routing type to use when resolving the
|
|
1243
|
+
* `to` location, defaults to `"route"`. See {@link RelativeRoutingType} for
|
|
1244
|
+
* more details.
|
|
1245
|
+
* @returns `true` if there is an active [View Transition](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API)
|
|
1246
|
+
* and the resolved path matches the transition's destination or source pathname, otherwise `false`.
|
|
1247
|
+
*/
|
|
1248
|
+
function useViewTransitionState(to, { relative } = {}) {
|
|
1249
|
+
let vtContext = React$1.useContext(ViewTransitionContext);
|
|
1250
|
+
invariant(vtContext != null, "`useViewTransitionState` must be used within `react-router/dom`'s `RouterProvider`. Did you accidentally import `RouterProvider` from `react-router`?");
|
|
1251
|
+
let { basename } = useDataRouterContext("useViewTransitionState");
|
|
1252
|
+
let path = useResolvedPath(to, { relative });
|
|
1253
|
+
if (!vtContext.isTransitioning) return false;
|
|
1254
|
+
let currentPath = stripBasename(vtContext.currentLocation.pathname, basename) || vtContext.currentLocation.pathname;
|
|
1255
|
+
let nextPath = stripBasename(vtContext.nextLocation.pathname, basename) || vtContext.nextLocation.pathname;
|
|
1256
|
+
return matchPath(path.pathname, nextPath) != null || matchPath(path.pathname, currentPath) != null;
|
|
1257
|
+
}
|
|
1258
|
+
//#endregion
|
|
1259
|
+
export { BrowserRouter, Form, HashRouter, HistoryRouter, Link, NavLink, ScrollRestoration, createBrowserRouter, createHashRouter, useBeforeUnload, useFetcher, useFetchers, useFormAction, useLinkClickHandler, usePrompt, useScrollRestoration, useSearchParams, useSubmit, useViewTransitionState };
|