@remix-run/router 0.0.0-experimental-7b1bbb00 → 0.0.0-experimental-4a8a492a
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 -0
- package/dist/history.d.ts +4 -4
- package/dist/index.d.ts +2 -2
- package/dist/router.cjs.js +130 -54
- package/dist/router.cjs.js.map +1 -1
- package/dist/router.d.ts +10 -10
- package/dist/router.js +115 -30
- package/dist/router.js.map +1 -1
- package/dist/router.umd.js +130 -54
- package/dist/router.umd.js.map +1 -1
- package/dist/router.umd.min.js +2 -2
- package/dist/router.umd.min.js.map +1 -1
- package/dist/utils.d.ts +28 -12
- package/history.ts +8 -5
- package/index.ts +2 -0
- package/package.json +1 -1
- package/router.ts +155 -47
- package/utils.ts +61 -24
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# `@remix-run/router`
|
|
2
2
|
|
|
3
|
+
## 1.9.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- In order to move towards stricter TypeScript support in the future, we're aiming to replace current usages of `any` with `unknown` on exposed typings for user-provided data. To do this in Remix v2 without introducing breaking changes in React Router v6, we have added generics to a number of shared types. These continue to default to `any` in React Router and are overridden with `unknown` in Remix. In React Router v7 we plan to move these to `unknown` as a breaking change. ([#10843](https://github.com/remix-run/react-router/pull/10843))
|
|
8
|
+
- `Location` now accepts a generic for the `location.state` value
|
|
9
|
+
- `ActionFunctionArgs`/`ActionFunction`/`LoaderFunctionArgs`/`LoaderFunction` now accept a generic for the `context` parameter (only used in SSR usages via `createStaticHandler`)
|
|
10
|
+
- The return type of `useMatches` (now exported as `UIMatch`) accepts generics for `match.data` and `match.handle` - both of which were already set to `unknown`
|
|
11
|
+
- Move the `@private` class export `ErrorResponse` to an `UNSAFE_ErrorResponseImpl` export since it is an implementation detail and there should be no construction of `ErrorResponse` instances in userland. This frees us up to export a `type ErrorResponse` which correlates to an instance of the class via `InstanceType`. Userland code should only ever be using `ErrorResponse` as a type and should be type-narrowing via `isRouteErrorResponse`. ([#10811](https://github.com/remix-run/react-router/pull/10811))
|
|
12
|
+
- Export `ShouldRevalidateFunctionArgs` interface ([#10797](https://github.com/remix-run/react-router/pull/10797))
|
|
13
|
+
- Removed private/internal APIs only required for the Remix v1 backwards compatibility layer and no longer needed in Remix v2 (`_isFetchActionRedirect`, `_hasFetcherDoneAnything`) ([#10715](https://github.com/remix-run/react-router/pull/10715))
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- Add method/url to error message on aborted `query`/`queryRoute` calls ([#10793](https://github.com/remix-run/react-router/pull/10793))
|
|
18
|
+
- Fix a race-condition with loader/action-thrown errors on `route.lazy` routes ([#10778](https://github.com/remix-run/react-router/pull/10778))
|
|
19
|
+
- Fix type for `actionResult` on the arguments object passed to `shouldRevalidate` ([#10779](https://github.com/remix-run/react-router/pull/10779))
|
|
20
|
+
|
|
3
21
|
## 1.8.0
|
|
4
22
|
|
|
5
23
|
### Minor Changes
|
package/dist/history.d.ts
CHANGED
|
@@ -43,11 +43,11 @@ export interface Path {
|
|
|
43
43
|
* An entry in a history stack. A location contains information about the
|
|
44
44
|
* URL path, as well as possibly some arbitrary state and a key.
|
|
45
45
|
*/
|
|
46
|
-
export interface Location extends Path {
|
|
46
|
+
export interface Location<State = any> extends Path {
|
|
47
47
|
/**
|
|
48
48
|
* A value of arbitrary data associated with this location.
|
|
49
49
|
*/
|
|
50
|
-
state:
|
|
50
|
+
state: State;
|
|
51
51
|
/**
|
|
52
52
|
* A unique string associated with this location. May be used to safely store
|
|
53
53
|
* and retrieve data in some other storage API, like `localStorage`.
|
|
@@ -81,8 +81,8 @@ export interface Listener {
|
|
|
81
81
|
}
|
|
82
82
|
/**
|
|
83
83
|
* Describes a location that is the destination of some navigation, either via
|
|
84
|
-
* `history.push` or `history.replace`.
|
|
85
|
-
* URL path.
|
|
84
|
+
* `history.push` or `history.replace`. This may be either a URL or the pieces
|
|
85
|
+
* of a URL path.
|
|
86
86
|
*/
|
|
87
87
|
export type To = string | Partial<Path>;
|
|
88
88
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export type { ActionFunction, ActionFunctionArgs, AgnosticDataIndexRouteObject, AgnosticDataNonIndexRouteObject, AgnosticDataRouteMatch, AgnosticDataRouteObject, AgnosticIndexRouteObject, AgnosticNonIndexRouteObject, AgnosticRouteMatch, AgnosticRouteObject, ErrorResponse, FormEncType, FormMethod, HTMLFormMethod, JsonFunction, LazyRouteFunction, LoaderFunction, LoaderFunctionArgs, ParamParseKey, Params, PathMatch, PathPattern, RedirectFunction, ShouldRevalidateFunction, ShouldRevalidateFunctionArgs, TrackedPromise, V7_FormMethod, } from "./utils";
|
|
1
|
+
export type { ActionFunction, ActionFunctionArgs, AgnosticDataIndexRouteObject, AgnosticDataNonIndexRouteObject, AgnosticDataRouteMatch, AgnosticDataRouteObject, AgnosticIndexRouteObject, AgnosticNonIndexRouteObject, AgnosticRouteMatch, AgnosticRouteObject, ErrorResponse, FormEncType, FormMethod, HTMLFormMethod, JsonFunction, LazyRouteFunction, LoaderFunction, LoaderFunctionArgs, ParamParseKey, Params, PathMatch, PathPattern, RedirectFunction, ShouldRevalidateFunction, ShouldRevalidateFunctionArgs, TrackedPromise, UIMatch, V7_FormMethod, } from "./utils";
|
|
2
2
|
export { AbortedDeferredError, defer, generatePath, getToPathname, isRouteErrorResponse, joinPaths, json, matchPath, matchRoutes, normalizePathname, redirect, redirectDocument, resolvePath, resolveTo, stripBasename, } from "./utils";
|
|
3
3
|
export type { BrowserHistory, BrowserHistoryOptions, HashHistory, HashHistoryOptions, History, InitialEntry, Location, MemoryHistory, MemoryHistoryOptions, Path, To, } from "./history";
|
|
4
4
|
export { Action, createBrowserHistory, createHashHistory, createMemoryHistory, createPath, parsePath, } from "./history";
|
|
5
5
|
export * from "./router";
|
|
6
6
|
/** @internal */
|
|
7
7
|
export type { RouteManifest as UNSAFE_RouteManifest } from "./utils";
|
|
8
|
-
export { DeferredData as UNSAFE_DeferredData, ErrorResponseImpl as UNSAFE_ErrorResponseImpl, convertRoutesToDataRoutes as UNSAFE_convertRoutesToDataRoutes, getPathContributingMatches as UNSAFE_getPathContributingMatches, } from "./utils";
|
|
8
|
+
export { DeferredData as UNSAFE_DeferredData, ErrorResponseImpl as UNSAFE_ErrorResponseImpl, convertRoutesToDataRoutes as UNSAFE_convertRoutesToDataRoutes, convertRouteMatchToUiMatch as UNSAFE_convertRouteMatchToUiMatch, getPathContributingMatches as UNSAFE_getPathContributingMatches, } from "./utils";
|
|
9
9
|
export { invariant as UNSAFE_invariant, warning as UNSAFE_warning, } from "./history";
|
package/dist/router.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @remix-run/router v0.0.0-experimental-
|
|
2
|
+
* @remix-run/router v0.0.0-experimental-4a8a492a
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -45,25 +45,23 @@ let Action = /*#__PURE__*/function (Action) {
|
|
|
45
45
|
* The pathname, search, and hash values of a URL.
|
|
46
46
|
*/
|
|
47
47
|
|
|
48
|
+
// TODO: (v7) Change the Location generic default from `any` to `unknown` and
|
|
49
|
+
// remove Remix `useLocation` wrapper.
|
|
48
50
|
/**
|
|
49
51
|
* An entry in a history stack. A location contains information about the
|
|
50
52
|
* URL path, as well as possibly some arbitrary state and a key.
|
|
51
53
|
*/
|
|
52
|
-
|
|
53
54
|
/**
|
|
54
55
|
* A change to the current location.
|
|
55
56
|
*/
|
|
56
|
-
|
|
57
57
|
/**
|
|
58
58
|
* A function that receives notifications about location changes.
|
|
59
59
|
*/
|
|
60
|
-
|
|
61
60
|
/**
|
|
62
61
|
* Describes a location that is the destination of some navigation, either via
|
|
63
|
-
* `history.push` or `history.replace`.
|
|
64
|
-
* URL path.
|
|
62
|
+
* `history.push` or `history.replace`. This may be either a URL or the pieces
|
|
63
|
+
* of a URL path.
|
|
65
64
|
*/
|
|
66
|
-
|
|
67
65
|
/**
|
|
68
66
|
* A history is an interface to the navigation stack. The history serves as the
|
|
69
67
|
* source of truth for the current location, as well as provides a set of
|
|
@@ -72,7 +70,6 @@ let Action = /*#__PURE__*/function (Action) {
|
|
|
72
70
|
* It is similar to the DOM's `window.history` object, but with a smaller, more
|
|
73
71
|
* focused API.
|
|
74
72
|
*/
|
|
75
|
-
|
|
76
73
|
const PopStateEventType = "popstate";
|
|
77
74
|
//#endregion
|
|
78
75
|
|
|
@@ -325,7 +322,7 @@ function warning(cond, message) {
|
|
|
325
322
|
try {
|
|
326
323
|
// Welcome to debugging history!
|
|
327
324
|
//
|
|
328
|
-
// This error is thrown as a convenience so you can more easily
|
|
325
|
+
// This error is thrown as a convenience, so you can more easily
|
|
329
326
|
// find the source for a warning that appears in the console by
|
|
330
327
|
// enabling "pause on exceptions" in your JavaScript debugger.
|
|
331
328
|
throw new Error(message);
|
|
@@ -577,8 +574,8 @@ let ResultType = /*#__PURE__*/function (ResultType) {
|
|
|
577
574
|
*/
|
|
578
575
|
|
|
579
576
|
/**
|
|
580
|
-
* Users can specify either lowercase or uppercase form methods on
|
|
581
|
-
* useSubmit(),
|
|
577
|
+
* Users can specify either lowercase or uppercase form methods on `<Form>`,
|
|
578
|
+
* useSubmit(), `<fetcher.Form>`, etc.
|
|
582
579
|
*/
|
|
583
580
|
|
|
584
581
|
/**
|
|
@@ -605,32 +602,29 @@ let ResultType = /*#__PURE__*/function (ResultType) {
|
|
|
605
602
|
* this as a private implementation detail in case they diverge in the future.
|
|
606
603
|
*/
|
|
607
604
|
|
|
605
|
+
// TODO: (v7) Change the defaults from any to unknown in and remove Remix wrappers:
|
|
606
|
+
// ActionFunction, ActionFunctionArgs, LoaderFunction, LoaderFunctionArgs
|
|
607
|
+
// Also, make them a type alias instead of an interface
|
|
608
608
|
/**
|
|
609
609
|
* Arguments passed to loader functions
|
|
610
610
|
*/
|
|
611
|
-
|
|
612
611
|
/**
|
|
613
612
|
* Arguments passed to action functions
|
|
614
613
|
*/
|
|
615
|
-
|
|
616
614
|
/**
|
|
617
615
|
* Loaders and actions can return anything except `undefined` (`null` is a
|
|
618
616
|
* valid return value if there is no data to return). Responses are preferred
|
|
619
617
|
* and will ease any future migration to Remix
|
|
620
618
|
*/
|
|
621
|
-
|
|
622
619
|
/**
|
|
623
620
|
* Route loader function signature
|
|
624
621
|
*/
|
|
625
|
-
|
|
626
622
|
/**
|
|
627
623
|
* Route action function signature
|
|
628
624
|
*/
|
|
629
|
-
|
|
630
625
|
/**
|
|
631
626
|
* Arguments passed to shouldRevalidate function
|
|
632
627
|
*/
|
|
633
|
-
|
|
634
628
|
/**
|
|
635
629
|
* Route shouldRevalidate function signature. This runs after any submission
|
|
636
630
|
* (navigation or fetcher), so we flatten the navigation/fetcher submission
|
|
@@ -638,25 +632,21 @@ let ResultType = /*#__PURE__*/function (ResultType) {
|
|
|
638
632
|
* or a fetcher, what really matters is the URLs and the formData since loaders
|
|
639
633
|
* have to re-run based on the data models that were potentially mutated.
|
|
640
634
|
*/
|
|
641
|
-
|
|
642
635
|
/**
|
|
643
636
|
* Function provided by the framework-aware layers to set `hasErrorBoundary`
|
|
644
637
|
* from the framework-aware `errorElement` prop
|
|
645
638
|
*
|
|
646
639
|
* @deprecated Use `mapRouteProperties` instead
|
|
647
640
|
*/
|
|
648
|
-
|
|
649
641
|
/**
|
|
650
642
|
* Function provided by the framework-aware layers to set any framework-specific
|
|
651
643
|
* properties from framework-agnostic properties
|
|
652
644
|
*/
|
|
653
|
-
|
|
654
645
|
/**
|
|
655
646
|
* Keys we cannot change from within a lazy() function. We spread all other keys
|
|
656
647
|
* onto the route. Either they're meaningful to the router, or they'll get
|
|
657
648
|
* ignored.
|
|
658
649
|
*/
|
|
659
|
-
|
|
660
650
|
const immutableRouteKeys = new Set(["lazy", "caseSensitive", "path", "id", "index", "children"]);
|
|
661
651
|
|
|
662
652
|
/**
|
|
@@ -698,7 +688,7 @@ const immutableRouteKeys = new Set(["lazy", "caseSensitive", "path", "id", "inde
|
|
|
698
688
|
*/
|
|
699
689
|
|
|
700
690
|
// Attempt to parse the given string segment. If it fails, then just return the
|
|
701
|
-
// plain string type as a default fallback. Otherwise return the union of the
|
|
691
|
+
// plain string type as a default fallback. Otherwise, return the union of the
|
|
702
692
|
// parsed string literals that were referenced as dynamic segments in the route.
|
|
703
693
|
/**
|
|
704
694
|
* The parameters that were parsed from the URL path.
|
|
@@ -710,7 +700,7 @@ function isIndexRoute(route) {
|
|
|
710
700
|
return route.index === true;
|
|
711
701
|
}
|
|
712
702
|
|
|
713
|
-
// Walk the route tree generating unique IDs where necessary so we are working
|
|
703
|
+
// Walk the route tree generating unique IDs where necessary, so we are working
|
|
714
704
|
// solely with AgnosticDataRouteObject's within the Router
|
|
715
705
|
function convertRoutesToDataRoutes(routes, mapRouteProperties, parentPath, manifest) {
|
|
716
706
|
if (parentPath === void 0) {
|
|
@@ -773,6 +763,20 @@ function matchRoutes(routes, locationArg, basename) {
|
|
|
773
763
|
}
|
|
774
764
|
return matches;
|
|
775
765
|
}
|
|
766
|
+
function convertRouteMatchToUiMatch(match, loaderData) {
|
|
767
|
+
let {
|
|
768
|
+
route,
|
|
769
|
+
pathname,
|
|
770
|
+
params
|
|
771
|
+
} = match;
|
|
772
|
+
return {
|
|
773
|
+
id: route.id,
|
|
774
|
+
pathname,
|
|
775
|
+
params,
|
|
776
|
+
data: loaderData[route.id],
|
|
777
|
+
handle: route.handle
|
|
778
|
+
};
|
|
779
|
+
}
|
|
776
780
|
function flattenRoutes(routes, branches, parentsMeta, parentPath) {
|
|
777
781
|
if (branches === void 0) {
|
|
778
782
|
branches = [];
|
|
@@ -797,7 +801,7 @@ function flattenRoutes(routes, branches, parentsMeta, parentPath) {
|
|
|
797
801
|
let path = joinPaths([parentPath, meta.relativePath]);
|
|
798
802
|
let routesMeta = parentsMeta.concat(meta);
|
|
799
803
|
|
|
800
|
-
// Add the children before adding this route to the array so we traverse the
|
|
804
|
+
// Add the children before adding this route to the array, so we traverse the
|
|
801
805
|
// route tree depth-first and child routes appear before their parents in
|
|
802
806
|
// the "flattened" version.
|
|
803
807
|
if (route.children && route.children.length > 0) {
|
|
@@ -865,15 +869,15 @@ function explodeOptionalSegments(path) {
|
|
|
865
869
|
let result = [];
|
|
866
870
|
|
|
867
871
|
// All child paths with the prefix. Do this for all children before the
|
|
868
|
-
// optional version for all children so we get consistent ordering where the
|
|
872
|
+
// optional version for all children, so we get consistent ordering where the
|
|
869
873
|
// parent optional aspect is preferred as required. Otherwise, we can get
|
|
870
874
|
// child sections interspersed where deeper optional segments are higher than
|
|
871
|
-
// parent optional segments, where for example, /:two would
|
|
875
|
+
// parent optional segments, where for example, /:two would explode _earlier_
|
|
872
876
|
// then /:one. By always including the parent as required _for all children_
|
|
873
877
|
// first, we avoid this issue
|
|
874
878
|
result.push(...restExploded.map(subpath => subpath === "" ? required : [required, subpath].join("/")));
|
|
875
879
|
|
|
876
|
-
// Then if this is an optional value, add all child versions without
|
|
880
|
+
// Then, if this is an optional value, add all child versions without
|
|
877
881
|
if (isOptional) {
|
|
878
882
|
result.push(...restExploded);
|
|
879
883
|
}
|
|
@@ -1061,7 +1065,7 @@ function compilePath(path, caseSensitive, end) {
|
|
|
1061
1065
|
regexpSource += "\\/*$";
|
|
1062
1066
|
} else if (path !== "" && path !== "/") {
|
|
1063
1067
|
// If our path is non-empty and contains anything beyond an initial slash,
|
|
1064
|
-
// then we have _some_ form of path in our regex so we should expect to
|
|
1068
|
+
// then we have _some_ form of path in our regex, so we should expect to
|
|
1065
1069
|
// match only if we find the end of this path segment. Look for an optional
|
|
1066
1070
|
// non-captured trailing slash (to match a portion of the URL) or the end
|
|
1067
1071
|
// of the path (if we've matched to the end). We used to do this with a
|
|
@@ -1464,10 +1468,13 @@ const redirectDocument = (url, init) => {
|
|
|
1464
1468
|
response.headers.set("X-Remix-Reload-Document", "true");
|
|
1465
1469
|
return response;
|
|
1466
1470
|
};
|
|
1467
|
-
|
|
1468
1471
|
/**
|
|
1469
1472
|
* @private
|
|
1470
1473
|
* Utility class we use to hold auto-unwrapped 4xx/5xx Response bodies
|
|
1474
|
+
*
|
|
1475
|
+
* We don't export the class for public use since it's an implementation
|
|
1476
|
+
* detail, but we export the interface above so folks can build their own
|
|
1477
|
+
* abstractions around instances via isRouteErrorResponse()
|
|
1471
1478
|
*/
|
|
1472
1479
|
class ErrorResponseImpl {
|
|
1473
1480
|
constructor(status, statusText, data, internal) {
|
|
@@ -1486,9 +1493,6 @@ class ErrorResponseImpl {
|
|
|
1486
1493
|
}
|
|
1487
1494
|
}
|
|
1488
1495
|
|
|
1489
|
-
// We don't want the class exported since usage of it at runtime is an
|
|
1490
|
-
// implementation detail, but we do want to export the shape so folks can
|
|
1491
|
-
// build their own abstractions around instances via isRouteErrorResponse()
|
|
1492
1496
|
/**
|
|
1493
1497
|
* Check if the given error is an ErrorResponse generated from a 4xx/5xx
|
|
1494
1498
|
* Response thrown from an action/loader
|
|
@@ -1608,6 +1612,7 @@ const ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
|
|
|
1608
1612
|
const defaultMapRouteProperties = route => ({
|
|
1609
1613
|
hasErrorBoundary: Boolean(route.hasErrorBoundary)
|
|
1610
1614
|
});
|
|
1615
|
+
const TRANSITIONS_STORAGE_KEY = "remix-router-transitions";
|
|
1611
1616
|
|
|
1612
1617
|
//#endregion
|
|
1613
1618
|
|
|
@@ -1716,6 +1721,15 @@ function createRouter(init) {
|
|
|
1716
1721
|
// AbortController for the active navigation
|
|
1717
1722
|
let pendingNavigationController;
|
|
1718
1723
|
|
|
1724
|
+
// Should the current navigation enable document.startViewTransition?
|
|
1725
|
+
let pendingViewTransitionEnabled = false;
|
|
1726
|
+
|
|
1727
|
+
// Store applied view transitions so we can apply them on POP
|
|
1728
|
+
let appliedViewTransitions = new Map();
|
|
1729
|
+
|
|
1730
|
+
// Cleanup function for persisting applied transitions to sessionStorage
|
|
1731
|
+
let removePageHideEventListener = null;
|
|
1732
|
+
|
|
1719
1733
|
// We use this to avoid touching history in completeNavigation if a
|
|
1720
1734
|
// revalidation is entirely uninterrupted
|
|
1721
1735
|
let isUninterruptedRevalidation = false;
|
|
@@ -1823,6 +1837,14 @@ function createRouter(init) {
|
|
|
1823
1837
|
}
|
|
1824
1838
|
return startNavigation(historyAction, location);
|
|
1825
1839
|
});
|
|
1840
|
+
if (isBrowser) {
|
|
1841
|
+
// FIXME: This feels gross. How can we cleanup the lines between
|
|
1842
|
+
// scrollRestoration/appliedTransitions persistance?
|
|
1843
|
+
restoreAppliedTransitions(routerWindow, appliedViewTransitions);
|
|
1844
|
+
let _saveAppliedTransitions = () => persistAppliedTransitions(routerWindow, appliedViewTransitions);
|
|
1845
|
+
routerWindow.addEventListener("pagehide", _saveAppliedTransitions);
|
|
1846
|
+
removePageHideEventListener = () => routerWindow.removeEventListener("pagehide", _saveAppliedTransitions);
|
|
1847
|
+
}
|
|
1826
1848
|
|
|
1827
1849
|
// Kick off initial data load if needed. Use Pop to avoid modifying history
|
|
1828
1850
|
// Note we don't do any handling of lazy here. For SPA's it'll get handled
|
|
@@ -1840,6 +1862,9 @@ function createRouter(init) {
|
|
|
1840
1862
|
if (unlistenHistory) {
|
|
1841
1863
|
unlistenHistory();
|
|
1842
1864
|
}
|
|
1865
|
+
if (removePageHideEventListener) {
|
|
1866
|
+
removePageHideEventListener();
|
|
1867
|
+
}
|
|
1843
1868
|
subscribers.clear();
|
|
1844
1869
|
pendingNavigationController && pendingNavigationController.abort();
|
|
1845
1870
|
state.fetchers.forEach((_, key) => deleteFetcher(key));
|
|
@@ -1853,9 +1878,11 @@ function createRouter(init) {
|
|
|
1853
1878
|
}
|
|
1854
1879
|
|
|
1855
1880
|
// Update our state and notify the calling context of the change
|
|
1856
|
-
function updateState(newState) {
|
|
1881
|
+
function updateState(newState, viewTransitionOpts) {
|
|
1857
1882
|
state = _extends({}, state, newState);
|
|
1858
|
-
subscribers.forEach(subscriber => subscriber(state
|
|
1883
|
+
subscribers.forEach(subscriber => subscriber(state, {
|
|
1884
|
+
viewTransitionOpts
|
|
1885
|
+
}));
|
|
1859
1886
|
}
|
|
1860
1887
|
|
|
1861
1888
|
// Complete a navigation returning the state.navigation back to the IDLE_NAVIGATION
|
|
@@ -1910,6 +1937,39 @@ function createRouter(init) {
|
|
|
1910
1937
|
} else if (pendingAction === Action.Replace) {
|
|
1911
1938
|
init.history.replace(location, location.state);
|
|
1912
1939
|
}
|
|
1940
|
+
let viewTransitionOpts;
|
|
1941
|
+
|
|
1942
|
+
// On POP, enable transitions if they were enabled on the original navigation
|
|
1943
|
+
if (pendingAction === Action.Pop) {
|
|
1944
|
+
// Forward takes precedence so they behave like the original navigation
|
|
1945
|
+
let priorPaths = appliedViewTransitions.get(state.location.pathname);
|
|
1946
|
+
if (priorPaths && priorPaths.has(location.pathname)) {
|
|
1947
|
+
viewTransitionOpts = {
|
|
1948
|
+
currentLocation: state.location,
|
|
1949
|
+
nextLocation: location
|
|
1950
|
+
};
|
|
1951
|
+
} else if (appliedViewTransitions.has(location.pathname)) {
|
|
1952
|
+
// If we don't have a previous forward nav, assume we're popping back to
|
|
1953
|
+
// the new location and enable if that location previously enabled
|
|
1954
|
+
viewTransitionOpts = {
|
|
1955
|
+
currentLocation: location,
|
|
1956
|
+
nextLocation: state.location
|
|
1957
|
+
};
|
|
1958
|
+
}
|
|
1959
|
+
} else if (pendingViewTransitionEnabled) {
|
|
1960
|
+
// Store the applied transition on PUSH/REPLACE
|
|
1961
|
+
let toPaths = appliedViewTransitions.get(state.location.pathname);
|
|
1962
|
+
if (toPaths) {
|
|
1963
|
+
toPaths.add(location.pathname);
|
|
1964
|
+
} else {
|
|
1965
|
+
toPaths = new Set([location.pathname]);
|
|
1966
|
+
appliedViewTransitions.set(state.location.pathname, toPaths);
|
|
1967
|
+
}
|
|
1968
|
+
viewTransitionOpts = {
|
|
1969
|
+
currentLocation: state.location,
|
|
1970
|
+
nextLocation: location
|
|
1971
|
+
};
|
|
1972
|
+
}
|
|
1913
1973
|
updateState(_extends({}, newState, {
|
|
1914
1974
|
// matches, errors, fetchers go through as-is
|
|
1915
1975
|
actionData,
|
|
@@ -1922,11 +1982,12 @@ function createRouter(init) {
|
|
|
1922
1982
|
restoreScrollPosition: getSavedScrollPosition(location, newState.matches || state.matches),
|
|
1923
1983
|
preventScrollReset,
|
|
1924
1984
|
blockers
|
|
1925
|
-
}));
|
|
1985
|
+
}), viewTransitionOpts);
|
|
1926
1986
|
|
|
1927
1987
|
// Reset stateful navigation vars
|
|
1928
1988
|
pendingAction = Action.Pop;
|
|
1929
1989
|
pendingPreventScrollReset = false;
|
|
1990
|
+
pendingViewTransitionEnabled = false;
|
|
1930
1991
|
isUninterruptedRevalidation = false;
|
|
1931
1992
|
isRevalidationRequired = false;
|
|
1932
1993
|
cancelledDeferredRoutes = [];
|
|
@@ -2003,7 +2064,8 @@ function createRouter(init) {
|
|
|
2003
2064
|
// render at the right error boundary after we match routes
|
|
2004
2065
|
pendingError: error,
|
|
2005
2066
|
preventScrollReset,
|
|
2006
|
-
replace: opts && opts.replace
|
|
2067
|
+
replace: opts && opts.replace,
|
|
2068
|
+
enableViewTransition: opts && opts.unstable_viewTransition
|
|
2007
2069
|
});
|
|
2008
2070
|
}
|
|
2009
2071
|
|
|
@@ -2056,6 +2118,7 @@ function createRouter(init) {
|
|
|
2056
2118
|
// and track whether we should reset scroll on completion
|
|
2057
2119
|
saveScrollPosition(state.location, state.matches);
|
|
2058
2120
|
pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
|
|
2121
|
+
pendingViewTransitionEnabled = (opts && opts.enableViewTransition) === true;
|
|
2059
2122
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
2060
2123
|
let loadingNavigation = opts && opts.overrideNavigation;
|
|
2061
2124
|
let matches = matchRoutes(routesToUse, location, basename);
|
|
@@ -2972,7 +3035,7 @@ function createRouter(init) {
|
|
|
2972
3035
|
}
|
|
2973
3036
|
function getScrollKey(location, matches) {
|
|
2974
3037
|
if (getScrollRestorationKey) {
|
|
2975
|
-
let key = getScrollRestorationKey(location, matches.map(m =>
|
|
3038
|
+
let key = getScrollRestorationKey(location, matches.map(m => convertRouteMatchToUiMatch(m, state.loaderData)));
|
|
2976
3039
|
return key || location.key;
|
|
2977
3040
|
}
|
|
2978
3041
|
return location.key;
|
|
@@ -4377,23 +4440,6 @@ async function resolveDeferredData(result, signal, unwrap) {
|
|
|
4377
4440
|
function hasNakedIndexQuery(search) {
|
|
4378
4441
|
return new URLSearchParams(search).getAll("index").some(v => v === "");
|
|
4379
4442
|
}
|
|
4380
|
-
|
|
4381
|
-
// Note: This should match the format exported by useMatches, so if you change
|
|
4382
|
-
// this please also change that :) Eventually we'll DRY this up
|
|
4383
|
-
function createUseMatchesMatch(match, loaderData) {
|
|
4384
|
-
let {
|
|
4385
|
-
route,
|
|
4386
|
-
pathname,
|
|
4387
|
-
params
|
|
4388
|
-
} = match;
|
|
4389
|
-
return {
|
|
4390
|
-
id: route.id,
|
|
4391
|
-
pathname,
|
|
4392
|
-
params,
|
|
4393
|
-
data: loaderData[route.id],
|
|
4394
|
-
handle: route.handle
|
|
4395
|
-
};
|
|
4396
|
-
}
|
|
4397
4443
|
function getTargetMatch(matches, location) {
|
|
4398
4444
|
let search = typeof location === "string" ? parsePath(location).search : location.search;
|
|
4399
4445
|
if (matches[matches.length - 1].route.index && hasNakedIndexQuery(search || "")) {
|
|
@@ -4539,6 +4585,35 @@ function getDoneFetcher(data) {
|
|
|
4539
4585
|
};
|
|
4540
4586
|
return fetcher;
|
|
4541
4587
|
}
|
|
4588
|
+
function restoreAppliedTransitions(_window, transitions) {
|
|
4589
|
+
try {
|
|
4590
|
+
let sessionPositions = _window.sessionStorage.getItem(TRANSITIONS_STORAGE_KEY);
|
|
4591
|
+
if (sessionPositions) {
|
|
4592
|
+
let json = JSON.parse(sessionPositions);
|
|
4593
|
+
for (let [k, v] of Object.entries(json || {})) {
|
|
4594
|
+
if (v && Array.isArray(v)) {
|
|
4595
|
+
transitions.set(k, new Set(v || []));
|
|
4596
|
+
}
|
|
4597
|
+
}
|
|
4598
|
+
}
|
|
4599
|
+
} catch (e) {
|
|
4600
|
+
// no-op, use default empty object
|
|
4601
|
+
}
|
|
4602
|
+
}
|
|
4603
|
+
function persistAppliedTransitions(_window, transitions) {
|
|
4604
|
+
if (transitions.size > 0) {
|
|
4605
|
+
let json = {};
|
|
4606
|
+
for (let [k, v] of transitions) {
|
|
4607
|
+
json[k] = [...v];
|
|
4608
|
+
}
|
|
4609
|
+
try {
|
|
4610
|
+
_window.sessionStorage.setItem(TRANSITIONS_STORAGE_KEY, JSON.stringify(json));
|
|
4611
|
+
} catch (error) {
|
|
4612
|
+
warning(false, "Failed to save applied view transitions in sessionStorage (" + error + ").");
|
|
4613
|
+
}
|
|
4614
|
+
}
|
|
4615
|
+
}
|
|
4616
|
+
|
|
4542
4617
|
//#endregion
|
|
4543
4618
|
|
|
4544
4619
|
exports.AbortedDeferredError = AbortedDeferredError;
|
|
@@ -4549,6 +4624,7 @@ exports.IDLE_NAVIGATION = IDLE_NAVIGATION;
|
|
|
4549
4624
|
exports.UNSAFE_DEFERRED_SYMBOL = UNSAFE_DEFERRED_SYMBOL;
|
|
4550
4625
|
exports.UNSAFE_DeferredData = DeferredData;
|
|
4551
4626
|
exports.UNSAFE_ErrorResponseImpl = ErrorResponseImpl;
|
|
4627
|
+
exports.UNSAFE_convertRouteMatchToUiMatch = convertRouteMatchToUiMatch;
|
|
4552
4628
|
exports.UNSAFE_convertRoutesToDataRoutes = convertRoutesToDataRoutes;
|
|
4553
4629
|
exports.UNSAFE_getPathContributingMatches = getPathContributingMatches;
|
|
4554
4630
|
exports.UNSAFE_invariant = invariant;
|