react-router 7.0.0-pre.1 → 7.0.0-pre.2
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 +38 -0
- package/dist/dom-export.mjs +10 -2
- package/dist/dom-export.mjs.map +1 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.mjs +1375 -219
- package/dist/index.mjs.map +1 -1
- package/dist/lib/components.d.ts +6 -6
- package/dist/lib/dom/lib.d.ts +3 -2
- package/dist/lib/dom/ssr/components.d.ts +0 -1
- package/dist/lib/dom/ssr/data.d.ts +0 -5
- package/dist/lib/dom/ssr/entry.d.ts +2 -1
- package/dist/lib/dom/ssr/routeModules.d.ts +64 -22
- package/dist/lib/dom/ssr/routes.d.ts +2 -5
- package/dist/lib/hooks.d.ts +4 -3
- package/dist/lib/router/router.d.ts +4 -0
- package/dist/lib/router/utils.d.ts +1 -9
- package/dist/lib/server-runtime/build.d.ts +1 -1
- package/dist/lib/server-runtime/cookies.d.ts +5 -5
- package/dist/lib/server-runtime/data.d.ts +1 -5
- package/dist/lib/server-runtime/routeModules.d.ts +3 -175
- package/dist/lib/server-runtime/routes.d.ts +2 -22
- package/dist/lib/server-runtime/sessions.d.ts +4 -4
- package/dist/lib/types.d.ts +17 -10
- package/dist/lib/types.mjs +1 -1
- package/dist/main-dom-export.js +1 -1
- package/dist/main.js +1 -1
- package/dist/react-router-dom.development.js +2 -2
- package/dist/react-router-dom.development.js.map +1 -1
- package/dist/react-router-dom.production.min.js +2 -2
- package/dist/react-router-dom.production.min.js.map +1 -1
- package/dist/react-router.development.js +196 -171
- package/dist/react-router.development.js.map +1 -1
- package/dist/react-router.production.min.js +2 -2
- package/dist/react-router.production.min.js.map +1 -1
- package/dist/umd/react-router-dom.development.js +2 -2
- package/dist/umd/react-router-dom.development.js.map +1 -1
- package/dist/umd/react-router-dom.production.min.js +2 -2
- package/dist/umd/react-router-dom.production.min.js.map +1 -1
- package/dist/umd/react-router.development.js +195 -179
- package/dist/umd/react-router.development.js.map +1 -1
- package/dist/umd/react-router.production.min.js +2 -2
- package/dist/umd/react-router.production.min.js.map +1 -1
- package/package.json +4 -4
- package/dist/lib/server-runtime/jsonify.d.ts +0 -33
- package/dist/lib/server-runtime/responses.d.ts +0 -37
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* React Router v7.0.0-pre.
|
|
2
|
+
* React Router v7.0.0-pre.2
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -43,32 +43,69 @@ function _objectWithoutPropertiesLoose(source, excluded) {
|
|
|
43
43
|
////////////////////////////////////////////////////////////////////////////////
|
|
44
44
|
//#region Types and Constants
|
|
45
45
|
////////////////////////////////////////////////////////////////////////////////
|
|
46
|
+
|
|
46
47
|
/**
|
|
47
48
|
* Actions represent the type of change to a location value.
|
|
48
49
|
*/
|
|
49
|
-
|
|
50
|
-
(function (Action) {
|
|
51
|
-
/**
|
|
52
|
-
* A POP indicates a change to an arbitrary index in the history stack, such
|
|
53
|
-
* as a back or forward navigation. It does not describe the direction of the
|
|
54
|
-
* navigation, only that the current index changed.
|
|
55
|
-
*
|
|
56
|
-
* Note: This is the default action for newly created history objects.
|
|
57
|
-
*/
|
|
50
|
+
let Action = /*#__PURE__*/function (Action) {
|
|
58
51
|
Action["Pop"] = "POP";
|
|
59
|
-
/**
|
|
60
|
-
* A PUSH indicates a new entry being added to the history stack, such as when
|
|
61
|
-
* a link is clicked and a new page loads. When this happens, all subsequent
|
|
62
|
-
* entries in the stack are lost.
|
|
63
|
-
*/
|
|
64
52
|
Action["Push"] = "PUSH";
|
|
65
|
-
/**
|
|
66
|
-
* A REPLACE indicates the entry at the current index in the history stack
|
|
67
|
-
* being replaced by a new one.
|
|
68
|
-
*/
|
|
69
53
|
Action["Replace"] = "REPLACE";
|
|
70
|
-
|
|
54
|
+
return Action;
|
|
55
|
+
}({});
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The pathname, search, and hash values of a URL.
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
// TODO: (v7) Change the Location generic default from `any` to `unknown` and
|
|
62
|
+
// remove Remix `useLocation` wrapper.
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* An entry in a history stack. A location contains information about the
|
|
66
|
+
* URL path, as well as possibly some arbitrary state and a key.
|
|
67
|
+
*/
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* A change to the current location.
|
|
71
|
+
*/
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* A function that receives notifications about location changes.
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Describes a location that is the destination of some navigation used in
|
|
79
|
+
* {@link Link}, {@link useNavigate}, etc.
|
|
80
|
+
*/
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* A history is an interface to the navigation stack. The history serves as the
|
|
84
|
+
* source of truth for the current location, as well as provides a set of
|
|
85
|
+
* methods that may be used to change it.
|
|
86
|
+
*
|
|
87
|
+
* It is similar to the DOM's `window.history` object, but with a smaller, more
|
|
88
|
+
* focused API.
|
|
89
|
+
*/
|
|
90
|
+
|
|
71
91
|
const PopStateEventType = "popstate";
|
|
92
|
+
//#endregion
|
|
93
|
+
|
|
94
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
95
|
+
//#region Memory History
|
|
96
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* A user-supplied object that describes a location. Used when providing
|
|
100
|
+
* entries to `createMemoryHistory` via its `initialEntries` option.
|
|
101
|
+
*/
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* A memory history stores locations in memory. This is useful in stateful
|
|
105
|
+
* environments where there is no web browser, such as node tests or React
|
|
106
|
+
* Native.
|
|
107
|
+
*/
|
|
108
|
+
|
|
72
109
|
/**
|
|
73
110
|
* Memory history stores the current location in memory. It is designed for use
|
|
74
111
|
* in stateful non-browser environments like tests and React Native.
|
|
@@ -173,6 +210,20 @@ function createMemoryHistory(options) {
|
|
|
173
210
|
};
|
|
174
211
|
return history;
|
|
175
212
|
}
|
|
213
|
+
//#endregion
|
|
214
|
+
|
|
215
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
216
|
+
//#region Browser History
|
|
217
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* A browser history stores the current location in regular URLs in a web
|
|
221
|
+
* browser environment. This is the standard for most web apps and provides the
|
|
222
|
+
* cleanest URLs the browser's address bar.
|
|
223
|
+
*
|
|
224
|
+
* @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#browserhistory
|
|
225
|
+
*/
|
|
226
|
+
|
|
176
227
|
/**
|
|
177
228
|
* Browser history stores the location in regular URLs. This is the standard for
|
|
178
229
|
* most web apps, but it requires some configuration on the server to ensure you
|
|
@@ -203,6 +254,24 @@ function createBrowserHistory(options) {
|
|
|
203
254
|
}
|
|
204
255
|
return getUrlBasedHistory(createBrowserLocation, createBrowserHref, null, options);
|
|
205
256
|
}
|
|
257
|
+
//#endregion
|
|
258
|
+
|
|
259
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
260
|
+
//#region Hash History
|
|
261
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* A hash history stores the current location in the fragment identifier portion
|
|
265
|
+
* of the URL in a web browser environment.
|
|
266
|
+
*
|
|
267
|
+
* This is ideal for apps that do not control the server for some reason
|
|
268
|
+
* (because the fragment identifier is never sent to the server), including some
|
|
269
|
+
* shared hosting environments that do not provide fine-grained controls over
|
|
270
|
+
* which pages are served at which URLs.
|
|
271
|
+
*
|
|
272
|
+
* @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#hashhistory
|
|
273
|
+
*/
|
|
274
|
+
|
|
206
275
|
/**
|
|
207
276
|
* Hash history stores the location in window.location.hash. This makes it ideal
|
|
208
277
|
* for situations where you don't want to send the location to the server for
|
|
@@ -220,7 +289,8 @@ function createHashHistory(options) {
|
|
|
220
289
|
pathname = "/",
|
|
221
290
|
search = "",
|
|
222
291
|
hash = ""
|
|
223
|
-
} = parsePath(window.location.hash.
|
|
292
|
+
} = parsePath(window.location.hash.substring(1));
|
|
293
|
+
|
|
224
294
|
// Hash URL should always have a leading / just like window.location.pathname
|
|
225
295
|
// does, so if an app ends up at a route like /#something then we add a
|
|
226
296
|
// leading slash so all of our path-matching behaves the same as if it would
|
|
@@ -253,6 +323,16 @@ function createHashHistory(options) {
|
|
|
253
323
|
}
|
|
254
324
|
return getUrlBasedHistory(createHashLocation, createHashHref, validateHashLocation, options);
|
|
255
325
|
}
|
|
326
|
+
//#endregion
|
|
327
|
+
|
|
328
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
329
|
+
//#region UTILS
|
|
330
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* @private
|
|
334
|
+
*/
|
|
335
|
+
|
|
256
336
|
function invariant$2(value, message) {
|
|
257
337
|
if (value === false || value === null || typeof value === "undefined") {
|
|
258
338
|
throw new Error(message);
|
|
@@ -272,8 +352,9 @@ function warning(cond, message) {
|
|
|
272
352
|
}
|
|
273
353
|
}
|
|
274
354
|
function createKey$1() {
|
|
275
|
-
return Math.random().toString(36).
|
|
355
|
+
return Math.random().toString(36).substring(2, 10);
|
|
276
356
|
}
|
|
357
|
+
|
|
277
358
|
/**
|
|
278
359
|
* For browser-based histories, we combine the state and key into an object
|
|
279
360
|
*/
|
|
@@ -284,6 +365,7 @@ function getHistoryState(location, index) {
|
|
|
284
365
|
idx: index
|
|
285
366
|
};
|
|
286
367
|
}
|
|
368
|
+
|
|
287
369
|
/**
|
|
288
370
|
* Creates a Location object with a unique key from the given Path
|
|
289
371
|
*/
|
|
@@ -305,6 +387,7 @@ function createLocation(current, to, state, key) {
|
|
|
305
387
|
});
|
|
306
388
|
return location;
|
|
307
389
|
}
|
|
390
|
+
|
|
308
391
|
/**
|
|
309
392
|
* Creates a string URL path from the given pathname, search, and hash components.
|
|
310
393
|
*
|
|
@@ -320,6 +403,7 @@ function createPath(_ref) {
|
|
|
320
403
|
if (hash && hash !== "#") pathname += hash.charAt(0) === "#" ? hash : "#" + hash;
|
|
321
404
|
return pathname;
|
|
322
405
|
}
|
|
406
|
+
|
|
323
407
|
/**
|
|
324
408
|
* Parses a string URL path into its separate pathname, search, and hash components.
|
|
325
409
|
*
|
|
@@ -330,13 +414,13 @@ function parsePath(path) {
|
|
|
330
414
|
if (path) {
|
|
331
415
|
let hashIndex = path.indexOf("#");
|
|
332
416
|
if (hashIndex >= 0) {
|
|
333
|
-
parsedPath.hash = path.
|
|
334
|
-
path = path.
|
|
417
|
+
parsedPath.hash = path.substring(hashIndex);
|
|
418
|
+
path = path.substring(0, hashIndex);
|
|
335
419
|
}
|
|
336
420
|
let searchIndex = path.indexOf("?");
|
|
337
421
|
if (searchIndex >= 0) {
|
|
338
|
-
parsedPath.search = path.
|
|
339
|
-
path = path.
|
|
422
|
+
parsedPath.search = path.substring(searchIndex);
|
|
423
|
+
path = path.substring(0, searchIndex);
|
|
340
424
|
}
|
|
341
425
|
if (path) {
|
|
342
426
|
parsedPath.pathname = path;
|
|
@@ -391,6 +475,7 @@ function getUrlBasedHistory(getLocation, createHref, validateLocation, options)
|
|
|
391
475
|
index = getIndex() + 1;
|
|
392
476
|
let historyState = getHistoryState(location, index);
|
|
393
477
|
let url = history.createHref(location);
|
|
478
|
+
|
|
394
479
|
// try...catch because iOS limits us to 100 pushState calls :/
|
|
395
480
|
try {
|
|
396
481
|
globalHistory.pushState(historyState, "", url);
|
|
@@ -482,18 +567,165 @@ function getUrlBasedHistory(getLocation, createHref, validateLocation, options)
|
|
|
482
567
|
};
|
|
483
568
|
return history;
|
|
484
569
|
}
|
|
570
|
+
|
|
485
571
|
//#endregion
|
|
486
572
|
|
|
487
|
-
|
|
488
|
-
|
|
573
|
+
/**
|
|
574
|
+
* Map of routeId -> data returned from a loader/action/error
|
|
575
|
+
*/
|
|
576
|
+
|
|
577
|
+
let ResultType = /*#__PURE__*/function (ResultType) {
|
|
489
578
|
ResultType["data"] = "data";
|
|
490
579
|
ResultType["redirect"] = "redirect";
|
|
491
580
|
ResultType["error"] = "error";
|
|
492
|
-
|
|
581
|
+
return ResultType;
|
|
582
|
+
}({});
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* Successful result from a loader or action
|
|
586
|
+
*/
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Redirect result from a loader or action
|
|
590
|
+
*/
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* Unsuccessful result from a loader or action
|
|
594
|
+
*/
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* Result from a loader or action - potentially successful or unsuccessful
|
|
598
|
+
*/
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* Users can specify either lowercase or uppercase form methods on `<Form>`,
|
|
602
|
+
* useSubmit(), `<fetcher.Form>`, etc.
|
|
603
|
+
*/
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Active navigation/fetcher form methods are exposed in uppercase on the
|
|
607
|
+
* RouterState. This is to align with the normalization done via fetch().
|
|
608
|
+
*/
|
|
609
|
+
|
|
610
|
+
// Thanks https://github.com/sindresorhus/type-fest!
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* @private
|
|
614
|
+
* Internal interface to pass around for action submissions, not intended for
|
|
615
|
+
* external consumption
|
|
616
|
+
*/
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* @private
|
|
620
|
+
* Arguments passed to route loader/action functions. Same for now but we keep
|
|
621
|
+
* this as a private implementation detail in case they diverge in the future.
|
|
622
|
+
*/
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* Arguments passed to loader functions
|
|
626
|
+
*/
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* Arguments passed to action functions
|
|
630
|
+
*/
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Loaders and actions can return anything except `undefined` (`null` is a
|
|
634
|
+
* valid return value if there is no data to return). Responses are preferred
|
|
635
|
+
* and will ease any future migration to Remix
|
|
636
|
+
*/
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Route loader function signature
|
|
640
|
+
*/
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Route action function signature
|
|
644
|
+
*/
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Arguments passed to shouldRevalidate function
|
|
648
|
+
*/
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Route shouldRevalidate function signature. This runs after any submission
|
|
652
|
+
* (navigation or fetcher), so we flatten the navigation/fetcher submission
|
|
653
|
+
* onto the arguments. It shouldn't matter whether it came from a navigation
|
|
654
|
+
* or a fetcher, what really matters is the URLs and the formData since loaders
|
|
655
|
+
* have to re-run based on the data models that were potentially mutated.
|
|
656
|
+
*/
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Result from a loader or action called via dataStrategy
|
|
660
|
+
*/
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Function provided by the framework-aware layers to set any framework-specific
|
|
664
|
+
* properties from framework-agnostic properties
|
|
665
|
+
*/
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Keys we cannot change from within a lazy() function. We spread all other keys
|
|
669
|
+
* onto the route. Either they're meaningful to the router, or they'll get
|
|
670
|
+
* ignored.
|
|
671
|
+
*/
|
|
672
|
+
|
|
493
673
|
const immutableRouteKeys = new Set(["lazy", "caseSensitive", "path", "id", "index", "children"]);
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* lazy() function to load a route definition, which can add non-matching
|
|
677
|
+
* related properties to a route
|
|
678
|
+
*/
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Base RouteObject with common props shared by all types of routes
|
|
682
|
+
*/
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Index routes must not have children
|
|
686
|
+
*/
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* Non-index routes may have children, but cannot have index
|
|
690
|
+
*/
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* A route object represents a logical route, with (optionally) its child
|
|
694
|
+
* routes organized in a tree-like structure.
|
|
695
|
+
*/
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* A data route object, which is just a RouteObject with a required unique ID
|
|
699
|
+
*/
|
|
700
|
+
|
|
701
|
+
// Recursive helper for finding path parameters in the absence of wildcards
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* Examples:
|
|
705
|
+
* "/a/b/*" -> "*"
|
|
706
|
+
* ":a" -> "a"
|
|
707
|
+
* "/a/:b" -> "b"
|
|
708
|
+
* "/a/blahblahblah:b" -> "b"
|
|
709
|
+
* "/:a/:b" -> "a" | "b"
|
|
710
|
+
* "/:a/b/:c/*" -> "a" | "c" | "*"
|
|
711
|
+
*/
|
|
712
|
+
|
|
713
|
+
// Attempt to parse the given string segment. If it fails, then just return the
|
|
714
|
+
// plain string type as a default fallback. Otherwise, return the union of the
|
|
715
|
+
// parsed string literals that were referenced as dynamic segments in the route.
|
|
716
|
+
|
|
717
|
+
/**
|
|
718
|
+
* The parameters that were parsed from the URL path.
|
|
719
|
+
*/
|
|
720
|
+
|
|
721
|
+
/**
|
|
722
|
+
* A RouteMatch contains info about how a route matched a URL.
|
|
723
|
+
*/
|
|
724
|
+
|
|
494
725
|
function isIndexRoute(route) {
|
|
495
726
|
return route.index === true;
|
|
496
727
|
}
|
|
728
|
+
|
|
497
729
|
// Walk the route tree generating unique IDs where necessary, so we are working
|
|
498
730
|
// solely with AgnosticDataRouteObject's within the Router
|
|
499
731
|
function convertRoutesToDataRoutes(routes, mapRouteProperties, parentPath, manifest) {
|
|
@@ -527,6 +759,7 @@ function convertRoutesToDataRoutes(routes, mapRouteProperties, parentPath, manif
|
|
|
527
759
|
}
|
|
528
760
|
});
|
|
529
761
|
}
|
|
762
|
+
|
|
530
763
|
/**
|
|
531
764
|
* Matches the given routes to a location and returns the match data.
|
|
532
765
|
*
|
|
@@ -596,6 +829,7 @@ function flattenRoutes(routes, branches, parentsMeta, parentPath) {
|
|
|
596
829
|
}
|
|
597
830
|
let path = joinPaths([parentPath, meta.relativePath]);
|
|
598
831
|
let routesMeta = parentsMeta.concat(meta);
|
|
832
|
+
|
|
599
833
|
// Add the children before adding this route to the array, so we traverse the
|
|
600
834
|
// route tree depth-first and child routes appear before their parents in
|
|
601
835
|
// the "flattened" version.
|
|
@@ -606,6 +840,7 @@ function flattenRoutes(routes, branches, parentsMeta, parentPath) {
|
|
|
606
840
|
route.index !== true) ? process.env.NODE_ENV !== "production" ? invariant$2(false, "Index routes must not have child routes. Please remove " + ("all child routes from route path \"" + path + "\".")) : invariant$2(false) : void 0;
|
|
607
841
|
flattenRoutes(route.children, branches, routesMeta, path);
|
|
608
842
|
}
|
|
843
|
+
|
|
609
844
|
// Routes without a path shouldn't ever match by themselves unless they are
|
|
610
845
|
// index routes, so don't add them to the list of possible branches.
|
|
611
846
|
if (route.path == null && !route.index) {
|
|
@@ -630,6 +865,7 @@ function flattenRoutes(routes, branches, parentsMeta, parentPath) {
|
|
|
630
865
|
});
|
|
631
866
|
return branches;
|
|
632
867
|
}
|
|
868
|
+
|
|
633
869
|
/**
|
|
634
870
|
* Computes all combinations of optional path segments for a given path,
|
|
635
871
|
* excluding combinations that are ambiguous and of lower priority.
|
|
@@ -648,6 +884,7 @@ function explodeOptionalSegments(path) {
|
|
|
648
884
|
let segments = path.split("/");
|
|
649
885
|
if (segments.length === 0) return [];
|
|
650
886
|
let [first, ...rest] = segments;
|
|
887
|
+
|
|
651
888
|
// Optional path segments are denoted by a trailing `?`
|
|
652
889
|
let isOptional = first.endsWith("?");
|
|
653
890
|
// Compute the corresponding required segment: `foo?` -> `foo`
|
|
@@ -659,6 +896,7 @@ function explodeOptionalSegments(path) {
|
|
|
659
896
|
}
|
|
660
897
|
let restExploded = explodeOptionalSegments(rest.join("/"));
|
|
661
898
|
let result = [];
|
|
899
|
+
|
|
662
900
|
// All child paths with the prefix. Do this for all children before the
|
|
663
901
|
// optional version for all children, so we get consistent ordering where the
|
|
664
902
|
// parent optional aspect is preferred as required. Otherwise, we can get
|
|
@@ -667,10 +905,12 @@ function explodeOptionalSegments(path) {
|
|
|
667
905
|
// then /:one. By always including the parent as required _for all children_
|
|
668
906
|
// first, we avoid this issue
|
|
669
907
|
result.push(...restExploded.map(subpath => subpath === "" ? required : [required, subpath].join("/")));
|
|
908
|
+
|
|
670
909
|
// Then, if this is an optional value, add all child versions without
|
|
671
910
|
if (isOptional) {
|
|
672
911
|
result.push(...restExploded);
|
|
673
912
|
}
|
|
913
|
+
|
|
674
914
|
// for absolute paths, ensure `/` instead of empty segment
|
|
675
915
|
return result.map(exploded => path.startsWith("/") && exploded === "" ? "/" : exploded);
|
|
676
916
|
}
|
|
@@ -752,6 +992,7 @@ function matchRouteBranch(branch, pathname, allowPartial) {
|
|
|
752
992
|
}
|
|
753
993
|
return matches;
|
|
754
994
|
}
|
|
995
|
+
|
|
755
996
|
/**
|
|
756
997
|
* Returns a path with params interpolated.
|
|
757
998
|
*
|
|
@@ -766,11 +1007,13 @@ function generatePath(originalPath, params) {
|
|
|
766
1007
|
process.env.NODE_ENV !== "production" ? warning(false, "Route path \"" + path + "\" will be treated as if it were " + ("\"" + path.replace(/\*$/, "/*") + "\" because the `*` character must ") + "always follow a `/` in the pattern. To get rid of this warning, " + ("please change the route path to \"" + path.replace(/\*$/, "/*") + "\".")) : void 0;
|
|
767
1008
|
path = path.replace(/\*$/, "/*");
|
|
768
1009
|
}
|
|
1010
|
+
|
|
769
1011
|
// ensure `/` is added at the beginning if the path is absolute
|
|
770
1012
|
const prefix = path.startsWith("/") ? "/" : "";
|
|
771
1013
|
const stringify = p => p == null ? "" : typeof p === "string" ? p : String(p);
|
|
772
1014
|
const segments = path.split(/\/+/).map((segment, index, array) => {
|
|
773
1015
|
const isLastSegment = index === array.length - 1;
|
|
1016
|
+
|
|
774
1017
|
// only apply the splat if it's the last segment
|
|
775
1018
|
if (isLastSegment && segment === "*") {
|
|
776
1019
|
const star = "*";
|
|
@@ -784,6 +1027,7 @@ function generatePath(originalPath, params) {
|
|
|
784
1027
|
!(optional === "?" || param != null) ? process.env.NODE_ENV !== "production" ? invariant$2(false, "Missing \":" + key + "\" param") : invariant$2(false) : void 0;
|
|
785
1028
|
return stringify(param);
|
|
786
1029
|
}
|
|
1030
|
+
|
|
787
1031
|
// Remove any optional markers from optional static segments
|
|
788
1032
|
return segment.replace(/\?$/g, "");
|
|
789
1033
|
})
|
|
@@ -791,6 +1035,15 @@ function generatePath(originalPath, params) {
|
|
|
791
1035
|
.filter(segment => !!segment);
|
|
792
1036
|
return prefix + segments.join("/");
|
|
793
1037
|
}
|
|
1038
|
+
|
|
1039
|
+
/**
|
|
1040
|
+
* A PathPattern is used to match on some portion of a URL pathname.
|
|
1041
|
+
*/
|
|
1042
|
+
|
|
1043
|
+
/**
|
|
1044
|
+
* A PathMatch contains info about how a PathPattern matched on a URL pathname.
|
|
1045
|
+
*/
|
|
1046
|
+
|
|
794
1047
|
/**
|
|
795
1048
|
* Performs pattern matching on a URL pathname and returns information about
|
|
796
1049
|
* the match.
|
|
@@ -886,6 +1139,7 @@ function decodePath(value) {
|
|
|
886
1139
|
return value;
|
|
887
1140
|
}
|
|
888
1141
|
}
|
|
1142
|
+
|
|
889
1143
|
/**
|
|
890
1144
|
* @private
|
|
891
1145
|
*/
|
|
@@ -894,6 +1148,7 @@ function stripBasename(pathname, basename) {
|
|
|
894
1148
|
if (!pathname.toLowerCase().startsWith(basename.toLowerCase())) {
|
|
895
1149
|
return null;
|
|
896
1150
|
}
|
|
1151
|
+
|
|
897
1152
|
// We want to leave trailing slash behavior in the user's control, so if they
|
|
898
1153
|
// specify a basename with a trailing slash, we should support it
|
|
899
1154
|
let startIndex = basename.endsWith("/") ? basename.length - 1 : basename.length;
|
|
@@ -904,6 +1159,7 @@ function stripBasename(pathname, basename) {
|
|
|
904
1159
|
}
|
|
905
1160
|
return pathname.slice(startIndex) || "/";
|
|
906
1161
|
}
|
|
1162
|
+
|
|
907
1163
|
/**
|
|
908
1164
|
* Returns a resolved path object relative to the given pathname.
|
|
909
1165
|
*
|
|
@@ -941,6 +1197,7 @@ function resolvePathname(relativePath, fromPathname) {
|
|
|
941
1197
|
function getInvalidPathError(char, field, dest, path) {
|
|
942
1198
|
return "Cannot include a '" + char + "' character in a manually specified " + ("`to." + field + "` field [" + JSON.stringify(path) + "]. Please separate it out to the ") + ("`to." + dest + "` field. Alternatively you may provide the full path as ") + "a string in <Link to=\"...\"> and the router will parse it for you.";
|
|
943
1199
|
}
|
|
1200
|
+
|
|
944
1201
|
/**
|
|
945
1202
|
* @private
|
|
946
1203
|
*
|
|
@@ -967,14 +1224,17 @@ function getInvalidPathError(char, field, dest, path) {
|
|
|
967
1224
|
function getPathContributingMatches(matches) {
|
|
968
1225
|
return matches.filter((match, index) => index === 0 || match.route.path && match.route.path.length > 0);
|
|
969
1226
|
}
|
|
1227
|
+
|
|
970
1228
|
// Return the array of pathnames for the current route matches - used to
|
|
971
1229
|
// generate the routePathnames input for resolveTo()
|
|
972
1230
|
function getResolveToMatches(matches) {
|
|
973
1231
|
let pathMatches = getPathContributingMatches(matches);
|
|
1232
|
+
|
|
974
1233
|
// Use the full pathname for the leaf match so we include splat values for "." links
|
|
975
1234
|
// https://github.com/remix-run/react-router/issues/11052#issuecomment-1836589329
|
|
976
1235
|
return pathMatches.map((match, idx) => idx === pathMatches.length - 1 ? match.pathname : match.pathnameBase);
|
|
977
1236
|
}
|
|
1237
|
+
|
|
978
1238
|
/**
|
|
979
1239
|
* @private
|
|
980
1240
|
*/
|
|
@@ -994,6 +1254,7 @@ function resolveTo(toArg, routePathnames, locationPathname, isPathRelative) {
|
|
|
994
1254
|
let isEmptyPath = toArg === "" || to.pathname === "";
|
|
995
1255
|
let toPathname = isEmptyPath ? "/" : to.pathname;
|
|
996
1256
|
let from;
|
|
1257
|
+
|
|
997
1258
|
// Routing is relative to the current pathname if explicitly requested.
|
|
998
1259
|
//
|
|
999
1260
|
// If a pathname is explicitly provided in `to`, it should be relative to the
|
|
@@ -1007,6 +1268,7 @@ function resolveTo(toArg, routePathnames, locationPathname, isPathRelative) {
|
|
|
1007
1268
|
from = locationPathname;
|
|
1008
1269
|
} else {
|
|
1009
1270
|
let routePathnameIndex = routePathnames.length - 1;
|
|
1271
|
+
|
|
1010
1272
|
// With relative="route" (the default), each leading .. segment means
|
|
1011
1273
|
// "go up one route" instead of "go up one URL segment". This is a key
|
|
1012
1274
|
// difference from how <a href> works and a major reason we call this a
|
|
@@ -1022,6 +1284,7 @@ function resolveTo(toArg, routePathnames, locationPathname, isPathRelative) {
|
|
|
1022
1284
|
from = routePathnameIndex >= 0 ? routePathnames[routePathnameIndex] : "/";
|
|
1023
1285
|
}
|
|
1024
1286
|
let path = resolvePath(to, from);
|
|
1287
|
+
|
|
1025
1288
|
// Ensure the pathname has a trailing slash if the original "to" had one
|
|
1026
1289
|
let hasExplicitTrailingSlash = toPathname && toPathname !== "/" && toPathname.endsWith("/");
|
|
1027
1290
|
// Or if this was a link to the current path which has a trailing slash
|
|
@@ -1031,43 +1294,26 @@ function resolveTo(toArg, routePathnames, locationPathname, isPathRelative) {
|
|
|
1031
1294
|
}
|
|
1032
1295
|
return path;
|
|
1033
1296
|
}
|
|
1297
|
+
|
|
1034
1298
|
/**
|
|
1035
1299
|
* @private
|
|
1036
1300
|
*/
|
|
1037
1301
|
const joinPaths = paths => paths.join("/").replace(/\/\/+/g, "/");
|
|
1302
|
+
|
|
1038
1303
|
/**
|
|
1039
1304
|
* @private
|
|
1040
1305
|
*/
|
|
1041
1306
|
const normalizePathname = pathname => pathname.replace(/\/+$/, "").replace(/^\/*/, "/");
|
|
1307
|
+
|
|
1042
1308
|
/**
|
|
1043
1309
|
* @private
|
|
1044
1310
|
*/
|
|
1045
1311
|
const normalizeSearch = search => !search || search === "?" ? "" : search.startsWith("?") ? search : "?" + search;
|
|
1312
|
+
|
|
1046
1313
|
/**
|
|
1047
1314
|
* @private
|
|
1048
1315
|
*/
|
|
1049
1316
|
const normalizeHash = hash => !hash || hash === "#" ? "" : hash.startsWith("#") ? hash : "#" + hash;
|
|
1050
|
-
/**
|
|
1051
|
-
* This is a shortcut for creating `application/json` responses. Converts `data`
|
|
1052
|
-
* to JSON and sets the `Content-Type` header.
|
|
1053
|
-
*
|
|
1054
|
-
* @category Utils
|
|
1055
|
-
*/
|
|
1056
|
-
const json$1 = function json(data, init) {
|
|
1057
|
-
if (init === void 0) {
|
|
1058
|
-
init = {};
|
|
1059
|
-
}
|
|
1060
|
-
let responseInit = typeof init === "number" ? {
|
|
1061
|
-
status: init
|
|
1062
|
-
} : init;
|
|
1063
|
-
let headers = new Headers(responseInit.headers);
|
|
1064
|
-
if (!headers.has("Content-Type")) {
|
|
1065
|
-
headers.set("Content-Type", "application/json; charset=utf-8");
|
|
1066
|
-
}
|
|
1067
|
-
return new Response(JSON.stringify(data), _extends({}, responseInit, {
|
|
1068
|
-
headers
|
|
1069
|
-
}));
|
|
1070
|
-
};
|
|
1071
1317
|
class DataWithResponseInit {
|
|
1072
1318
|
constructor(data, init) {
|
|
1073
1319
|
this.type = "DataWithResponseInit";
|
|
@@ -1075,6 +1321,7 @@ class DataWithResponseInit {
|
|
|
1075
1321
|
this.init = init || null;
|
|
1076
1322
|
}
|
|
1077
1323
|
}
|
|
1324
|
+
|
|
1078
1325
|
/**
|
|
1079
1326
|
* Create "responses" that contain `status`/`headers` without forcing
|
|
1080
1327
|
* serialization into an actual `Response` - used by Remix single fetch
|
|
@@ -1086,6 +1333,10 @@ function data(data, init) {
|
|
|
1086
1333
|
status: init
|
|
1087
1334
|
} : init);
|
|
1088
1335
|
}
|
|
1336
|
+
|
|
1337
|
+
// This is now only used by the Await component and will eventually probably
|
|
1338
|
+
// go away in favor of the format used by `React.use`
|
|
1339
|
+
|
|
1089
1340
|
/**
|
|
1090
1341
|
* A redirect response. Sets the status code and the `Location` header.
|
|
1091
1342
|
* Defaults to "302 Found".
|
|
@@ -1110,6 +1361,7 @@ const redirect = function redirect(url, init) {
|
|
|
1110
1361
|
headers
|
|
1111
1362
|
}));
|
|
1112
1363
|
};
|
|
1364
|
+
|
|
1113
1365
|
/**
|
|
1114
1366
|
* A redirect response that will force a document reload to the new location.
|
|
1115
1367
|
* Sets the status code and the `Location` header.
|
|
@@ -1122,6 +1374,7 @@ const redirectDocument = (url, init) => {
|
|
|
1122
1374
|
response.headers.set("X-Remix-Reload-Document", "true");
|
|
1123
1375
|
return response;
|
|
1124
1376
|
};
|
|
1377
|
+
|
|
1125
1378
|
/**
|
|
1126
1379
|
* A redirect response that will perform a `history.replaceState` instead of a
|
|
1127
1380
|
* `history.pushState` for client-side navigation redirects.
|
|
@@ -1159,6 +1412,7 @@ class ErrorResponseImpl {
|
|
|
1159
1412
|
}
|
|
1160
1413
|
}
|
|
1161
1414
|
}
|
|
1415
|
+
|
|
1162
1416
|
/**
|
|
1163
1417
|
* Check if the given error is an ErrorResponse generated from a 4xx/5xx
|
|
1164
1418
|
* Response thrown from an action/loader
|
|
@@ -1169,11 +1423,109 @@ function isRouteErrorResponse(error) {
|
|
|
1169
1423
|
return error != null && typeof error.status === "number" && typeof error.statusText === "string" && typeof error.internal === "boolean" && "data" in error;
|
|
1170
1424
|
}
|
|
1171
1425
|
|
|
1426
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1427
|
+
//#region Types and Constants
|
|
1428
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
1429
|
+
|
|
1430
|
+
/**
|
|
1431
|
+
* A Router instance manages all navigation and data loading/mutations
|
|
1432
|
+
*/
|
|
1433
|
+
|
|
1434
|
+
/**
|
|
1435
|
+
* State maintained internally by the router. During a navigation, all states
|
|
1436
|
+
* reflect the the "old" location unless otherwise noted.
|
|
1437
|
+
*/
|
|
1438
|
+
|
|
1439
|
+
/**
|
|
1440
|
+
* Data that can be passed into hydrate a Router from SSR
|
|
1441
|
+
*/
|
|
1442
|
+
|
|
1443
|
+
/**
|
|
1444
|
+
* Future flags to toggle new feature behavior
|
|
1445
|
+
*/
|
|
1446
|
+
|
|
1447
|
+
/**
|
|
1448
|
+
* Initialization options for createRouter
|
|
1449
|
+
*/
|
|
1450
|
+
|
|
1451
|
+
/**
|
|
1452
|
+
* State returned from a server-side query() call
|
|
1453
|
+
*/
|
|
1454
|
+
|
|
1455
|
+
/**
|
|
1456
|
+
* A StaticHandler instance manages a singular SSR navigation/fetch event
|
|
1457
|
+
*/
|
|
1458
|
+
|
|
1459
|
+
/**
|
|
1460
|
+
* Subscriber function signature for changes to router state
|
|
1461
|
+
*/
|
|
1462
|
+
|
|
1463
|
+
/**
|
|
1464
|
+
* Function signature for determining the key to be used in scroll restoration
|
|
1465
|
+
* for a given location
|
|
1466
|
+
*/
|
|
1467
|
+
|
|
1468
|
+
/**
|
|
1469
|
+
* Function signature for determining the current scroll position
|
|
1470
|
+
*/
|
|
1471
|
+
|
|
1472
|
+
/**
|
|
1473
|
+
- "route": relative to the route hierarchy so `..` means remove all segments of the current route even if it has many. For example, a `route("posts/:id")` would have both `:id` and `posts` removed from the url.
|
|
1474
|
+
- "path": relative to the pathname so `..` means remove one segment of the pathname. For example, a `route("posts/:id")` would have only `:id` removed from the url.
|
|
1475
|
+
*/
|
|
1476
|
+
|
|
1477
|
+
// Allowed for any navigation or fetch
|
|
1478
|
+
|
|
1479
|
+
// Only allowed for navigations
|
|
1480
|
+
|
|
1481
|
+
// Only allowed for submission navigations
|
|
1482
|
+
|
|
1483
|
+
/**
|
|
1484
|
+
* Options for a navigate() call for a normal (non-submission) navigation
|
|
1485
|
+
*/
|
|
1486
|
+
|
|
1487
|
+
/**
|
|
1488
|
+
* Options for a navigate() call for a submission navigation
|
|
1489
|
+
*/
|
|
1490
|
+
|
|
1491
|
+
/**
|
|
1492
|
+
* Options to pass to navigate() for a navigation
|
|
1493
|
+
*/
|
|
1494
|
+
|
|
1495
|
+
/**
|
|
1496
|
+
* Options for a fetch() load
|
|
1497
|
+
*/
|
|
1498
|
+
|
|
1499
|
+
/**
|
|
1500
|
+
* Options for a fetch() submission
|
|
1501
|
+
*/
|
|
1502
|
+
|
|
1503
|
+
/**
|
|
1504
|
+
* Options to pass to fetch()
|
|
1505
|
+
*/
|
|
1506
|
+
|
|
1507
|
+
/**
|
|
1508
|
+
* Potential states for state.navigation
|
|
1509
|
+
*/
|
|
1510
|
+
|
|
1511
|
+
/**
|
|
1512
|
+
* Potential states for fetchers
|
|
1513
|
+
*/
|
|
1514
|
+
|
|
1515
|
+
/**
|
|
1516
|
+
* Cached info for active fetcher.load() instances so they can participate
|
|
1517
|
+
* in revalidation
|
|
1518
|
+
*/
|
|
1519
|
+
|
|
1520
|
+
/**
|
|
1521
|
+
* Identified fetcher.load() calls that need to be revalidated
|
|
1522
|
+
*/
|
|
1523
|
+
|
|
1172
1524
|
const validMutationMethodsArr = ["POST", "PUT", "PATCH", "DELETE"];
|
|
1173
1525
|
const validMutationMethods = new Set(validMutationMethodsArr);
|
|
1174
1526
|
const validRequestMethodsArr = ["GET", ...validMutationMethodsArr];
|
|
1175
1527
|
const validRequestMethods = new Set(validRequestMethodsArr);
|
|
1176
|
-
const redirectStatusCodes
|
|
1528
|
+
const redirectStatusCodes = new Set([301, 302, 303, 307, 308]);
|
|
1177
1529
|
const redirectPreserveMethodStatusCodes = new Set([307, 308]);
|
|
1178
1530
|
const IDLE_NAVIGATION = {
|
|
1179
1531
|
state: "idle",
|
|
@@ -1206,13 +1558,17 @@ const defaultMapRouteProperties = route => ({
|
|
|
1206
1558
|
hasErrorBoundary: Boolean(route.hasErrorBoundary)
|
|
1207
1559
|
});
|
|
1208
1560
|
const TRANSITIONS_STORAGE_KEY = "remix-router-transitions";
|
|
1561
|
+
|
|
1209
1562
|
// Flag used on new `loaderData` to indicate that we do not want to preserve
|
|
1210
1563
|
// any prior loader data from the throwing route in `mergeLoaderData`
|
|
1211
1564
|
const ResetLoaderDataSymbol = Symbol("ResetLoaderData");
|
|
1565
|
+
|
|
1212
1566
|
//#endregion
|
|
1567
|
+
|
|
1213
1568
|
////////////////////////////////////////////////////////////////////////////////
|
|
1214
1569
|
//#region createRouter
|
|
1215
1570
|
////////////////////////////////////////////////////////////////////////////////
|
|
1571
|
+
|
|
1216
1572
|
/**
|
|
1217
1573
|
* Create a router and listen to history POP navigations
|
|
1218
1574
|
*/
|
|
@@ -1221,6 +1577,7 @@ function createRouter(init) {
|
|
|
1221
1577
|
const isBrowser = typeof routerWindow !== "undefined" && typeof routerWindow.document !== "undefined" && typeof routerWindow.document.createElement !== "undefined";
|
|
1222
1578
|
!(init.routes.length > 0) ? process.env.NODE_ENV !== "production" ? invariant$2(false, "You must provide a non-empty routes array to createRouter") : invariant$2(false) : void 0;
|
|
1223
1579
|
let mapRouteProperties = init.mapRouteProperties || defaultMapRouteProperties;
|
|
1580
|
+
|
|
1224
1581
|
// Routes keyed by ID
|
|
1225
1582
|
let manifest = {};
|
|
1226
1583
|
// Routes in tree format for matching
|
|
@@ -1229,6 +1586,7 @@ function createRouter(init) {
|
|
|
1229
1586
|
let basename = init.basename || "/";
|
|
1230
1587
|
let dataStrategyImpl = init.dataStrategy || defaultDataStrategy;
|
|
1231
1588
|
let patchRoutesOnNavigationImpl = init.patchRoutesOnNavigation;
|
|
1589
|
+
|
|
1232
1590
|
// Config driven behavior flags
|
|
1233
1591
|
let future = _extends({}, init.future);
|
|
1234
1592
|
// Cleanup function for history
|
|
@@ -1265,6 +1623,7 @@ function createRouter(init) {
|
|
|
1265
1623
|
[route.id]: error
|
|
1266
1624
|
};
|
|
1267
1625
|
}
|
|
1626
|
+
|
|
1268
1627
|
// In SPA apps, if the user provided a patchRoutesOnNavigation implementation and
|
|
1269
1628
|
// our initial match is a splat route, clear them out so we run through lazy
|
|
1270
1629
|
// discovery on hydration in case there's a more accurate lazy route match.
|
|
@@ -1281,6 +1640,7 @@ function createRouter(init) {
|
|
|
1281
1640
|
if (!initialMatches) {
|
|
1282
1641
|
initialized = false;
|
|
1283
1642
|
initialMatches = [];
|
|
1643
|
+
|
|
1284
1644
|
// If partial hydration and fog of war is enabled, we will be running
|
|
1285
1645
|
// `patchRoutesOnNavigation` during hydration so include any partial matches as
|
|
1286
1646
|
// the initial matches so we can properly render `HydrateFallback`'s
|
|
@@ -1326,57 +1686,77 @@ function createRouter(init) {
|
|
|
1326
1686
|
fetchers: new Map(),
|
|
1327
1687
|
blockers: new Map()
|
|
1328
1688
|
};
|
|
1689
|
+
|
|
1329
1690
|
// -- Stateful internal variables to manage navigations --
|
|
1330
1691
|
// Current navigation in progress (to be committed in completeNavigation)
|
|
1331
1692
|
let pendingAction = Action.Pop;
|
|
1693
|
+
|
|
1332
1694
|
// Should the current navigation prevent the scroll reset if scroll cannot
|
|
1333
1695
|
// be restored?
|
|
1334
1696
|
let pendingPreventScrollReset = false;
|
|
1697
|
+
|
|
1335
1698
|
// AbortController for the active navigation
|
|
1336
1699
|
let pendingNavigationController;
|
|
1700
|
+
|
|
1337
1701
|
// Should the current navigation enable document.startViewTransition?
|
|
1338
1702
|
let pendingViewTransitionEnabled = false;
|
|
1703
|
+
|
|
1339
1704
|
// Store applied view transitions so we can apply them on POP
|
|
1340
1705
|
let appliedViewTransitions = new Map();
|
|
1706
|
+
|
|
1341
1707
|
// Cleanup function for persisting applied transitions to sessionStorage
|
|
1342
1708
|
let removePageHideEventListener = null;
|
|
1709
|
+
|
|
1343
1710
|
// We use this to avoid touching history in completeNavigation if a
|
|
1344
1711
|
// revalidation is entirely uninterrupted
|
|
1345
1712
|
let isUninterruptedRevalidation = false;
|
|
1713
|
+
|
|
1346
1714
|
// Use this internal flag to force revalidation of all loaders:
|
|
1347
1715
|
// - submissions (completed or interrupted)
|
|
1348
1716
|
// - useRevalidator()
|
|
1349
1717
|
// - X-Remix-Revalidate (from redirect)
|
|
1350
1718
|
let isRevalidationRequired = false;
|
|
1719
|
+
|
|
1351
1720
|
// Use this internal array to capture fetcher loads that were cancelled by an
|
|
1352
1721
|
// action navigation and require revalidation
|
|
1353
1722
|
let cancelledFetcherLoads = new Set();
|
|
1723
|
+
|
|
1354
1724
|
// AbortControllers for any in-flight fetchers
|
|
1355
1725
|
let fetchControllers = new Map();
|
|
1726
|
+
|
|
1356
1727
|
// Track loads based on the order in which they started
|
|
1357
1728
|
let incrementingLoadId = 0;
|
|
1729
|
+
|
|
1358
1730
|
// Track the outstanding pending navigation data load to be compared against
|
|
1359
1731
|
// the globally incrementing load when a fetcher load lands after a completed
|
|
1360
1732
|
// navigation
|
|
1361
1733
|
let pendingNavigationLoadId = -1;
|
|
1734
|
+
|
|
1362
1735
|
// Fetchers that triggered data reloads as a result of their actions
|
|
1363
1736
|
let fetchReloadIds = new Map();
|
|
1737
|
+
|
|
1364
1738
|
// Fetchers that triggered redirect navigations
|
|
1365
1739
|
let fetchRedirectIds = new Set();
|
|
1740
|
+
|
|
1366
1741
|
// Most recent href/match for fetcher.load calls for fetchers
|
|
1367
1742
|
let fetchLoadMatches = new Map();
|
|
1743
|
+
|
|
1368
1744
|
// Ref-count mounted fetchers so we know when it's ok to clean them up
|
|
1369
1745
|
let activeFetchers = new Map();
|
|
1746
|
+
|
|
1370
1747
|
// Fetchers queued for deletion because they've been removed from the UI.
|
|
1371
1748
|
// These will be officially deleted after they return to idle
|
|
1372
1749
|
let fetchersQueuedForDeletion = new Set();
|
|
1750
|
+
|
|
1373
1751
|
// Store blocker functions in a separate Map outside of router state since
|
|
1374
1752
|
// we don't need to update UI state if they change
|
|
1375
1753
|
let blockerFunctions = new Map();
|
|
1754
|
+
|
|
1376
1755
|
// Flag to ignore the next history update, so we can revert the URL change on
|
|
1377
1756
|
// a POP navigation that was blocked by the user without touching router state
|
|
1378
1757
|
let unblockBlockerHistoryUpdate = undefined;
|
|
1379
1758
|
let pendingRevalidationDfd = null;
|
|
1759
|
+
|
|
1380
1760
|
// Initialize the router, all side effects should be kicked off from here.
|
|
1381
1761
|
// Implemented as a Fluent API for ease of:
|
|
1382
1762
|
// let router = createRouter(init).initialize();
|
|
@@ -1408,6 +1788,7 @@ function createRouter(init) {
|
|
|
1408
1788
|
unblockBlockerHistoryUpdate = resolve;
|
|
1409
1789
|
});
|
|
1410
1790
|
init.history.go(delta * -1);
|
|
1791
|
+
|
|
1411
1792
|
// Put the blocker into a blocked state
|
|
1412
1793
|
updateBlocker(blockerKey, {
|
|
1413
1794
|
state: "blocked",
|
|
@@ -1444,6 +1825,7 @@ function createRouter(init) {
|
|
|
1444
1825
|
routerWindow.addEventListener("pagehide", _saveAppliedTransitions);
|
|
1445
1826
|
removePageHideEventListener = () => routerWindow.removeEventListener("pagehide", _saveAppliedTransitions);
|
|
1446
1827
|
}
|
|
1828
|
+
|
|
1447
1829
|
// Kick off initial data load if needed. Use Pop to avoid modifying history
|
|
1448
1830
|
// Note we don't do any handling of lazy here. For SPA's it'll get handled
|
|
1449
1831
|
// in the normal navigation flow. For SSR it's expected that lazy modules are
|
|
@@ -1456,6 +1838,7 @@ function createRouter(init) {
|
|
|
1456
1838
|
}
|
|
1457
1839
|
return router;
|
|
1458
1840
|
}
|
|
1841
|
+
|
|
1459
1842
|
// Clean up a router and it's side effects
|
|
1460
1843
|
function dispose() {
|
|
1461
1844
|
if (unlistenHistory) {
|
|
@@ -1469,17 +1852,20 @@ function createRouter(init) {
|
|
|
1469
1852
|
state.fetchers.forEach((_, key) => deleteFetcher(key));
|
|
1470
1853
|
state.blockers.forEach((_, key) => deleteBlocker(key));
|
|
1471
1854
|
}
|
|
1855
|
+
|
|
1472
1856
|
// Subscribe to state updates for the router
|
|
1473
1857
|
function subscribe(fn) {
|
|
1474
1858
|
subscribers.add(fn);
|
|
1475
1859
|
return () => subscribers.delete(fn);
|
|
1476
1860
|
}
|
|
1861
|
+
|
|
1477
1862
|
// Update our state and notify the calling context of the change
|
|
1478
1863
|
function updateState(newState, opts) {
|
|
1479
1864
|
if (opts === void 0) {
|
|
1480
1865
|
opts = {};
|
|
1481
1866
|
}
|
|
1482
1867
|
state = _extends({}, state, newState);
|
|
1868
|
+
|
|
1483
1869
|
// Cleanup for all fetchers that have returned to idle since we only
|
|
1484
1870
|
// care about in-flight fetchers
|
|
1485
1871
|
// - If it's been unmounted then we can completely delete it
|
|
@@ -1497,6 +1883,7 @@ function createRouter(init) {
|
|
|
1497
1883
|
}
|
|
1498
1884
|
}
|
|
1499
1885
|
});
|
|
1886
|
+
|
|
1500
1887
|
// Iterate over a local copy so that if flushSync is used and we end up
|
|
1501
1888
|
// removing and adding a new subscriber due to the useCallback dependencies,
|
|
1502
1889
|
// we don't get ourselves into a loop calling the new subscriber immediately
|
|
@@ -1505,10 +1892,12 @@ function createRouter(init) {
|
|
|
1505
1892
|
viewTransitionOpts: opts.viewTransitionOpts,
|
|
1506
1893
|
flushSync: opts.flushSync === true
|
|
1507
1894
|
}));
|
|
1895
|
+
|
|
1508
1896
|
// Cleanup internally now that we've called our subscribers/updated state
|
|
1509
1897
|
unmountedFetchers.forEach(key => deleteFetcher(key));
|
|
1510
1898
|
mountedFetchers.forEach(key => state.fetchers.delete(key));
|
|
1511
1899
|
}
|
|
1900
|
+
|
|
1512
1901
|
// Complete a navigation returning the state.navigation back to the IDLE_NAVIGATION
|
|
1513
1902
|
// and setting state.[historyAction/location/matches] to the new route.
|
|
1514
1903
|
// - Location is a required param
|
|
@@ -1540,8 +1929,10 @@ function createRouter(init) {
|
|
|
1540
1929
|
// Clear actionData on any other completed navigations
|
|
1541
1930
|
actionData = null;
|
|
1542
1931
|
}
|
|
1932
|
+
|
|
1543
1933
|
// Always preserve any existing loaderData from re-used routes
|
|
1544
1934
|
let loaderData = newState.loaderData ? mergeLoaderData(state.loaderData, newState.loaderData, newState.matches || [], newState.errors) : state.loaderData;
|
|
1935
|
+
|
|
1545
1936
|
// On a successful navigation we can assume we got through all blockers
|
|
1546
1937
|
// so we can start fresh
|
|
1547
1938
|
let blockers = state.blockers;
|
|
@@ -1549,9 +1940,11 @@ function createRouter(init) {
|
|
|
1549
1940
|
blockers = new Map(blockers);
|
|
1550
1941
|
blockers.forEach((_, k) => blockers.set(k, IDLE_BLOCKER));
|
|
1551
1942
|
}
|
|
1943
|
+
|
|
1552
1944
|
// Always respect the user flag. Otherwise don't reset on mutation
|
|
1553
1945
|
// submission navigations unless they redirect
|
|
1554
1946
|
let preventScrollReset = pendingPreventScrollReset === true || state.navigation.formMethod != null && isMutationMethod(state.navigation.formMethod) && ((_location$state2 = location.state) == null ? void 0 : _location$state2._isRedirect) !== true;
|
|
1947
|
+
|
|
1555
1948
|
// Commit any in-flight routes at the end of the HMR revalidation "navigation"
|
|
1556
1949
|
if (inFlightDataRoutes) {
|
|
1557
1950
|
dataRoutes = inFlightDataRoutes;
|
|
@@ -1563,6 +1956,7 @@ function createRouter(init) {
|
|
|
1563
1956
|
init.history.replace(location, location.state);
|
|
1564
1957
|
}
|
|
1565
1958
|
let viewTransitionOpts;
|
|
1959
|
+
|
|
1566
1960
|
// On POP, enable transitions if they were enabled on the original navigation
|
|
1567
1961
|
if (pendingAction === Action.Pop) {
|
|
1568
1962
|
// Forward takes precedence so they behave like the original navigation
|
|
@@ -1610,6 +2004,7 @@ function createRouter(init) {
|
|
|
1610
2004
|
viewTransitionOpts,
|
|
1611
2005
|
flushSync: flushSync === true
|
|
1612
2006
|
});
|
|
2007
|
+
|
|
1613
2008
|
// Reset stateful navigation vars
|
|
1614
2009
|
pendingAction = Action.Pop;
|
|
1615
2010
|
pendingPreventScrollReset = false;
|
|
@@ -1619,6 +2014,7 @@ function createRouter(init) {
|
|
|
1619
2014
|
(_pendingRevalidationD = pendingRevalidationDfd) == null ? void 0 : _pendingRevalidationD.resolve();
|
|
1620
2015
|
pendingRevalidationDfd = null;
|
|
1621
2016
|
}
|
|
2017
|
+
|
|
1622
2018
|
// Trigger a navigation event, which can either be a numerical POP or a PUSH
|
|
1623
2019
|
// replace with an optional submission
|
|
1624
2020
|
async function navigate(to, opts) {
|
|
@@ -1634,6 +2030,7 @@ function createRouter(init) {
|
|
|
1634
2030
|
} = normalizeNavigateOptions(false, normalizedPath, opts);
|
|
1635
2031
|
let currentLocation = state.location;
|
|
1636
2032
|
let nextLocation = createLocation(state.location, path, opts && opts.state);
|
|
2033
|
+
|
|
1637
2034
|
// When using navigate as a PUSH/REPLACE we aren't reading an already-encoded
|
|
1638
2035
|
// URL from window.location, so we need to encode it here so the behavior
|
|
1639
2036
|
// remains the same as POP and non-data-router usages. new URL() does all
|
|
@@ -1694,6 +2091,7 @@ function createRouter(init) {
|
|
|
1694
2091
|
flushSync
|
|
1695
2092
|
});
|
|
1696
2093
|
}
|
|
2094
|
+
|
|
1697
2095
|
// Revalidate all current loaders. If a navigation is in progress or if this
|
|
1698
2096
|
// is interrupted by a navigation, allow this to "succeed" by calling all
|
|
1699
2097
|
// loaders during the next loader round
|
|
@@ -1713,15 +2111,18 @@ function createRouter(init) {
|
|
|
1713
2111
|
updateState({
|
|
1714
2112
|
revalidation: "loading"
|
|
1715
2113
|
});
|
|
2114
|
+
|
|
1716
2115
|
// Capture this here for the edge-case that we have a fully synchronous
|
|
1717
2116
|
// startNavigation which would resolve and null out pendingRevalidationDfd
|
|
1718
2117
|
// before we return from this function
|
|
1719
2118
|
let promise = pendingRevalidationDfd.promise;
|
|
2119
|
+
|
|
1720
2120
|
// If we're currently submitting an action, we don't need to start a new
|
|
1721
2121
|
// navigation, we'll just let the follow up loader execution call all loaders
|
|
1722
2122
|
if (state.navigation.state === "submitting") {
|
|
1723
2123
|
return promise;
|
|
1724
2124
|
}
|
|
2125
|
+
|
|
1725
2126
|
// If we're currently in an idle state, start a new navigation for the current
|
|
1726
2127
|
// action/location and mark it as uninterrupted, which will skip the history
|
|
1727
2128
|
// update in completeNavigation
|
|
@@ -1731,6 +2132,7 @@ function createRouter(init) {
|
|
|
1731
2132
|
});
|
|
1732
2133
|
return promise;
|
|
1733
2134
|
}
|
|
2135
|
+
|
|
1734
2136
|
// Otherwise, if we're currently in a loading state, just start a new
|
|
1735
2137
|
// navigation to the navigation.location but do not trigger an uninterrupted
|
|
1736
2138
|
// revalidation so that history correctly updates once the navigation completes
|
|
@@ -1741,6 +2143,7 @@ function createRouter(init) {
|
|
|
1741
2143
|
});
|
|
1742
2144
|
return promise;
|
|
1743
2145
|
}
|
|
2146
|
+
|
|
1744
2147
|
// Start a navigation to the given action/location. Can optionally provide a
|
|
1745
2148
|
// overrideNavigation which will override the normalLoad in the case of a redirect
|
|
1746
2149
|
// navigation
|
|
@@ -1752,6 +2155,7 @@ function createRouter(init) {
|
|
|
1752
2155
|
pendingNavigationController = null;
|
|
1753
2156
|
pendingAction = historyAction;
|
|
1754
2157
|
isUninterruptedRevalidation = (opts && opts.startUninterruptedRevalidation) === true;
|
|
2158
|
+
|
|
1755
2159
|
// Save the current scroll position every time we start a new navigation,
|
|
1756
2160
|
// and track whether we should reset scroll on completion
|
|
1757
2161
|
saveScrollPosition(state.location, state.matches);
|
|
@@ -1765,6 +2169,7 @@ function createRouter(init) {
|
|
|
1765
2169
|
if (fogOfWar.active && fogOfWar.matches) {
|
|
1766
2170
|
matches = fogOfWar.matches;
|
|
1767
2171
|
}
|
|
2172
|
+
|
|
1768
2173
|
// Short circuit with a 404 on the root error boundary if we match nothing
|
|
1769
2174
|
if (!matches) {
|
|
1770
2175
|
let {
|
|
@@ -1783,6 +2188,7 @@ function createRouter(init) {
|
|
|
1783
2188
|
});
|
|
1784
2189
|
return;
|
|
1785
2190
|
}
|
|
2191
|
+
|
|
1786
2192
|
// Short circuit if it's only a hash change and not a revalidation or
|
|
1787
2193
|
// mutation submission.
|
|
1788
2194
|
//
|
|
@@ -1797,6 +2203,7 @@ function createRouter(init) {
|
|
|
1797
2203
|
});
|
|
1798
2204
|
return;
|
|
1799
2205
|
}
|
|
2206
|
+
|
|
1800
2207
|
// Create a controller/Request for this navigation
|
|
1801
2208
|
pendingNavigationController = new AbortController();
|
|
1802
2209
|
let request = createClientSideRequest(init.history, location, pendingNavigationController.signal, opts && opts.submission);
|
|
@@ -1819,6 +2226,7 @@ function createRouter(init) {
|
|
|
1819
2226
|
if (actionResult.shortCircuited) {
|
|
1820
2227
|
return;
|
|
1821
2228
|
}
|
|
2229
|
+
|
|
1822
2230
|
// If we received a 404 from handleAction, it's because we couldn't lazily
|
|
1823
2231
|
// discover the destination route so we don't want to call loaders
|
|
1824
2232
|
if (actionResult.pendingActionResult) {
|
|
@@ -1841,9 +2249,11 @@ function createRouter(init) {
|
|
|
1841
2249
|
flushSync = false;
|
|
1842
2250
|
// No need to do fog of war matching again on loader execution
|
|
1843
2251
|
fogOfWar.active = false;
|
|
2252
|
+
|
|
1844
2253
|
// Create a GET request for the loaders
|
|
1845
2254
|
request = createClientSideRequest(init.history, request.url, request.signal);
|
|
1846
2255
|
}
|
|
2256
|
+
|
|
1847
2257
|
// Call loaders
|
|
1848
2258
|
let {
|
|
1849
2259
|
shortCircuited,
|
|
@@ -1854,6 +2264,7 @@ function createRouter(init) {
|
|
|
1854
2264
|
if (shortCircuited) {
|
|
1855
2265
|
return;
|
|
1856
2266
|
}
|
|
2267
|
+
|
|
1857
2268
|
// Clean up now that the action/loaders have completed. Don't clean up if
|
|
1858
2269
|
// we short circuited because pendingNavigationController will have already
|
|
1859
2270
|
// been assigned to a new controller for the next navigation
|
|
@@ -1865,6 +2276,7 @@ function createRouter(init) {
|
|
|
1865
2276
|
errors
|
|
1866
2277
|
}));
|
|
1867
2278
|
}
|
|
2279
|
+
|
|
1868
2280
|
// Call the action matched by the leaf route for this navigation and handle
|
|
1869
2281
|
// redirects/errors
|
|
1870
2282
|
async function handleAction(request, location, submission, matches, isFogOfWar, opts) {
|
|
@@ -1872,6 +2284,7 @@ function createRouter(init) {
|
|
|
1872
2284
|
opts = {};
|
|
1873
2285
|
}
|
|
1874
2286
|
interruptActiveLoads();
|
|
2287
|
+
|
|
1875
2288
|
// Put us in a submitting state
|
|
1876
2289
|
let navigation = getSubmittingNavigation(location, submission);
|
|
1877
2290
|
updateState({
|
|
@@ -1911,6 +2324,7 @@ function createRouter(init) {
|
|
|
1911
2324
|
matches = discoverResult.matches;
|
|
1912
2325
|
}
|
|
1913
2326
|
}
|
|
2327
|
+
|
|
1914
2328
|
// Call our action and get the result
|
|
1915
2329
|
let result;
|
|
1916
2330
|
let actionMatch = getTargetMatch(matches, location);
|
|
@@ -1955,6 +2369,7 @@ function createRouter(init) {
|
|
|
1955
2369
|
// Store off the pending error - we use it to determine which loaders
|
|
1956
2370
|
// to call and will commit it when we complete the navigation
|
|
1957
2371
|
let boundaryMatch = findNearestBoundary(matches, actionMatch.route.id);
|
|
2372
|
+
|
|
1958
2373
|
// By default, all submissions to the current location are REPLACE
|
|
1959
2374
|
// navigations, but if the action threw an error that'll be rendered in
|
|
1960
2375
|
// an errorElement, we fall back to PUSH so that the user can use the
|
|
@@ -1973,14 +2388,17 @@ function createRouter(init) {
|
|
|
1973
2388
|
pendingActionResult: [actionMatch.route.id, result]
|
|
1974
2389
|
};
|
|
1975
2390
|
}
|
|
2391
|
+
|
|
1976
2392
|
// Call all applicable loaders for the given matches, handling redirects,
|
|
1977
2393
|
// errors, etc.
|
|
1978
2394
|
async function handleLoaders(request, location, matches, isFogOfWar, overrideNavigation, submission, fetcherSubmission, replace, initialHydration, flushSync, pendingActionResult) {
|
|
1979
2395
|
// Figure out the right navigation we want to use for data loading
|
|
1980
2396
|
let loadingNavigation = overrideNavigation || getLoadingNavigation(location, submission);
|
|
2397
|
+
|
|
1981
2398
|
// If this was a redirect from an action we don't have a "submission" but
|
|
1982
2399
|
// we have it on the loading navigation so use that if available
|
|
1983
2400
|
let activeSubmission = submission || fetcherSubmission || getSubmissionFromNavigation(loadingNavigation);
|
|
2401
|
+
|
|
1984
2402
|
// If this is an uninterrupted revalidation, we remain in our current idle
|
|
1985
2403
|
// state. If not, we need to switch to our loading state and load data,
|
|
1986
2404
|
// preserving any new action data or existing action data (in the case of
|
|
@@ -1988,6 +2406,7 @@ function createRouter(init) {
|
|
|
1988
2406
|
// Also (with "partial hydration"), don't update the state for the initial
|
|
1989
2407
|
// data load since it's not a "navigation"
|
|
1990
2408
|
let shouldUpdateNavigationState = !isUninterruptedRevalidation && !initialHydration;
|
|
2409
|
+
|
|
1991
2410
|
// When fog of war is enabled, we enter our `loading` state earlier so we
|
|
1992
2411
|
// can discover new routes during the `loading` state. We skip this if
|
|
1993
2412
|
// we've already run actions since we would have done our matching already.
|
|
@@ -2038,6 +2457,7 @@ function createRouter(init) {
|
|
|
2038
2457
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
2039
2458
|
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, activeSubmission, location, initialHydration === true, isRevalidationRequired, cancelledFetcherLoads, fetchersQueuedForDeletion, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, pendingActionResult);
|
|
2040
2459
|
pendingNavigationLoadId = ++incrementingLoadId;
|
|
2460
|
+
|
|
2041
2461
|
// Short circuit if we have no loaders to run
|
|
2042
2462
|
if (matchesToLoad.length === 0 && revalidatingFetchers.length === 0) {
|
|
2043
2463
|
let updatedFetchers = markFetchRedirectsDone();
|
|
@@ -2083,6 +2503,7 @@ function createRouter(init) {
|
|
|
2083
2503
|
fetchControllers.set(rf.key, rf.controller);
|
|
2084
2504
|
}
|
|
2085
2505
|
});
|
|
2506
|
+
|
|
2086
2507
|
// Proxy navigation abort through to revalidation fetchers
|
|
2087
2508
|
let abortPendingFetchRevalidations = () => revalidatingFetchers.forEach(f => abortFetcher(f.key));
|
|
2088
2509
|
if (pendingNavigationController) {
|
|
@@ -2097,6 +2518,7 @@ function createRouter(init) {
|
|
|
2097
2518
|
shortCircuited: true
|
|
2098
2519
|
};
|
|
2099
2520
|
}
|
|
2521
|
+
|
|
2100
2522
|
// Clean up _after_ loaders have completed. Don't clean up if we short
|
|
2101
2523
|
// circuited because fetchControllers would have been aborted and
|
|
2102
2524
|
// reassigned to new controllers for the next navigation
|
|
@@ -2104,6 +2526,7 @@ function createRouter(init) {
|
|
|
2104
2526
|
pendingNavigationController.signal.removeEventListener("abort", abortPendingFetchRevalidations);
|
|
2105
2527
|
}
|
|
2106
2528
|
revalidatingFetchers.forEach(rf => fetchControllers.delete(rf.key));
|
|
2529
|
+
|
|
2107
2530
|
// If any loaders returned a redirect Response, start a new REPLACE navigation
|
|
2108
2531
|
let redirect = findRedirect(loaderResults);
|
|
2109
2532
|
if (redirect) {
|
|
@@ -2127,11 +2550,13 @@ function createRouter(init) {
|
|
|
2127
2550
|
shortCircuited: true
|
|
2128
2551
|
};
|
|
2129
2552
|
}
|
|
2553
|
+
|
|
2130
2554
|
// Process and commit output from loaders
|
|
2131
2555
|
let {
|
|
2132
2556
|
loaderData,
|
|
2133
2557
|
errors
|
|
2134
2558
|
} = processLoaderData(state, matches, loaderResults, pendingActionResult, revalidatingFetchers, fetcherResults);
|
|
2559
|
+
|
|
2135
2560
|
// Preserve SSR errors during partial hydration
|
|
2136
2561
|
if (initialHydration && state.errors) {
|
|
2137
2562
|
errors = _extends({}, state.errors, errors);
|
|
@@ -2171,6 +2596,7 @@ function createRouter(init) {
|
|
|
2171
2596
|
});
|
|
2172
2597
|
return new Map(state.fetchers);
|
|
2173
2598
|
}
|
|
2599
|
+
|
|
2174
2600
|
// Trigger a fetcher load/submit for the given fetcher key
|
|
2175
2601
|
async function fetch(key, routeId, href, opts) {
|
|
2176
2602
|
abortFetcher(key);
|
|
@@ -2207,6 +2633,7 @@ function createRouter(init) {
|
|
|
2207
2633
|
await handleFetcherAction(key, routeId, path, match, matches, fogOfWar.active, flushSync, preventScrollReset, submission);
|
|
2208
2634
|
return;
|
|
2209
2635
|
}
|
|
2636
|
+
|
|
2210
2637
|
// Store off the match so we can call it's shouldRevalidate on subsequent
|
|
2211
2638
|
// revalidations
|
|
2212
2639
|
fetchLoadMatches.set(key, {
|
|
@@ -2215,6 +2642,7 @@ function createRouter(init) {
|
|
|
2215
2642
|
});
|
|
2216
2643
|
await handleFetcherLoader(key, routeId, path, match, matches, fogOfWar.active, flushSync, preventScrollReset, submission);
|
|
2217
2644
|
}
|
|
2645
|
+
|
|
2218
2646
|
// Call the action for the matched fetcher.submit(), and then handle redirects,
|
|
2219
2647
|
// errors, and revalidation
|
|
2220
2648
|
async function handleFetcherAction(key, routeId, path, match, requestMatches, isFogOfWar, flushSync, preventScrollReset, submission) {
|
|
@@ -2237,6 +2665,7 @@ function createRouter(init) {
|
|
|
2237
2665
|
if (!isFogOfWar && detectAndHandle405Error(match)) {
|
|
2238
2666
|
return;
|
|
2239
2667
|
}
|
|
2668
|
+
|
|
2240
2669
|
// Put this fetcher into it's submitting state
|
|
2241
2670
|
let existingFetcher = state.fetchers.get(key);
|
|
2242
2671
|
updateFetcherState(key, getSubmittingFetcher(submission, existingFetcher), {
|
|
@@ -2268,6 +2697,7 @@ function createRouter(init) {
|
|
|
2268
2697
|
}
|
|
2269
2698
|
}
|
|
2270
2699
|
}
|
|
2700
|
+
|
|
2271
2701
|
// Call the action for the fetcher
|
|
2272
2702
|
fetchControllers.set(key, abortController);
|
|
2273
2703
|
let originatingLoadId = incrementingLoadId;
|
|
@@ -2281,6 +2711,7 @@ function createRouter(init) {
|
|
|
2281
2711
|
}
|
|
2282
2712
|
return;
|
|
2283
2713
|
}
|
|
2714
|
+
|
|
2284
2715
|
// We don't want errors bubbling up to the UI or redirects processed for
|
|
2285
2716
|
// unmounted fetchers so we just revert them to idle
|
|
2286
2717
|
if (fetchersQueuedForDeletion.has(key)) {
|
|
@@ -2308,12 +2739,14 @@ function createRouter(init) {
|
|
|
2308
2739
|
});
|
|
2309
2740
|
}
|
|
2310
2741
|
}
|
|
2742
|
+
|
|
2311
2743
|
// Process any non-redirect errors thrown
|
|
2312
2744
|
if (isErrorResult(actionResult)) {
|
|
2313
2745
|
setFetcherError(key, routeId, actionResult.error);
|
|
2314
2746
|
return;
|
|
2315
2747
|
}
|
|
2316
2748
|
}
|
|
2749
|
+
|
|
2317
2750
|
// Start the data load for current matches, or the next location if we're
|
|
2318
2751
|
// in the middle of a navigation
|
|
2319
2752
|
let nextLocation = state.navigation.location || state.location;
|
|
@@ -2326,6 +2759,7 @@ function createRouter(init) {
|
|
|
2326
2759
|
let loadFetcher = getLoadingFetcher(submission, actionResult.data);
|
|
2327
2760
|
state.fetchers.set(key, loadFetcher);
|
|
2328
2761
|
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, submission, nextLocation, false, isRevalidationRequired, cancelledFetcherLoads, fetchersQueuedForDeletion, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, [match.route.id, actionResult]);
|
|
2762
|
+
|
|
2329
2763
|
// Put all revalidating fetchers into the loading state, except for the
|
|
2330
2764
|
// current fetcher which we want to keep in it's current loading state which
|
|
2331
2765
|
// contains it's action submission info + action data
|
|
@@ -2371,11 +2805,13 @@ function createRouter(init) {
|
|
|
2371
2805
|
preventScrollReset
|
|
2372
2806
|
});
|
|
2373
2807
|
}
|
|
2808
|
+
|
|
2374
2809
|
// Process and commit output from loaders
|
|
2375
2810
|
let {
|
|
2376
2811
|
loaderData,
|
|
2377
2812
|
errors
|
|
2378
2813
|
} = processLoaderData(state, matches, loaderResults, undefined, revalidatingFetchers, fetcherResults);
|
|
2814
|
+
|
|
2379
2815
|
// Since we let revalidations complete even if the submitting fetcher was
|
|
2380
2816
|
// deleted, only put it back to idle if it hasn't been deleted
|
|
2381
2817
|
if (state.fetchers.has(key)) {
|
|
@@ -2383,6 +2819,7 @@ function createRouter(init) {
|
|
|
2383
2819
|
state.fetchers.set(key, doneFetcher);
|
|
2384
2820
|
}
|
|
2385
2821
|
abortStaleFetchLoads(loadId);
|
|
2822
|
+
|
|
2386
2823
|
// If we are currently in a navigation loading state and this fetcher is
|
|
2387
2824
|
// more recent than the navigation, we want the newer data so abort the
|
|
2388
2825
|
// navigation and complete it with the fetcher data
|
|
@@ -2407,6 +2844,7 @@ function createRouter(init) {
|
|
|
2407
2844
|
isRevalidationRequired = false;
|
|
2408
2845
|
}
|
|
2409
2846
|
}
|
|
2847
|
+
|
|
2410
2848
|
// Call the matched loader for fetcher.load(), handling redirects, errors, etc.
|
|
2411
2849
|
async function handleFetcherLoader(key, routeId, path, match, matches, isFogOfWar, flushSync, preventScrollReset, submission) {
|
|
2412
2850
|
let existingFetcher = state.fetchers.get(key);
|
|
@@ -2436,11 +2874,13 @@ function createRouter(init) {
|
|
|
2436
2874
|
match = getTargetMatch(matches, path);
|
|
2437
2875
|
}
|
|
2438
2876
|
}
|
|
2877
|
+
|
|
2439
2878
|
// Call the loader for this fetcher route match
|
|
2440
2879
|
fetchControllers.set(key, abortController);
|
|
2441
2880
|
let originatingLoadId = incrementingLoadId;
|
|
2442
2881
|
let results = await callDataStrategy("loader", state, fetchRequest, [match], matches, key);
|
|
2443
2882
|
let result = results[match.route.id];
|
|
2883
|
+
|
|
2444
2884
|
// We can delete this so long as we weren't aborted by our our own fetcher
|
|
2445
2885
|
// re-load which would have put _new_ controller is in fetchControllers
|
|
2446
2886
|
if (fetchControllers.get(key) === abortController) {
|
|
@@ -2449,12 +2889,14 @@ function createRouter(init) {
|
|
|
2449
2889
|
if (fetchRequest.signal.aborted) {
|
|
2450
2890
|
return;
|
|
2451
2891
|
}
|
|
2892
|
+
|
|
2452
2893
|
// We don't want errors bubbling up or redirects followed for unmounted
|
|
2453
2894
|
// fetchers, so short circuit here if it was removed from the UI
|
|
2454
2895
|
if (fetchersQueuedForDeletion.has(key)) {
|
|
2455
2896
|
updateFetcherState(key, getDoneFetcher(undefined));
|
|
2456
2897
|
return;
|
|
2457
2898
|
}
|
|
2899
|
+
|
|
2458
2900
|
// If the loader threw a redirect Response, start a new REPLACE navigation
|
|
2459
2901
|
if (isRedirectResult(result)) {
|
|
2460
2902
|
if (pendingNavigationLoadId > originatingLoadId) {
|
|
@@ -2470,14 +2912,17 @@ function createRouter(init) {
|
|
|
2470
2912
|
return;
|
|
2471
2913
|
}
|
|
2472
2914
|
}
|
|
2915
|
+
|
|
2473
2916
|
// Process any non-redirect errors thrown
|
|
2474
2917
|
if (isErrorResult(result)) {
|
|
2475
2918
|
setFetcherError(key, routeId, result.error);
|
|
2476
2919
|
return;
|
|
2477
2920
|
}
|
|
2921
|
+
|
|
2478
2922
|
// Put the fetcher back into an idle state
|
|
2479
2923
|
updateFetcherState(key, getDoneFetcher(result.data));
|
|
2480
2924
|
}
|
|
2925
|
+
|
|
2481
2926
|
/**
|
|
2482
2927
|
* Utility function to handle redirects returned from an action or loader.
|
|
2483
2928
|
* Normally, a redirect "replaces" the navigation that triggered it. So, for
|
|
@@ -2535,10 +2980,12 @@ function createRouter(init) {
|
|
|
2535
2980
|
return;
|
|
2536
2981
|
}
|
|
2537
2982
|
}
|
|
2983
|
+
|
|
2538
2984
|
// There's no need to abort on redirects, since we don't detect the
|
|
2539
2985
|
// redirect until the action/loaders have settled
|
|
2540
2986
|
pendingNavigationController = null;
|
|
2541
2987
|
let redirectNavigationType = replace === true || redirect.response.headers.has("X-Remix-Replace") ? Action.Replace : Action.Push;
|
|
2988
|
+
|
|
2542
2989
|
// Use the incoming submission if provided, fallback on the active one in
|
|
2543
2990
|
// state.navigation
|
|
2544
2991
|
let {
|
|
@@ -2549,6 +2996,7 @@ function createRouter(init) {
|
|
|
2549
2996
|
if (!submission && !fetcherSubmission && formMethod && formAction && formEncType) {
|
|
2550
2997
|
submission = getSubmissionFromNavigation(state.navigation);
|
|
2551
2998
|
}
|
|
2999
|
+
|
|
2552
3000
|
// If this was a 307/308 submission we want to preserve the HTTP method and
|
|
2553
3001
|
// re-submit the GET/POST/PUT/PATCH/DELETE as a submission navigation to the
|
|
2554
3002
|
// redirected location
|
|
@@ -2576,6 +3024,7 @@ function createRouter(init) {
|
|
|
2576
3024
|
});
|
|
2577
3025
|
}
|
|
2578
3026
|
}
|
|
3027
|
+
|
|
2579
3028
|
// Utility wrapper for calling dataStrategy client-side without having to
|
|
2580
3029
|
// pass around the manifest, mapRouteProperties, etc.
|
|
2581
3030
|
async function callDataStrategy(type, state, request, matchesToLoad, matches, fetcherKey) {
|
|
@@ -2595,7 +3044,7 @@ function createRouter(init) {
|
|
|
2595
3044
|
return dataResults;
|
|
2596
3045
|
}
|
|
2597
3046
|
for (let [routeId, result] of Object.entries(results)) {
|
|
2598
|
-
if (
|
|
3047
|
+
if (isRedirectDataStrategyResult(result)) {
|
|
2599
3048
|
let response = result.result;
|
|
2600
3049
|
dataResults[routeId] = {
|
|
2601
3050
|
type: ResultType.redirect,
|
|
@@ -2608,7 +3057,6 @@ function createRouter(init) {
|
|
|
2608
3057
|
return dataResults;
|
|
2609
3058
|
}
|
|
2610
3059
|
async function callLoadersAndMaybeResolveData(state, matches, matchesToLoad, fetchersToLoad, request) {
|
|
2611
|
-
state.matches;
|
|
2612
3060
|
// Kick off loaders and fetchers in parallel
|
|
2613
3061
|
let loaderResultsPromise = callDataStrategy("loader", state, request, matchesToLoad, matches, null);
|
|
2614
3062
|
let fetcherResultsPromise = Promise.all(fetchersToLoad.map(async f => {
|
|
@@ -2640,6 +3088,7 @@ function createRouter(init) {
|
|
|
2640
3088
|
function interruptActiveLoads() {
|
|
2641
3089
|
// Every interruption triggers a revalidation
|
|
2642
3090
|
isRevalidationRequired = true;
|
|
3091
|
+
|
|
2643
3092
|
// Abort in-flight fetcher loads
|
|
2644
3093
|
fetchLoadMatches.forEach((_, key) => {
|
|
2645
3094
|
if (fetchControllers.has(key)) {
|
|
@@ -2766,9 +3215,11 @@ function createRouter(init) {
|
|
|
2766
3215
|
state.blockers.delete(key);
|
|
2767
3216
|
blockerFunctions.delete(key);
|
|
2768
3217
|
}
|
|
3218
|
+
|
|
2769
3219
|
// Utility function to update blockers, ensuring valid state transitions
|
|
2770
3220
|
function updateBlocker(key, newBlocker) {
|
|
2771
3221
|
let blocker = state.blockers.get(key) || IDLE_BLOCKER;
|
|
3222
|
+
|
|
2772
3223
|
// Poor mans state machine :)
|
|
2773
3224
|
// https://mermaid.live/edit#pako:eNqVkc9OwzAMxl8l8nnjAYrEtDIOHEBIgwvKJTReGy3_lDpIqO27k6awMG0XcrLlnz87nwdonESogKXXBuE79rq75XZO3-yHds0RJVuv70YrPlUrCEe2HfrORS3rubqZfuhtpg5C9wk5tZ4VKcRUq88q9Z8RS0-48cE1iHJkL0ugbHuFLus9L6spZy8nX9MP2CNdomVaposqu3fGayT8T8-jJQwhepo_UtpgBQaDEUom04dZhAN1aJBDlUKJBxE1ceB2Smj0Mln-IBW5AFU2dwUiktt_2Qaq2dBfaKdEup85UV7Yd-dKjlnkabl2Pvr0DTkTreM
|
|
2774
3225
|
!(blocker.state === "unblocked" && newBlocker.state === "blocked" || blocker.state === "blocked" && newBlocker.state === "blocked" || blocker.state === "blocked" && newBlocker.state === "proceeding" || blocker.state === "blocked" && newBlocker.state === "unblocked" || blocker.state === "proceeding" && newBlocker.state === "unblocked") ? process.env.NODE_ENV !== "production" ? invariant$2(false, "Invalid blocker state transition: " + blocker.state + " -> " + newBlocker.state) : invariant$2(false) : void 0;
|
|
@@ -2787,6 +3238,7 @@ function createRouter(init) {
|
|
|
2787
3238
|
if (blockerFunctions.size === 0) {
|
|
2788
3239
|
return;
|
|
2789
3240
|
}
|
|
3241
|
+
|
|
2790
3242
|
// We ony support a single active blocker at the moment since we don't have
|
|
2791
3243
|
// any compelling use cases for multi-blocker yet
|
|
2792
3244
|
if (blockerFunctions.size > 1) {
|
|
@@ -2800,6 +3252,7 @@ function createRouter(init) {
|
|
|
2800
3252
|
// it and can let this navigation continue
|
|
2801
3253
|
return;
|
|
2802
3254
|
}
|
|
3255
|
+
|
|
2803
3256
|
// At this point, we know we're unblocked/blocked so we need to check the
|
|
2804
3257
|
// user-provided blocker function
|
|
2805
3258
|
if (blockerFunction({
|
|
@@ -2825,12 +3278,14 @@ function createRouter(init) {
|
|
|
2825
3278
|
error
|
|
2826
3279
|
};
|
|
2827
3280
|
}
|
|
3281
|
+
|
|
2828
3282
|
// Opt in to capturing and reporting scroll positions during navigations,
|
|
2829
3283
|
// used by the <ScrollRestoration> component
|
|
2830
3284
|
function enableScrollRestoration(positions, getPosition, getKey) {
|
|
2831
3285
|
savedScrollPositions = positions;
|
|
2832
3286
|
getScrollPosition = getPosition;
|
|
2833
3287
|
getScrollRestorationKey = getKey || null;
|
|
3288
|
+
|
|
2834
3289
|
// Perform initial hydration scroll restoration, since we miss the boat on
|
|
2835
3290
|
// the initial updateState() because we've not yet rendered <ScrollRestoration/>
|
|
2836
3291
|
// and therefore have no savedScrollPositions available
|
|
@@ -2949,6 +3404,7 @@ function createRouter(init) {
|
|
|
2949
3404
|
};
|
|
2950
3405
|
}
|
|
2951
3406
|
let newPartialMatches = matchRoutesImpl(routesToUse, pathname, basename, true);
|
|
3407
|
+
|
|
2952
3408
|
// Avoid loops if the second pass results in the same partial matches
|
|
2953
3409
|
if (!newPartialMatches || partialMatches.length === newPartialMatches.length && partialMatches.every((m, i) => m.route.id === newPartialMatches[i].route.id)) {
|
|
2954
3410
|
return {
|
|
@@ -2967,6 +3423,7 @@ function createRouter(init) {
|
|
|
2967
3423
|
let isNonHMR = inFlightDataRoutes == null;
|
|
2968
3424
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
2969
3425
|
patchRoutesImpl(routeId, children, routesToUse, manifest, mapRouteProperties);
|
|
3426
|
+
|
|
2970
3427
|
// If we are not in the middle of an HMR revalidation and we changed the
|
|
2971
3428
|
// routes, provide a new identity and trigger a reflow via `updateState`
|
|
2972
3429
|
// to re-run memoized `router.routes` dependencies.
|
|
@@ -3016,12 +3473,19 @@ function createRouter(init) {
|
|
|
3016
3473
|
};
|
|
3017
3474
|
return router;
|
|
3018
3475
|
}
|
|
3476
|
+
//#endregion
|
|
3477
|
+
|
|
3478
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
3479
|
+
//#region createStaticHandler
|
|
3480
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
3481
|
+
|
|
3019
3482
|
function createStaticHandler$1(routes, opts) {
|
|
3020
3483
|
!(routes.length > 0) ? process.env.NODE_ENV !== "production" ? invariant$2(false, "You must provide a non-empty routes array to createStaticHandler") : invariant$2(false) : void 0;
|
|
3021
3484
|
let manifest = {};
|
|
3022
3485
|
let basename = (opts ? opts.basename : null) || "/";
|
|
3023
3486
|
let mapRouteProperties = (opts == null ? void 0 : opts.mapRouteProperties) || defaultMapRouteProperties;
|
|
3024
3487
|
let dataRoutes = convertRoutesToDataRoutes(routes, mapRouteProperties, undefined, manifest);
|
|
3488
|
+
|
|
3025
3489
|
/**
|
|
3026
3490
|
* The query() method is intended for document requests, in which we want to
|
|
3027
3491
|
* call an optional action and potentially multiple loaders for all nested
|
|
@@ -3058,6 +3522,7 @@ function createStaticHandler$1(routes, opts) {
|
|
|
3058
3522
|
let method = request.method;
|
|
3059
3523
|
let location = createLocation("", createPath(url), null, "default");
|
|
3060
3524
|
let matches = matchRoutes(dataRoutes, location, basename);
|
|
3525
|
+
|
|
3061
3526
|
// SSR supports HEAD requests while SPA doesn't
|
|
3062
3527
|
if (!isValidMethod(method) && method !== "HEAD") {
|
|
3063
3528
|
let error = getInternalRouterError(405, {
|
|
@@ -3103,9 +3568,10 @@ function createStaticHandler$1(routes, opts) {
|
|
|
3103
3568
|
};
|
|
3104
3569
|
}
|
|
3105
3570
|
let result = await queryImpl(request, location, matches, requestContext, dataStrategy || null, skipLoaderErrorBubbling === true, null);
|
|
3106
|
-
if (isResponse
|
|
3571
|
+
if (isResponse(result)) {
|
|
3107
3572
|
return result;
|
|
3108
3573
|
}
|
|
3574
|
+
|
|
3109
3575
|
// When returning StaticHandlerContext, we patch back in the location here
|
|
3110
3576
|
// since we need it for React Context. But this helps keep our submit and
|
|
3111
3577
|
// loadRouteData operating on a Request instead of a Location
|
|
@@ -3114,6 +3580,7 @@ function createStaticHandler$1(routes, opts) {
|
|
|
3114
3580
|
basename
|
|
3115
3581
|
}, result);
|
|
3116
3582
|
}
|
|
3583
|
+
|
|
3117
3584
|
/**
|
|
3118
3585
|
* The queryRoute() method is intended for targeted route requests, either
|
|
3119
3586
|
* for fetch ?_data requests or resource route requests. In this case, we
|
|
@@ -3150,6 +3617,7 @@ function createStaticHandler$1(routes, opts) {
|
|
|
3150
3617
|
let method = request.method;
|
|
3151
3618
|
let location = createLocation("", createPath(url), null, "default");
|
|
3152
3619
|
let matches = matchRoutes(dataRoutes, location, basename);
|
|
3620
|
+
|
|
3153
3621
|
// SSR supports HEAD requests while SPA doesn't
|
|
3154
3622
|
if (!isValidMethod(method) && method !== "HEAD" && method !== "OPTIONS") {
|
|
3155
3623
|
throw getInternalRouterError(405, {
|
|
@@ -3173,7 +3641,7 @@ function createStaticHandler$1(routes, opts) {
|
|
|
3173
3641
|
});
|
|
3174
3642
|
}
|
|
3175
3643
|
let result = await queryImpl(request, location, matches, requestContext, dataStrategy || null, false, match);
|
|
3176
|
-
if (isResponse
|
|
3644
|
+
if (isResponse(result)) {
|
|
3177
3645
|
return result;
|
|
3178
3646
|
}
|
|
3179
3647
|
let error = result.errors ? Object.values(result.errors)[0] : undefined;
|
|
@@ -3184,6 +3652,7 @@ function createStaticHandler$1(routes, opts) {
|
|
|
3184
3652
|
// preserve the "error" state outside of queryImpl.
|
|
3185
3653
|
throw error;
|
|
3186
3654
|
}
|
|
3655
|
+
|
|
3187
3656
|
// Pick off the right state value to return
|
|
3188
3657
|
if (result.actionData) {
|
|
3189
3658
|
return Object.values(result.actionData)[0];
|
|
@@ -3201,7 +3670,7 @@ function createStaticHandler$1(routes, opts) {
|
|
|
3201
3670
|
return result;
|
|
3202
3671
|
}
|
|
3203
3672
|
let result = await loadRouteData(request, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch);
|
|
3204
|
-
return isResponse
|
|
3673
|
+
return isResponse(result) ? result : _extends({}, result, {
|
|
3205
3674
|
actionData: null,
|
|
3206
3675
|
actionHeaders: {}
|
|
3207
3676
|
});
|
|
@@ -3209,7 +3678,7 @@ function createStaticHandler$1(routes, opts) {
|
|
|
3209
3678
|
// If the user threw/returned a Response in callLoaderOrAction for a
|
|
3210
3679
|
// `queryRoute` call, we throw the `DataStrategyResult` to bail out early
|
|
3211
3680
|
// and then return or throw the raw Response here accordingly
|
|
3212
|
-
if (isDataStrategyResult(e) && isResponse
|
|
3681
|
+
if (isDataStrategyResult(e) && isResponse(e.result)) {
|
|
3213
3682
|
if (e.type === ResultType.error) {
|
|
3214
3683
|
throw e.result;
|
|
3215
3684
|
}
|
|
@@ -3217,7 +3686,7 @@ function createStaticHandler$1(routes, opts) {
|
|
|
3217
3686
|
}
|
|
3218
3687
|
// Redirects are always returned since they don't propagate to catch
|
|
3219
3688
|
// boundaries
|
|
3220
|
-
if (isRedirectResponse
|
|
3689
|
+
if (isRedirectResponse(e)) {
|
|
3221
3690
|
return e;
|
|
3222
3691
|
}
|
|
3223
3692
|
throw e;
|
|
@@ -3277,6 +3746,7 @@ function createStaticHandler$1(routes, opts) {
|
|
|
3277
3746
|
actionHeaders: {}
|
|
3278
3747
|
};
|
|
3279
3748
|
}
|
|
3749
|
+
|
|
3280
3750
|
// Create a GET request for the loaders
|
|
3281
3751
|
let loaderRequest = new Request(request.url, {
|
|
3282
3752
|
headers: request.headers,
|
|
@@ -3288,6 +3758,7 @@ function createStaticHandler$1(routes, opts) {
|
|
|
3288
3758
|
// to call and will commit it when we complete the navigation
|
|
3289
3759
|
let boundaryMatch = skipLoaderErrorBubbling ? actionMatch : findNearestBoundary(matches, actionMatch.route.id);
|
|
3290
3760
|
let context = await loadRouteData(loaderRequest, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, null, [boundaryMatch.route.id, result]);
|
|
3761
|
+
|
|
3291
3762
|
// action status codes take precedence over loader status codes
|
|
3292
3763
|
return _extends({}, context, {
|
|
3293
3764
|
statusCode: isRouteErrorResponse(result.error) ? result.error.status : result.statusCode != null ? result.statusCode : 500,
|
|
@@ -3312,6 +3783,7 @@ function createStaticHandler$1(routes, opts) {
|
|
|
3312
3783
|
}
|
|
3313
3784
|
async function loadRouteData(request, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch, pendingActionResult) {
|
|
3314
3785
|
let isRouteRequest = routeMatch != null;
|
|
3786
|
+
|
|
3315
3787
|
// Short circuit if we have no loaders to run (queryRoute())
|
|
3316
3788
|
if (isRouteRequest && !(routeMatch != null && routeMatch.route.loader) && !(routeMatch != null && routeMatch.route.lazy)) {
|
|
3317
3789
|
throw getInternalRouterError(400, {
|
|
@@ -3322,6 +3794,7 @@ function createStaticHandler$1(routes, opts) {
|
|
|
3322
3794
|
}
|
|
3323
3795
|
let requestMatches = routeMatch ? [routeMatch] : pendingActionResult && isErrorResult(pendingActionResult[1]) ? getLoaderMatchesUntilBoundary(matches, pendingActionResult[0]) : matches;
|
|
3324
3796
|
let matchesToLoad = requestMatches.filter(m => m.route.loader || m.route.lazy);
|
|
3797
|
+
|
|
3325
3798
|
// Short circuit if we have no loaders to run (query())
|
|
3326
3799
|
if (matchesToLoad.length === 0) {
|
|
3327
3800
|
return {
|
|
@@ -3341,8 +3814,10 @@ function createStaticHandler$1(routes, opts) {
|
|
|
3341
3814
|
if (request.signal.aborted) {
|
|
3342
3815
|
throwStaticHandlerAbortedError(request, isRouteRequest);
|
|
3343
3816
|
}
|
|
3817
|
+
|
|
3344
3818
|
// Process and commit output from loaders
|
|
3345
3819
|
let context = processRouteLoaderData(matches, results, pendingActionResult, true, skipLoaderErrorBubbling);
|
|
3820
|
+
|
|
3346
3821
|
// Add a null for any non-loader matches for proper revalidation on the client
|
|
3347
3822
|
let executedLoaders = new Set(matchesToLoad.map(match => match.route.id));
|
|
3348
3823
|
matches.forEach(match => {
|
|
@@ -3354,6 +3829,7 @@ function createStaticHandler$1(routes, opts) {
|
|
|
3354
3829
|
matches
|
|
3355
3830
|
});
|
|
3356
3831
|
}
|
|
3832
|
+
|
|
3357
3833
|
// Utility wrapper for calling dataStrategy server-side without having to
|
|
3358
3834
|
// pass around the manifest, mapRouteProperties, etc.
|
|
3359
3835
|
async function callDataStrategy(type, request, matchesToLoad, matches, isRouteRequest, requestContext, dataStrategy) {
|
|
@@ -3364,12 +3840,12 @@ function createStaticHandler$1(routes, opts) {
|
|
|
3364
3840
|
return;
|
|
3365
3841
|
}
|
|
3366
3842
|
let result = results[match.route.id];
|
|
3367
|
-
if (
|
|
3843
|
+
if (isRedirectDataStrategyResult(result)) {
|
|
3368
3844
|
let response = result.result;
|
|
3369
3845
|
// Throw redirects and let the server handle them with an HTTP redirect
|
|
3370
3846
|
throw normalizeRelativeRoutingRedirectResponse(response, request, match.route.id, matches, basename);
|
|
3371
3847
|
}
|
|
3372
|
-
if (isResponse
|
|
3848
|
+
if (isResponse(result.result) && isRouteRequest) {
|
|
3373
3849
|
// For SSR single-route requests, we want to hand Responses back
|
|
3374
3850
|
// directly without unwrapping
|
|
3375
3851
|
throw result;
|
|
@@ -3384,10 +3860,13 @@ function createStaticHandler$1(routes, opts) {
|
|
|
3384
3860
|
queryRoute
|
|
3385
3861
|
};
|
|
3386
3862
|
}
|
|
3863
|
+
|
|
3387
3864
|
//#endregion
|
|
3865
|
+
|
|
3388
3866
|
////////////////////////////////////////////////////////////////////////////////
|
|
3389
3867
|
//#region Helpers
|
|
3390
3868
|
////////////////////////////////////////////////////////////////////////////////
|
|
3869
|
+
|
|
3391
3870
|
/**
|
|
3392
3871
|
* Given an existing StaticHandlerContext and an error thrown at render time,
|
|
3393
3872
|
* provide an updated StaticHandlerContext suitable for a second SSR render
|
|
@@ -3431,8 +3910,10 @@ function normalizeTo(location, matches, basename, to, fromRouteId, relative) {
|
|
|
3431
3910
|
contextualMatches = matches;
|
|
3432
3911
|
activeRouteMatch = matches[matches.length - 1];
|
|
3433
3912
|
}
|
|
3913
|
+
|
|
3434
3914
|
// Resolve the relative path
|
|
3435
3915
|
let path = resolveTo(to ? to : ".", getResolveToMatches(contextualMatches), stripBasename(location.pathname, basename) || location.pathname, relative === "path");
|
|
3916
|
+
|
|
3436
3917
|
// When `to` is not specified we inherit search/hash from the current
|
|
3437
3918
|
// location, unlike when to="." and we just inherit the path.
|
|
3438
3919
|
// See https://github.com/remix-run/remix/issues/927
|
|
@@ -3440,6 +3921,7 @@ function normalizeTo(location, matches, basename, to, fromRouteId, relative) {
|
|
|
3440
3921
|
path.search = location.search;
|
|
3441
3922
|
path.hash = location.hash;
|
|
3442
3923
|
}
|
|
3924
|
+
|
|
3443
3925
|
// Account for `?index` params when routing to the current location
|
|
3444
3926
|
if ((to == null || to === "" || to === ".") && activeRouteMatch) {
|
|
3445
3927
|
let nakedIndex = hasNakedIndexQuery(path.search);
|
|
@@ -3456,6 +3938,7 @@ function normalizeTo(location, matches, basename, to, fromRouteId, relative) {
|
|
|
3456
3938
|
path.search = qs ? "?" + qs : "";
|
|
3457
3939
|
}
|
|
3458
3940
|
}
|
|
3941
|
+
|
|
3459
3942
|
// If we're operating within a basename, prepend it to the pathname. If
|
|
3460
3943
|
// this is a root navigation, then just use the raw basename which allows
|
|
3461
3944
|
// the basename to have full control over the presence of a trailing slash
|
|
@@ -3465,6 +3948,7 @@ function normalizeTo(location, matches, basename, to, fromRouteId, relative) {
|
|
|
3465
3948
|
}
|
|
3466
3949
|
return createPath(path);
|
|
3467
3950
|
}
|
|
3951
|
+
|
|
3468
3952
|
// Normalize navigation options by converting formMethod=GET formData objects to
|
|
3469
3953
|
// URLSearchParams so they behave identically to links with query params
|
|
3470
3954
|
function normalizeNavigateOptions(isFetcher, path, opts) {
|
|
@@ -3488,6 +3972,7 @@ function normalizeNavigateOptions(isFetcher, path, opts) {
|
|
|
3488
3972
|
type: "invalid-body"
|
|
3489
3973
|
})
|
|
3490
3974
|
});
|
|
3975
|
+
|
|
3491
3976
|
// Create a Submission on non-GET navigations
|
|
3492
3977
|
let rawFormMethod = opts.formMethod || "get";
|
|
3493
3978
|
let formMethod = rawFormMethod.toUpperCase();
|
|
@@ -3575,6 +4060,7 @@ function normalizeNavigateOptions(isFetcher, path, opts) {
|
|
|
3575
4060
|
submission
|
|
3576
4061
|
};
|
|
3577
4062
|
}
|
|
4063
|
+
|
|
3578
4064
|
// Flatten submission onto URLSearchParams for GET submissions
|
|
3579
4065
|
let parsedPath = parsePath(path);
|
|
3580
4066
|
// On GET navigation submissions we can drop the ?index param from the
|
|
@@ -3589,6 +4075,7 @@ function normalizeNavigateOptions(isFetcher, path, opts) {
|
|
|
3589
4075
|
submission
|
|
3590
4076
|
};
|
|
3591
4077
|
}
|
|
4078
|
+
|
|
3592
4079
|
// Filter out all routes at/below any caught error as they aren't going to
|
|
3593
4080
|
// render so we don't need to load them
|
|
3594
4081
|
function getLoaderMatchesUntilBoundary(matches, boundaryId, includeBoundary) {
|
|
@@ -3605,6 +4092,7 @@ function getMatchesToLoad(history, state, matches, submission, location, initial
|
|
|
3605
4092
|
let actionResult = pendingActionResult ? isErrorResult(pendingActionResult[1]) ? pendingActionResult[1].error : pendingActionResult[1].data : undefined;
|
|
3606
4093
|
let currentUrl = history.createURL(state.location);
|
|
3607
4094
|
let nextUrl = history.createURL(location);
|
|
4095
|
+
|
|
3608
4096
|
// Pick navigation matches that are net-new or qualify for revalidation
|
|
3609
4097
|
let boundaryMatches = matches;
|
|
3610
4098
|
if (initialHydration && state.errors) {
|
|
@@ -3619,6 +4107,7 @@ function getMatchesToLoad(history, state, matches, submission, location, initial
|
|
|
3619
4107
|
// boundary
|
|
3620
4108
|
boundaryMatches = getLoaderMatchesUntilBoundary(matches, pendingActionResult[0]);
|
|
3621
4109
|
}
|
|
4110
|
+
|
|
3622
4111
|
// Don't revalidate loaders by default after action 4xx/5xx responses
|
|
3623
4112
|
// when the flag is enabled. They can still opt-into revalidation via
|
|
3624
4113
|
// `shouldRevalidate` via `actionResult`
|
|
@@ -3638,10 +4127,12 @@ function getMatchesToLoad(history, state, matches, submission, location, initial
|
|
|
3638
4127
|
if (initialHydration) {
|
|
3639
4128
|
return shouldLoadRouteOnHydration(route, state.loaderData, state.errors);
|
|
3640
4129
|
}
|
|
4130
|
+
|
|
3641
4131
|
// Always call the loader on new route instances
|
|
3642
4132
|
if (isNewLoader(state.loaderData, state.matches[index], match)) {
|
|
3643
4133
|
return true;
|
|
3644
4134
|
}
|
|
4135
|
+
|
|
3645
4136
|
// This is the default implementation for when we revalidate. If the route
|
|
3646
4137
|
// provides it's own implementation, then we give them full control but
|
|
3647
4138
|
// provide this value so they can leverage it if needed after they check
|
|
@@ -3663,6 +4154,7 @@ function getMatchesToLoad(history, state, matches, submission, location, initial
|
|
|
3663
4154
|
currentUrl.search !== nextUrl.search || isNewRouteInstance(currentRouteMatch, nextRouteMatch)
|
|
3664
4155
|
}));
|
|
3665
4156
|
});
|
|
4157
|
+
|
|
3666
4158
|
// Pick fetcher.loads that need to be revalidated
|
|
3667
4159
|
let revalidatingFetchers = [];
|
|
3668
4160
|
fetchLoadMatches.forEach((f, key) => {
|
|
@@ -3675,6 +4167,7 @@ function getMatchesToLoad(history, state, matches, submission, location, initial
|
|
|
3675
4167
|
return;
|
|
3676
4168
|
}
|
|
3677
4169
|
let fetcherMatches = matchRoutes(routesToUse, f.path, basename);
|
|
4170
|
+
|
|
3678
4171
|
// If the fetcher path no longer matches, push it in with null matches so
|
|
3679
4172
|
// we can trigger a 404 in callLoadersAndMaybeResolveData. Note this is
|
|
3680
4173
|
// currently only a use-case for Remix HMR where the route tree can change
|
|
@@ -3690,6 +4183,7 @@ function getMatchesToLoad(history, state, matches, submission, location, initial
|
|
|
3690
4183
|
});
|
|
3691
4184
|
return;
|
|
3692
4185
|
}
|
|
4186
|
+
|
|
3693
4187
|
// Revalidating fetchers are decoupled from the route matches since they
|
|
3694
4188
|
// load from a static href. They revalidate based on explicit revalidation
|
|
3695
4189
|
// (submission, useRevalidator, or X-Remix-Revalidate)
|
|
@@ -3740,20 +4234,24 @@ function shouldLoadRouteOnHydration(route, loaderData, errors) {
|
|
|
3740
4234
|
if (route.lazy) {
|
|
3741
4235
|
return true;
|
|
3742
4236
|
}
|
|
4237
|
+
|
|
3743
4238
|
// No loader, nothing to initialize
|
|
3744
4239
|
if (!route.loader) {
|
|
3745
4240
|
return false;
|
|
3746
4241
|
}
|
|
3747
4242
|
let hasData = loaderData != null && loaderData[route.id] !== undefined;
|
|
3748
4243
|
let hasError = errors != null && errors[route.id] !== undefined;
|
|
4244
|
+
|
|
3749
4245
|
// Don't run if we error'd during SSR
|
|
3750
4246
|
if (!hasData && hasError) {
|
|
3751
4247
|
return false;
|
|
3752
4248
|
}
|
|
4249
|
+
|
|
3753
4250
|
// Explicitly opting-in to running on hydration
|
|
3754
4251
|
if (typeof route.loader === "function" && route.loader.hydrate === true) {
|
|
3755
4252
|
return true;
|
|
3756
4253
|
}
|
|
4254
|
+
|
|
3757
4255
|
// Otherwise, run if we're not yet initialized with anything
|
|
3758
4256
|
return !hasData && !hasError;
|
|
3759
4257
|
}
|
|
@@ -3763,9 +4261,11 @@ function isNewLoader(currentLoaderData, currentMatch, match) {
|
|
|
3763
4261
|
!currentMatch ||
|
|
3764
4262
|
// [a, b] -> [a, c]
|
|
3765
4263
|
match.route.id !== currentMatch.route.id;
|
|
4264
|
+
|
|
3766
4265
|
// Handle the case that we don't have data for a re-used route, potentially
|
|
3767
4266
|
// from a prior error
|
|
3768
4267
|
let isMissingData = !currentLoaderData.hasOwnProperty(match.route.id);
|
|
4268
|
+
|
|
3769
4269
|
// Always load if this is a net-new route or we don't yet have data
|
|
3770
4270
|
return isNew || isMissingData;
|
|
3771
4271
|
}
|
|
@@ -3801,6 +4301,7 @@ function patchRoutesImpl(routeId, children, routesToUse, manifest, mapRoutePrope
|
|
|
3801
4301
|
} else {
|
|
3802
4302
|
childrenToPatch = routesToUse;
|
|
3803
4303
|
}
|
|
4304
|
+
|
|
3804
4305
|
// Don't patch in routes we already know about so that `patch` is idempotent
|
|
3805
4306
|
// to simplify user-land code. This is useful because we re-call the
|
|
3806
4307
|
// `patchRoutesOnNavigation` function for matched routes with params.
|
|
@@ -3813,15 +4314,18 @@ function isSameRoute(newRoute, existingRoute) {
|
|
|
3813
4314
|
if ("id" in newRoute && "id" in existingRoute && newRoute.id === existingRoute.id) {
|
|
3814
4315
|
return true;
|
|
3815
4316
|
}
|
|
4317
|
+
|
|
3816
4318
|
// Second is by pathing differences
|
|
3817
4319
|
if (!(newRoute.index === existingRoute.index && newRoute.path === existingRoute.path && newRoute.caseSensitive === existingRoute.caseSensitive)) {
|
|
3818
4320
|
return false;
|
|
3819
4321
|
}
|
|
4322
|
+
|
|
3820
4323
|
// Pathless layout routes are trickier since we need to check children.
|
|
3821
4324
|
// If they have no children then they're the same as far as we can tell
|
|
3822
4325
|
if ((!newRoute.children || newRoute.children.length === 0) && (!existingRoute.children || existingRoute.children.length === 0)) {
|
|
3823
4326
|
return true;
|
|
3824
4327
|
}
|
|
4328
|
+
|
|
3825
4329
|
// Otherwise, we look to see if every child in the new route is already
|
|
3826
4330
|
// represented in the existing route's children
|
|
3827
4331
|
return newRoute.children.every((aChild, i) => {
|
|
@@ -3829,6 +4333,7 @@ function isSameRoute(newRoute, existingRoute) {
|
|
|
3829
4333
|
return (_existingRoute$childr = existingRoute.children) == null ? void 0 : _existingRoute$childr.some(bChild => isSameRoute(aChild, bChild));
|
|
3830
4334
|
});
|
|
3831
4335
|
}
|
|
4336
|
+
|
|
3832
4337
|
/**
|
|
3833
4338
|
* Execute route.lazy() methods to lazily load route modules (loader, action,
|
|
3834
4339
|
* shouldRevalidate) and update the routeManifest in place which shares objects
|
|
@@ -3839,6 +4344,7 @@ async function loadLazyRouteModule(route, mapRouteProperties, manifest) {
|
|
|
3839
4344
|
return;
|
|
3840
4345
|
}
|
|
3841
4346
|
let lazyRoute = await route.lazy();
|
|
4347
|
+
|
|
3842
4348
|
// If the lazy route function was executed and removed by another parallel
|
|
3843
4349
|
// call then we can return - first lazy() to finish wins because the return
|
|
3844
4350
|
// value of lazy is expected to be static
|
|
@@ -3847,6 +4353,7 @@ async function loadLazyRouteModule(route, mapRouteProperties, manifest) {
|
|
|
3847
4353
|
}
|
|
3848
4354
|
let routeToUpdate = manifest[route.id];
|
|
3849
4355
|
!routeToUpdate ? process.env.NODE_ENV !== "production" ? invariant$2(false, "No route found in manifest") : invariant$2(false) : void 0;
|
|
4356
|
+
|
|
3850
4357
|
// Update the route in place. This should be safe because there's no way
|
|
3851
4358
|
// we could yet be sitting on this route as we can't get there without
|
|
3852
4359
|
// resolving lazy() first.
|
|
@@ -3867,9 +4374,11 @@ async function loadLazyRouteModule(route, mapRouteProperties, manifest) {
|
|
|
3867
4374
|
routeUpdates[lazyRouteProperty] = lazyRoute[lazyRouteProperty];
|
|
3868
4375
|
}
|
|
3869
4376
|
}
|
|
4377
|
+
|
|
3870
4378
|
// Mutate the route with the provided updates. Do this first so we pass
|
|
3871
4379
|
// the updated version to mapRouteProperties
|
|
3872
4380
|
Object.assign(routeToUpdate, routeUpdates);
|
|
4381
|
+
|
|
3873
4382
|
// Mutate the `hasErrorBoundary` property on the route based on the route
|
|
3874
4383
|
// updates and remove the `lazy` function so we don't resolve the lazy
|
|
3875
4384
|
// route again.
|
|
@@ -3877,6 +4386,7 @@ async function loadLazyRouteModule(route, mapRouteProperties, manifest) {
|
|
|
3877
4386
|
lazy: undefined
|
|
3878
4387
|
}));
|
|
3879
4388
|
}
|
|
4389
|
+
|
|
3880
4390
|
// Default implementation of `dataStrategy` which fetches all loaders in parallel
|
|
3881
4391
|
async function defaultDataStrategy(_ref4) {
|
|
3882
4392
|
let {
|
|
@@ -3911,6 +4421,7 @@ async function callDataStrategyImpl(dataStrategyImpl, type, state, request, matc
|
|
|
3911
4421
|
resolve
|
|
3912
4422
|
});
|
|
3913
4423
|
});
|
|
4424
|
+
|
|
3914
4425
|
// Send all matches here to allow for a middleware-type implementation.
|
|
3915
4426
|
// handler will be a no-op for unneeded routes and we filter those results
|
|
3916
4427
|
// back out below.
|
|
@@ -3921,6 +4432,7 @@ async function callDataStrategyImpl(dataStrategyImpl, type, state, request, matc
|
|
|
3921
4432
|
fetcherKey,
|
|
3922
4433
|
context: requestContext
|
|
3923
4434
|
});
|
|
4435
|
+
|
|
3924
4436
|
// Wait for all routes to load here but 'swallow the error since we want
|
|
3925
4437
|
// it to bubble up from the `await loadRoutePromise` in `callLoaderOrAction` -
|
|
3926
4438
|
// called from `match.resolve()`
|
|
@@ -3931,6 +4443,7 @@ async function callDataStrategyImpl(dataStrategyImpl, type, state, request, matc
|
|
|
3931
4443
|
}
|
|
3932
4444
|
return results;
|
|
3933
4445
|
}
|
|
4446
|
+
|
|
3934
4447
|
// Default logic for calling a loader/action is the user has no specified a dataStrategy
|
|
3935
4448
|
async function callLoaderOrAction(type, request, match, loadRoutePromise, handlerOverride, staticContext) {
|
|
3936
4449
|
let result;
|
|
@@ -3971,6 +4484,7 @@ async function callLoaderOrAction(type, request, match, loadRoutePromise, handle
|
|
|
3971
4484
|
};
|
|
3972
4485
|
try {
|
|
3973
4486
|
let handler = match.route[type];
|
|
4487
|
+
|
|
3974
4488
|
// If we have a route.lazy promise, await that first
|
|
3975
4489
|
if (loadRoutePromise) {
|
|
3976
4490
|
if (handler) {
|
|
@@ -4042,7 +4556,7 @@ async function convertDataStrategyResultToDataResult(dataStrategyResult) {
|
|
|
4042
4556
|
result,
|
|
4043
4557
|
type
|
|
4044
4558
|
} = dataStrategyResult;
|
|
4045
|
-
if (isResponse
|
|
4559
|
+
if (isResponse(result)) {
|
|
4046
4560
|
let data;
|
|
4047
4561
|
try {
|
|
4048
4562
|
let contentType = result.headers.get("Content-Type");
|
|
@@ -4089,6 +4603,7 @@ async function convertDataStrategyResultToDataResult(dataStrategyResult) {
|
|
|
4089
4603
|
statusCode: (_result$init = result.init) == null ? void 0 : _result$init.status
|
|
4090
4604
|
};
|
|
4091
4605
|
}
|
|
4606
|
+
|
|
4092
4607
|
// Convert thrown data() to ErrorResponse instances
|
|
4093
4608
|
result = new ErrorResponseImpl(((_result$init2 = result.init) == null ? void 0 : _result$init2.status) || 500, undefined, result.data);
|
|
4094
4609
|
}
|
|
@@ -4112,6 +4627,7 @@ async function convertDataStrategyResultToDataResult(dataStrategyResult) {
|
|
|
4112
4627
|
data: result
|
|
4113
4628
|
};
|
|
4114
4629
|
}
|
|
4630
|
+
|
|
4115
4631
|
// Support relative routing in internal redirects
|
|
4116
4632
|
function normalizeRelativeRoutingRedirectResponse(response, request, routeId, matches, basename) {
|
|
4117
4633
|
let location = response.headers.get("Location");
|
|
@@ -4135,6 +4651,7 @@ function normalizeRedirectLocation(location, currentUrl, basename) {
|
|
|
4135
4651
|
}
|
|
4136
4652
|
return location;
|
|
4137
4653
|
}
|
|
4654
|
+
|
|
4138
4655
|
// Utility method for creating the Request instances for loaders/actions during
|
|
4139
4656
|
// client-side navigations and fetches. During SSR we will always have a
|
|
4140
4657
|
// Request instance from the static handler (query/queryRoute)
|
|
@@ -4199,6 +4716,7 @@ function processRouteLoaderData(matches, results, pendingActionResult, isStaticH
|
|
|
4199
4716
|
let foundError = false;
|
|
4200
4717
|
let loaderHeaders = {};
|
|
4201
4718
|
let pendingError = pendingActionResult && isErrorResult(pendingActionResult[1]) ? pendingActionResult[1].error : undefined;
|
|
4719
|
+
|
|
4202
4720
|
// Process loader results into state.loaderData/state.errors
|
|
4203
4721
|
matches.forEach(match => {
|
|
4204
4722
|
if (!(match.route.id in results)) {
|
|
@@ -4228,10 +4746,12 @@ function processRouteLoaderData(matches, results, pendingActionResult, isStaticH
|
|
|
4228
4746
|
errors[boundaryMatch.route.id] = error;
|
|
4229
4747
|
}
|
|
4230
4748
|
}
|
|
4749
|
+
|
|
4231
4750
|
// Clear our any prior loaderData for the throwing route
|
|
4232
4751
|
if (!isStaticHandler) {
|
|
4233
4752
|
loaderData[id] = ResetLoaderDataSymbol;
|
|
4234
4753
|
}
|
|
4754
|
+
|
|
4235
4755
|
// Once we find our first (highest) error, we set the status code and
|
|
4236
4756
|
// prevent deeper status codes from overriding
|
|
4237
4757
|
if (!foundError) {
|
|
@@ -4253,6 +4773,7 @@ function processRouteLoaderData(matches, results, pendingActionResult, isStaticH
|
|
|
4253
4773
|
}
|
|
4254
4774
|
}
|
|
4255
4775
|
});
|
|
4776
|
+
|
|
4256
4777
|
// If we didn't consume the pending action error (i.e., all loaders
|
|
4257
4778
|
// resolved), then consume it here. Also clear out any loaderData for the
|
|
4258
4779
|
// throwing route
|
|
@@ -4274,6 +4795,7 @@ function processLoaderData(state, matches, results, pendingActionResult, revalid
|
|
|
4274
4795
|
loaderData,
|
|
4275
4796
|
errors
|
|
4276
4797
|
} = processRouteLoaderData(matches, results, pendingActionResult);
|
|
4798
|
+
|
|
4277
4799
|
// Process results from our revalidating fetchers
|
|
4278
4800
|
revalidatingFetchers.forEach(rf => {
|
|
4279
4801
|
let {
|
|
@@ -4283,6 +4805,7 @@ function processLoaderData(state, matches, results, pendingActionResult, revalid
|
|
|
4283
4805
|
} = rf;
|
|
4284
4806
|
let result = fetcherResults[key];
|
|
4285
4807
|
!result ? process.env.NODE_ENV !== "production" ? invariant$2(false, "Did not find corresponding fetcher result") : invariant$2(false) : void 0;
|
|
4808
|
+
|
|
4286
4809
|
// Process fetcher non-redirect errors
|
|
4287
4810
|
if (controller && controller.signal.aborted) {
|
|
4288
4811
|
// Nothing to do for aborted fetchers
|
|
@@ -4319,6 +4842,7 @@ function mergeLoaderData(loaderData, newLoaderData, matches, errors) {
|
|
|
4319
4842
|
merged[k] = v;
|
|
4320
4843
|
return merged;
|
|
4321
4844
|
}, {});
|
|
4845
|
+
|
|
4322
4846
|
// Preserve existing `loaderData` for routes not included in `newLoaderData` and
|
|
4323
4847
|
// where a loader wasn't removed by HMR
|
|
4324
4848
|
for (let match of matches) {
|
|
@@ -4346,6 +4870,7 @@ function getActionDataForCommit(pendingActionResult) {
|
|
|
4346
4870
|
}
|
|
4347
4871
|
};
|
|
4348
4872
|
}
|
|
4873
|
+
|
|
4349
4874
|
// Find the nearest error boundary, looking upwards from the leaf route (or the
|
|
4350
4875
|
// route specified by routeId) for the closest ancestor error boundary,
|
|
4351
4876
|
// defaulting to the root match
|
|
@@ -4401,6 +4926,7 @@ function getInternalRouterError(status, _temp5) {
|
|
|
4401
4926
|
}
|
|
4402
4927
|
return new ErrorResponseImpl(status || 500, statusText, new Error(errorMessage), true);
|
|
4403
4928
|
}
|
|
4929
|
+
|
|
4404
4930
|
// Find any returned redirect errors, starting from the lowest match
|
|
4405
4931
|
function findRedirect(results) {
|
|
4406
4932
|
let entries = Object.entries(results);
|
|
@@ -4434,6 +4960,7 @@ function isHashChangeOnly(a, b) {
|
|
|
4434
4960
|
// /page#hash -> /page#other
|
|
4435
4961
|
return true;
|
|
4436
4962
|
}
|
|
4963
|
+
|
|
4437
4964
|
// If the hash is removed the browser will re-perform a request to the server
|
|
4438
4965
|
// /page#hash -> /page
|
|
4439
4966
|
return false;
|
|
@@ -4441,8 +4968,8 @@ function isHashChangeOnly(a, b) {
|
|
|
4441
4968
|
function isDataStrategyResult(result) {
|
|
4442
4969
|
return result != null && typeof result === "object" && "type" in result && "result" in result && (result.type === ResultType.data || result.type === ResultType.error);
|
|
4443
4970
|
}
|
|
4444
|
-
function
|
|
4445
|
-
return isResponse
|
|
4971
|
+
function isRedirectDataStrategyResult(result) {
|
|
4972
|
+
return isResponse(result.result) && redirectStatusCodes.has(result.result.status);
|
|
4446
4973
|
}
|
|
4447
4974
|
function isErrorResult(result) {
|
|
4448
4975
|
return result.type === ResultType.error;
|
|
@@ -4453,16 +4980,14 @@ function isRedirectResult(result) {
|
|
|
4453
4980
|
function isDataWithResponseInit(value) {
|
|
4454
4981
|
return typeof value === "object" && value != null && "type" in value && "data" in value && "init" in value && value.type === "DataWithResponseInit";
|
|
4455
4982
|
}
|
|
4456
|
-
function isResponse
|
|
4983
|
+
function isResponse(value) {
|
|
4457
4984
|
return value != null && typeof value.status === "number" && typeof value.statusText === "string" && typeof value.headers === "object" && typeof value.body !== "undefined";
|
|
4458
4985
|
}
|
|
4459
|
-
function
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
let location = result.headers.get("Location");
|
|
4465
|
-
return status >= 300 && status <= 399 && location != null;
|
|
4986
|
+
function isRedirectStatusCode(statusCode) {
|
|
4987
|
+
return redirectStatusCodes.has(statusCode);
|
|
4988
|
+
}
|
|
4989
|
+
function isRedirectResponse(result) {
|
|
4990
|
+
return isResponse(result) && isRedirectStatusCode(result.status) && result.headers.has("Location");
|
|
4466
4991
|
}
|
|
4467
4992
|
function isValidMethod(method) {
|
|
4468
4993
|
return validRequestMethods.has(method.toUpperCase());
|
|
@@ -4673,6 +5198,9 @@ function createDeferred$1() {
|
|
|
4673
5198
|
}
|
|
4674
5199
|
//#endregion
|
|
4675
5200
|
|
|
5201
|
+
// Create react-specific types from the agnostic types in @remix-run/router to
|
|
5202
|
+
// export from react-router
|
|
5203
|
+
|
|
4676
5204
|
const DataRouterContext = /*#__PURE__*/React.createContext(null);
|
|
4677
5205
|
DataRouterContext.displayName = "DataRouter";
|
|
4678
5206
|
const DataRouterStateContext = /*#__PURE__*/React.createContext(null);
|
|
@@ -4681,10 +5209,24 @@ const ViewTransitionContext = /*#__PURE__*/React.createContext({
|
|
|
4681
5209
|
isTransitioning: false
|
|
4682
5210
|
});
|
|
4683
5211
|
ViewTransitionContext.displayName = "ViewTransition";
|
|
5212
|
+
|
|
5213
|
+
// TODO: (v7) Change the useFetcher data from `any` to `unknown`
|
|
5214
|
+
|
|
4684
5215
|
const FetchersContext = /*#__PURE__*/React.createContext(new Map());
|
|
4685
5216
|
FetchersContext.displayName = "Fetchers";
|
|
4686
5217
|
const AwaitContext = /*#__PURE__*/React.createContext(null);
|
|
4687
5218
|
AwaitContext.displayName = "Await";
|
|
5219
|
+
|
|
5220
|
+
/**
|
|
5221
|
+
* A Navigator is a "location changer"; it's how you get to different locations.
|
|
5222
|
+
*
|
|
5223
|
+
* Every history instance conforms to the Navigator interface, but the
|
|
5224
|
+
* distinction is useful primarily when it comes to the low-level `<Router>` API
|
|
5225
|
+
* where both the location and a navigator must be provided separately in order
|
|
5226
|
+
* to avoid "tearing" that may occur in a suspense-enabled app if the action
|
|
5227
|
+
* and/or location were to be read directly from the history instance.
|
|
5228
|
+
*/
|
|
5229
|
+
|
|
4688
5230
|
const NavigationContext = /*#__PURE__*/React.createContext(null);
|
|
4689
5231
|
NavigationContext.displayName = "Navigation";
|
|
4690
5232
|
const LocationContext = /*#__PURE__*/React.createContext(null);
|
|
@@ -4731,6 +5273,7 @@ function useHref(to, _temp) {
|
|
|
4731
5273
|
relative
|
|
4732
5274
|
});
|
|
4733
5275
|
let joinedPathname = pathname;
|
|
5276
|
+
|
|
4734
5277
|
// If we're operating within a basename, prepend it to the pathname prior
|
|
4735
5278
|
// to creating the href. If this is a root navigation, then just use the raw
|
|
4736
5279
|
// basename which allows the basename to have full control over the presence
|
|
@@ -4744,6 +5287,7 @@ function useHref(to, _temp) {
|
|
|
4744
5287
|
hash
|
|
4745
5288
|
});
|
|
4746
5289
|
}
|
|
5290
|
+
|
|
4747
5291
|
/**
|
|
4748
5292
|
* Returns true if this component is a descendant of a Router, useful to ensure
|
|
4749
5293
|
* a component is used within a Router.
|
|
@@ -4753,6 +5297,7 @@ function useHref(to, _temp) {
|
|
|
4753
5297
|
function useInRouterContext() {
|
|
4754
5298
|
return React.useContext(LocationContext) != null;
|
|
4755
5299
|
}
|
|
5300
|
+
|
|
4756
5301
|
/**
|
|
4757
5302
|
Returns the current {@link Location}. This can be useful if you'd like to perform some side effect whenever it changes.
|
|
4758
5303
|
|
|
@@ -4782,6 +5327,7 @@ function useLocation() {
|
|
|
4782
5327
|
"useLocation() may be used only in the context of a <Router> component.") : invariant$2(false) : void 0;
|
|
4783
5328
|
return React.useContext(LocationContext).location;
|
|
4784
5329
|
}
|
|
5330
|
+
|
|
4785
5331
|
/**
|
|
4786
5332
|
* Returns the current navigation action which describes how the router came to
|
|
4787
5333
|
* the current location, either by a pop, push, or replace on the history stack.
|
|
@@ -4791,6 +5337,7 @@ function useLocation() {
|
|
|
4791
5337
|
function useNavigationType() {
|
|
4792
5338
|
return React.useContext(LocationContext).navigationType;
|
|
4793
5339
|
}
|
|
5340
|
+
|
|
4794
5341
|
/**
|
|
4795
5342
|
* Returns a PathMatch object if the given pattern matches the current URL.
|
|
4796
5343
|
* This is useful for components that need to know "active" state, e.g.
|
|
@@ -4807,7 +5354,13 @@ function useMatch(pattern) {
|
|
|
4807
5354
|
} = useLocation();
|
|
4808
5355
|
return React.useMemo(() => matchPath(pattern, decodePath(pathname)), [pathname, pattern]);
|
|
4809
5356
|
}
|
|
5357
|
+
|
|
5358
|
+
/**
|
|
5359
|
+
* The interface for the navigate() function returned from useNavigate().
|
|
5360
|
+
*/
|
|
5361
|
+
|
|
4810
5362
|
const navigateEffectWarning = "You should call navigate() in a React.useEffect(), not when " + "your component is first rendered.";
|
|
5363
|
+
|
|
4811
5364
|
// Mute warnings for calls to useNavigate in SSR environments
|
|
4812
5365
|
function useIsomorphicLayoutEffect(cb) {
|
|
4813
5366
|
let isStatic = React.useContext(NavigationContext).static;
|
|
@@ -4818,6 +5371,7 @@ function useIsomorphicLayoutEffect(cb) {
|
|
|
4818
5371
|
React.useLayoutEffect(cb);
|
|
4819
5372
|
}
|
|
4820
5373
|
}
|
|
5374
|
+
|
|
4821
5375
|
/**
|
|
4822
5376
|
Returns a function that lets you navigate programmatically in the browser in response to user interactions or effects.
|
|
4823
5377
|
|
|
@@ -4873,6 +5427,7 @@ function useNavigateUnstable() {
|
|
|
4873
5427
|
options = {};
|
|
4874
5428
|
}
|
|
4875
5429
|
process.env.NODE_ENV !== "production" ? warning(activeRef.current, navigateEffectWarning) : void 0;
|
|
5430
|
+
|
|
4876
5431
|
// Short circuit here since if this happens on first render the navigate
|
|
4877
5432
|
// is useless because we haven't wired up our history listener yet
|
|
4878
5433
|
if (!activeRef.current) return;
|
|
@@ -4881,6 +5436,7 @@ function useNavigateUnstable() {
|
|
|
4881
5436
|
return;
|
|
4882
5437
|
}
|
|
4883
5438
|
let path = resolveTo(to, JSON.parse(routePathnamesJson), locationPathname, options.relative === "path");
|
|
5439
|
+
|
|
4884
5440
|
// If we're operating within a basename, prepend it to the pathname prior
|
|
4885
5441
|
// to handing off to history (but only if we're not in a data router,
|
|
4886
5442
|
// otherwise it'll prepend the basename inside of the router).
|
|
@@ -4895,6 +5451,7 @@ function useNavigateUnstable() {
|
|
|
4895
5451
|
return navigate;
|
|
4896
5452
|
}
|
|
4897
5453
|
const OutletContext = /*#__PURE__*/React.createContext(null);
|
|
5454
|
+
|
|
4898
5455
|
/**
|
|
4899
5456
|
* Returns the parent route {@link OutletProps.context | `<Outlet context>`}.
|
|
4900
5457
|
*
|
|
@@ -4903,6 +5460,7 @@ const OutletContext = /*#__PURE__*/React.createContext(null);
|
|
|
4903
5460
|
function useOutletContext() {
|
|
4904
5461
|
return React.useContext(OutletContext);
|
|
4905
5462
|
}
|
|
5463
|
+
|
|
4906
5464
|
/**
|
|
4907
5465
|
* Returns the element for the child route at this level of the route
|
|
4908
5466
|
* hierarchy. Used internally by `<Outlet>` to render child routes.
|
|
@@ -4918,6 +5476,7 @@ function useOutlet(context) {
|
|
|
4918
5476
|
}
|
|
4919
5477
|
return outlet;
|
|
4920
5478
|
}
|
|
5479
|
+
|
|
4921
5480
|
/**
|
|
4922
5481
|
Returns an object of key/value pairs of the dynamic params from the current URL that were matched by the routes. Child routes inherit all params from their parent routes.
|
|
4923
5482
|
|
|
@@ -4941,6 +5500,7 @@ function useParams() {
|
|
|
4941
5500
|
let routeMatch = matches[matches.length - 1];
|
|
4942
5501
|
return routeMatch ? routeMatch.params : {};
|
|
4943
5502
|
}
|
|
5503
|
+
|
|
4944
5504
|
/**
|
|
4945
5505
|
Resolves the pathname of the given `to` value against the current location. Similar to {@link useHref}, but returns a {@link Path} instead of a string.
|
|
4946
5506
|
|
|
@@ -4971,6 +5531,7 @@ function useResolvedPath(to, _temp2) {
|
|
|
4971
5531
|
let routePathnamesJson = JSON.stringify(getResolveToMatches(matches));
|
|
4972
5532
|
return React.useMemo(() => resolveTo(to, JSON.parse(routePathnamesJson), locationPathname, relative === "path"), [to, routePathnamesJson, locationPathname, relative]);
|
|
4973
5533
|
}
|
|
5534
|
+
|
|
4974
5535
|
/**
|
|
4975
5536
|
Hook version of {@link Routes | `<Routes>`} that uses objects instead of components. These objects have the same properties as the component props.
|
|
4976
5537
|
|
|
@@ -5005,6 +5566,7 @@ function useResolvedPath(to, _temp2) {
|
|
|
5005
5566
|
function useRoutes(routes, locationArg) {
|
|
5006
5567
|
return useRoutesImpl(routes, locationArg);
|
|
5007
5568
|
}
|
|
5569
|
+
|
|
5008
5570
|
/**
|
|
5009
5571
|
* Internal implementation with accept optional param for RouterProvider usage
|
|
5010
5572
|
*
|
|
@@ -5097,6 +5659,7 @@ function useRoutesImpl(routes, locationArg, dataRouterState, future) {
|
|
|
5097
5659
|
// Re-encode pathnames that were decoded inside matchRoutes
|
|
5098
5660
|
navigator.encodeLocation ? navigator.encodeLocation(match.pathnameBase).pathname : match.pathnameBase])
|
|
5099
5661
|
})), parentMatches, dataRouterState);
|
|
5662
|
+
|
|
5100
5663
|
// When a user passes in a `locationArg`, the associated routes need to
|
|
5101
5664
|
// be wrapped in a new `LocationContext.Provider` in order for `useLocation`
|
|
5102
5665
|
// to use the scoped location instead of the global location.
|
|
@@ -5177,6 +5740,7 @@ class RenderErrorBoundary extends React.Component {
|
|
|
5177
5740
|
revalidation: props.revalidation
|
|
5178
5741
|
};
|
|
5179
5742
|
}
|
|
5743
|
+
|
|
5180
5744
|
// If we're not changing locations, preserve the location but still surface
|
|
5181
5745
|
// any new errors that may come through. We retain the existing error, we do
|
|
5182
5746
|
// this because the error provided from the app state may be cleared without
|
|
@@ -5191,12 +5755,12 @@ class RenderErrorBoundary extends React.Component {
|
|
|
5191
5755
|
console.error("React Router caught the following error during render", error, errorInfo);
|
|
5192
5756
|
}
|
|
5193
5757
|
render() {
|
|
5194
|
-
return this.state.error !== undefined ?
|
|
5758
|
+
return this.state.error !== undefined ? /*#__PURE__*/React.createElement(RouteContext.Provider, {
|
|
5195
5759
|
value: this.props.routeContext
|
|
5196
5760
|
}, /*#__PURE__*/React.createElement(RouteErrorContext.Provider, {
|
|
5197
5761
|
value: this.state.error,
|
|
5198
5762
|
children: this.props.component
|
|
5199
|
-
}))
|
|
5763
|
+
})) : this.props.children;
|
|
5200
5764
|
}
|
|
5201
5765
|
}
|
|
5202
5766
|
function RenderedRoute(_ref) {
|
|
@@ -5206,6 +5770,7 @@ function RenderedRoute(_ref) {
|
|
|
5206
5770
|
children
|
|
5207
5771
|
} = _ref;
|
|
5208
5772
|
let dataRouterContext = React.useContext(DataRouterContext);
|
|
5773
|
+
|
|
5209
5774
|
// Track how deep we got in our render pass to emulate SSR componentDidCatch
|
|
5210
5775
|
// in a DataStaticRouter
|
|
5211
5776
|
if (dataRouterContext && dataRouterContext.static && dataRouterContext.staticContext && (match.route.errorElement || match.route.ErrorBoundary)) {
|
|
@@ -5244,6 +5809,7 @@ function _renderMatches(matches, parentMatches, dataRouterState, future) {
|
|
|
5244
5809
|
}
|
|
5245
5810
|
}
|
|
5246
5811
|
let renderedMatches = matches;
|
|
5812
|
+
|
|
5247
5813
|
// If we have data errors, trim matches to the highest error boundary
|
|
5248
5814
|
let errors = (_dataRouterState = dataRouterState) == null ? void 0 : _dataRouterState.errors;
|
|
5249
5815
|
if (errors != null) {
|
|
@@ -5251,6 +5817,7 @@ function _renderMatches(matches, parentMatches, dataRouterState, future) {
|
|
|
5251
5817
|
!(errorIndex >= 0) ? process.env.NODE_ENV !== "production" ? invariant$2(false, "Could not find a matching route for errors on route IDs: " + Object.keys(errors).join(",")) : invariant$2(false) : void 0;
|
|
5252
5818
|
renderedMatches = renderedMatches.slice(0, Math.min(renderedMatches.length, errorIndex + 1));
|
|
5253
5819
|
}
|
|
5820
|
+
|
|
5254
5821
|
// If we're in a partial hydration mode, detect if we need to render down to
|
|
5255
5822
|
// a given HydrateFallback while we load the rest of the hydration data
|
|
5256
5823
|
let renderFallback = false;
|
|
@@ -5336,7 +5903,7 @@ function _renderMatches(matches, parentMatches, dataRouterState, future) {
|
|
|
5336
5903
|
// Only wrap in an error boundary within data router usages when we have an
|
|
5337
5904
|
// ErrorBoundary/errorElement on this route. Otherwise let it bubble up to
|
|
5338
5905
|
// an ancestor ErrorBoundary/errorElement
|
|
5339
|
-
return dataRouterState && (match.route.ErrorBoundary || match.route.errorElement || index === 0) ?
|
|
5906
|
+
return dataRouterState && (match.route.ErrorBoundary || match.route.errorElement || index === 0) ? /*#__PURE__*/React.createElement(RenderErrorBoundary, {
|
|
5340
5907
|
location: dataRouterState.location,
|
|
5341
5908
|
revalidation: dataRouterState.revalidation,
|
|
5342
5909
|
component: errorElement,
|
|
@@ -5347,17 +5914,16 @@ function _renderMatches(matches, parentMatches, dataRouterState, future) {
|
|
|
5347
5914
|
matches,
|
|
5348
5915
|
isDataRoute: true
|
|
5349
5916
|
}
|
|
5350
|
-
})
|
|
5917
|
+
}) : getChildren();
|
|
5351
5918
|
}, null);
|
|
5352
5919
|
}
|
|
5353
|
-
var DataRouterHook$1
|
|
5354
|
-
(function (DataRouterHook) {
|
|
5920
|
+
var DataRouterHook$1 = /*#__PURE__*/function (DataRouterHook) {
|
|
5355
5921
|
DataRouterHook["UseBlocker"] = "useBlocker";
|
|
5356
5922
|
DataRouterHook["UseRevalidator"] = "useRevalidator";
|
|
5357
5923
|
DataRouterHook["UseNavigateStable"] = "useNavigate";
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5924
|
+
return DataRouterHook;
|
|
5925
|
+
}(DataRouterHook$1 || {});
|
|
5926
|
+
var DataRouterStateHook$1 = /*#__PURE__*/function (DataRouterStateHook) {
|
|
5361
5927
|
DataRouterStateHook["UseBlocker"] = "useBlocker";
|
|
5362
5928
|
DataRouterStateHook["UseLoaderData"] = "useLoaderData";
|
|
5363
5929
|
DataRouterStateHook["UseActionData"] = "useActionData";
|
|
@@ -5368,7 +5934,8 @@ var DataRouterStateHook$1;
|
|
|
5368
5934
|
DataRouterStateHook["UseRevalidator"] = "useRevalidator";
|
|
5369
5935
|
DataRouterStateHook["UseNavigateStable"] = "useNavigate";
|
|
5370
5936
|
DataRouterStateHook["UseRouteId"] = "useRouteId";
|
|
5371
|
-
|
|
5937
|
+
return DataRouterStateHook;
|
|
5938
|
+
}(DataRouterStateHook$1 || {});
|
|
5372
5939
|
function getDataRouterConsoleError$1(hookName) {
|
|
5373
5940
|
return hookName + " must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.";
|
|
5374
5941
|
}
|
|
@@ -5387,6 +5954,7 @@ function useRouteContext(hookName) {
|
|
|
5387
5954
|
!route ? process.env.NODE_ENV !== "production" ? invariant$2(false, getDataRouterConsoleError$1(hookName)) : invariant$2(false) : void 0;
|
|
5388
5955
|
return route;
|
|
5389
5956
|
}
|
|
5957
|
+
|
|
5390
5958
|
// Internal version with hookName-aware debugging
|
|
5391
5959
|
function useCurrentRouteId(hookName) {
|
|
5392
5960
|
let route = useRouteContext(hookName);
|
|
@@ -5394,12 +5962,14 @@ function useCurrentRouteId(hookName) {
|
|
|
5394
5962
|
!thisRoute.route.id ? process.env.NODE_ENV !== "production" ? invariant$2(false, hookName + " can only be used on routes that contain a unique \"id\"") : invariant$2(false) : void 0;
|
|
5395
5963
|
return thisRoute.route.id;
|
|
5396
5964
|
}
|
|
5965
|
+
|
|
5397
5966
|
/**
|
|
5398
5967
|
* Returns the ID for the nearest contextual route
|
|
5399
5968
|
*/
|
|
5400
5969
|
function useRouteId() {
|
|
5401
5970
|
return useCurrentRouteId(DataRouterStateHook$1.UseRouteId);
|
|
5402
5971
|
}
|
|
5972
|
+
|
|
5403
5973
|
/**
|
|
5404
5974
|
Returns the current navigation, defaulting to an "idle" navigation when no navigation is in progress. You can use this to render pending UI (like a global spinner) or read FormData from a form navigation.
|
|
5405
5975
|
|
|
@@ -5420,6 +5990,7 @@ function useNavigation() {
|
|
|
5420
5990
|
let state = useDataRouterState$1(DataRouterStateHook$1.UseNavigation);
|
|
5421
5991
|
return state.navigation;
|
|
5422
5992
|
}
|
|
5993
|
+
|
|
5423
5994
|
/**
|
|
5424
5995
|
Revalidate the data on the page for reasons outside of normal data mutations like window focus or polling on an interval.
|
|
5425
5996
|
|
|
@@ -5455,6 +6026,7 @@ function useRevalidator() {
|
|
|
5455
6026
|
state: state.revalidation
|
|
5456
6027
|
}), [dataRouterContext.router, state.revalidation]);
|
|
5457
6028
|
}
|
|
6029
|
+
|
|
5458
6030
|
/**
|
|
5459
6031
|
* Returns the active route matches, useful for accessing loaderData for
|
|
5460
6032
|
* parent/child routes or the route "handle" property
|
|
@@ -5468,6 +6040,7 @@ function useMatches() {
|
|
|
5468
6040
|
} = useDataRouterState$1(DataRouterStateHook$1.UseMatches);
|
|
5469
6041
|
return React.useMemo(() => matches.map(m => convertRouteMatchToUiMatch(m, loaderData)), [matches, loaderData]);
|
|
5470
6042
|
}
|
|
6043
|
+
|
|
5471
6044
|
/**
|
|
5472
6045
|
Returns the data from the closest route {@link LoaderFunction | loader} or {@link ClientLoaderFunction | client loader}.
|
|
5473
6046
|
|
|
@@ -5491,6 +6064,7 @@ function useLoaderData() {
|
|
|
5491
6064
|
let routeId = useCurrentRouteId(DataRouterStateHook$1.UseLoaderData);
|
|
5492
6065
|
return state.loaderData[routeId];
|
|
5493
6066
|
}
|
|
6067
|
+
|
|
5494
6068
|
/**
|
|
5495
6069
|
Returns the loader data for a given route by route ID.
|
|
5496
6070
|
|
|
@@ -5522,6 +6096,7 @@ function useRouteLoaderData(routeId) {
|
|
|
5522
6096
|
let state = useDataRouterState$1(DataRouterStateHook$1.UseRouteLoaderData);
|
|
5523
6097
|
return state.loaderData[routeId];
|
|
5524
6098
|
}
|
|
6099
|
+
|
|
5525
6100
|
/**
|
|
5526
6101
|
Returns the action data from the most recent POST navigation form submission or `undefined` if there hasn't been one.
|
|
5527
6102
|
|
|
@@ -5552,6 +6127,7 @@ function useActionData() {
|
|
|
5552
6127
|
let routeId = useCurrentRouteId(DataRouterStateHook$1.UseLoaderData);
|
|
5553
6128
|
return state.actionData ? state.actionData[routeId] : undefined;
|
|
5554
6129
|
}
|
|
6130
|
+
|
|
5555
6131
|
/**
|
|
5556
6132
|
Accesses the error thrown during an {@link ActionFunction | action}, {@link LoaderFunction | loader}, or component render to be used in a route module Error Boundary.
|
|
5557
6133
|
|
|
@@ -5569,14 +6145,17 @@ function useRouteError() {
|
|
|
5569
6145
|
let error = React.useContext(RouteErrorContext);
|
|
5570
6146
|
let state = useDataRouterState$1(DataRouterStateHook$1.UseRouteError);
|
|
5571
6147
|
let routeId = useCurrentRouteId(DataRouterStateHook$1.UseRouteError);
|
|
6148
|
+
|
|
5572
6149
|
// If this was a render error, we put it in a RouteError context inside
|
|
5573
6150
|
// of RenderErrorBoundary
|
|
5574
6151
|
if (error !== undefined) {
|
|
5575
6152
|
return error;
|
|
5576
6153
|
}
|
|
6154
|
+
|
|
5577
6155
|
// Otherwise look for errors from our data router state
|
|
5578
6156
|
return (_state$errors = state.errors) == null ? void 0 : _state$errors[routeId];
|
|
5579
6157
|
}
|
|
6158
|
+
|
|
5580
6159
|
/**
|
|
5581
6160
|
Returns the resolved promise value from the closest {@link Await | `<Await>`}.
|
|
5582
6161
|
|
|
@@ -5598,6 +6177,7 @@ function useAsyncValue() {
|
|
|
5598
6177
|
let value = React.useContext(AwaitContext);
|
|
5599
6178
|
return value == null ? void 0 : value._data;
|
|
5600
6179
|
}
|
|
6180
|
+
|
|
5601
6181
|
/**
|
|
5602
6182
|
Returns the rejection value from the closest {@link Await | `<Await>`}.
|
|
5603
6183
|
|
|
@@ -5625,6 +6205,7 @@ function useAsyncError() {
|
|
|
5625
6205
|
return value == null ? void 0 : value._error;
|
|
5626
6206
|
}
|
|
5627
6207
|
let blockerId = 0;
|
|
6208
|
+
|
|
5628
6209
|
/**
|
|
5629
6210
|
* Allow the application to block navigations within the SPA and present the
|
|
5630
6211
|
* user a confirmation dialog to confirm the navigation. Mostly used to avoid
|
|
@@ -5647,6 +6228,7 @@ function useBlocker(shouldBlock) {
|
|
|
5647
6228
|
if (basename === "/") {
|
|
5648
6229
|
return shouldBlock(arg);
|
|
5649
6230
|
}
|
|
6231
|
+
|
|
5650
6232
|
// If they provided us a function and we've got an active basename, strip
|
|
5651
6233
|
// it from the locations we expose to the user to match the behavior of
|
|
5652
6234
|
// useLocation
|
|
@@ -5665,6 +6247,7 @@ function useBlocker(shouldBlock) {
|
|
|
5665
6247
|
historyAction
|
|
5666
6248
|
});
|
|
5667
6249
|
}, [basename, shouldBlock]);
|
|
6250
|
+
|
|
5668
6251
|
// This effect is in charge of blocker key assignment and deletion (which is
|
|
5669
6252
|
// tightly coupled to the key)
|
|
5670
6253
|
React.useEffect(() => {
|
|
@@ -5672,6 +6255,7 @@ function useBlocker(shouldBlock) {
|
|
|
5672
6255
|
setBlockerKey(key);
|
|
5673
6256
|
return () => router.deleteBlocker(key);
|
|
5674
6257
|
}, [router]);
|
|
6258
|
+
|
|
5675
6259
|
// This effect handles assigning the blockerFunction. This is to handle
|
|
5676
6260
|
// unstable blocker function identities, and happens only after the prior
|
|
5677
6261
|
// effect so we don't get an orphaned blockerFunction in the router with a
|
|
@@ -5681,10 +6265,12 @@ function useBlocker(shouldBlock) {
|
|
|
5681
6265
|
router.getBlocker(blockerKey, blockerFunction);
|
|
5682
6266
|
}
|
|
5683
6267
|
}, [router, blockerKey, blockerFunction]);
|
|
6268
|
+
|
|
5684
6269
|
// Prefer the blocker from `state` not `router.state` since DataRouterContext
|
|
5685
6270
|
// is memoized so this ensures we update on blocker state updates
|
|
5686
6271
|
return blockerKey && state.blockers.has(blockerKey) ? state.blockers.get(blockerKey) : IDLE_BLOCKER;
|
|
5687
6272
|
}
|
|
6273
|
+
|
|
5688
6274
|
/**
|
|
5689
6275
|
* Stable version of useNavigate that is used when we are in the context of
|
|
5690
6276
|
* a RouterProvider.
|
|
@@ -5705,6 +6291,7 @@ function useNavigateStable() {
|
|
|
5705
6291
|
options = {};
|
|
5706
6292
|
}
|
|
5707
6293
|
process.env.NODE_ENV !== "production" ? warning(activeRef.current, navigateEffectWarning) : void 0;
|
|
6294
|
+
|
|
5708
6295
|
// Short circuit here since if this happens on first render the navigate
|
|
5709
6296
|
// is useless because we haven't wired up our router subscriber yet
|
|
5710
6297
|
if (!activeRef.current) return;
|
|
@@ -5778,6 +6365,7 @@ function mapRouteProperties(route) {
|
|
|
5778
6365
|
}
|
|
5779
6366
|
return updates;
|
|
5780
6367
|
}
|
|
6368
|
+
|
|
5781
6369
|
/**
|
|
5782
6370
|
* @category Routers
|
|
5783
6371
|
*/
|
|
@@ -5797,6 +6385,10 @@ function createMemoryRouter(routes, opts) {
|
|
|
5797
6385
|
}).initialize();
|
|
5798
6386
|
}
|
|
5799
6387
|
class Deferred {
|
|
6388
|
+
// @ts-expect-error - no initializer
|
|
6389
|
+
|
|
6390
|
+
// @ts-expect-error - no initializer
|
|
6391
|
+
|
|
5800
6392
|
constructor() {
|
|
5801
6393
|
this.status = "pending";
|
|
5802
6394
|
this.promise = new Promise((resolve, reject) => {
|
|
@@ -5815,6 +6407,9 @@ class Deferred {
|
|
|
5815
6407
|
});
|
|
5816
6408
|
}
|
|
5817
6409
|
}
|
|
6410
|
+
|
|
6411
|
+
// Copied from react-dom types
|
|
6412
|
+
|
|
5818
6413
|
/**
|
|
5819
6414
|
* Given a Remix Router instance, render the appropriate UI
|
|
5820
6415
|
*/
|
|
@@ -5835,8 +6430,8 @@ function RouterProvider(_ref) {
|
|
|
5835
6430
|
let setState = React.useCallback((newState, _ref2) => {
|
|
5836
6431
|
let {
|
|
5837
6432
|
deletedFetchers,
|
|
5838
|
-
flushSync
|
|
5839
|
-
viewTransitionOpts
|
|
6433
|
+
flushSync,
|
|
6434
|
+
viewTransitionOpts
|
|
5840
6435
|
} = _ref2;
|
|
5841
6436
|
deletedFetchers.forEach(key => fetcherData.current.delete(key));
|
|
5842
6437
|
newState.fetchers.forEach((fetcher, key) => {
|
|
@@ -5847,6 +6442,7 @@ function RouterProvider(_ref) {
|
|
|
5847
6442
|
warnOnce(flushSync === false || reactDomFlushSyncImpl != null, "You provided the `flushSync` option to a router update, " + "but you are not using the `<RouterProvider>` from `react-router/dom` " + "so `ReactDOM.flushSync()` is unavailable. Please update your app " + 'to `import { RouterProvider } from "react-router/dom"` and ensure ' + "you have `react-dom` installed as a dependency to use the " + "`flushSync` option.");
|
|
5848
6443
|
let isViewTransitionAvailable = router.window != null && router.window.document != null && typeof router.window.document.startViewTransition === "function";
|
|
5849
6444
|
warnOnce(viewTransitionOpts == null || isViewTransitionAvailable, "You provided the `viewTransition` option to a router update, " + "but you do not appear to be running in a DOM environment as " + "`window.startViewTransition` is not available.");
|
|
6445
|
+
|
|
5850
6446
|
// If this isn't a view transition or it's not available in this browser,
|
|
5851
6447
|
// just update and be done with it
|
|
5852
6448
|
if (!viewTransitionOpts || !isViewTransitionAvailable) {
|
|
@@ -5857,6 +6453,7 @@ function RouterProvider(_ref) {
|
|
|
5857
6453
|
}
|
|
5858
6454
|
return;
|
|
5859
6455
|
}
|
|
6456
|
+
|
|
5860
6457
|
// flushSync + startViewTransition
|
|
5861
6458
|
if (reactDomFlushSyncImpl && flushSync) {
|
|
5862
6459
|
// Flush through the context to mark DOM elements as transition=ing
|
|
@@ -5873,10 +6470,12 @@ function RouterProvider(_ref) {
|
|
|
5873
6470
|
nextLocation: viewTransitionOpts.nextLocation
|
|
5874
6471
|
});
|
|
5875
6472
|
});
|
|
6473
|
+
|
|
5876
6474
|
// Update the DOM
|
|
5877
6475
|
let t = router.window.document.startViewTransition(() => {
|
|
5878
6476
|
reactDomFlushSyncImpl(() => setStateImpl(newState));
|
|
5879
6477
|
});
|
|
6478
|
+
|
|
5880
6479
|
// Clean up after the animation completes
|
|
5881
6480
|
t.finished.finally(() => {
|
|
5882
6481
|
reactDomFlushSyncImpl(() => {
|
|
@@ -5891,6 +6490,7 @@ function RouterProvider(_ref) {
|
|
|
5891
6490
|
reactDomFlushSyncImpl(() => setTransition(t));
|
|
5892
6491
|
return;
|
|
5893
6492
|
}
|
|
6493
|
+
|
|
5894
6494
|
// startTransition + startViewTransition
|
|
5895
6495
|
if (transition) {
|
|
5896
6496
|
// Interrupting an in-progress transition, cancel and let everything flush
|
|
@@ -5913,9 +6513,11 @@ function RouterProvider(_ref) {
|
|
|
5913
6513
|
});
|
|
5914
6514
|
}
|
|
5915
6515
|
}, [router.window, reactDomFlushSyncImpl, transition, renderDfd]);
|
|
6516
|
+
|
|
5916
6517
|
// Need to use a layout effect here so we are subscribed early enough to
|
|
5917
6518
|
// pick up on any render-driven redirects/navigations (useEffect/<Navigate>)
|
|
5918
6519
|
React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);
|
|
6520
|
+
|
|
5919
6521
|
// When we start a view transition, create a Deferred we can use for the
|
|
5920
6522
|
// eventual "completed" render
|
|
5921
6523
|
React.useEffect(() => {
|
|
@@ -5923,6 +6525,7 @@ function RouterProvider(_ref) {
|
|
|
5923
6525
|
setRenderDfd(new Deferred());
|
|
5924
6526
|
}
|
|
5925
6527
|
}, [vtContext]);
|
|
6528
|
+
|
|
5926
6529
|
// Once the deferred is created, kick off startViewTransition() to update the
|
|
5927
6530
|
// DOM and then wait on the Deferred to resolve (indicating the DOM update has
|
|
5928
6531
|
// happened)
|
|
@@ -5945,6 +6548,7 @@ function RouterProvider(_ref) {
|
|
|
5945
6548
|
setTransition(transition);
|
|
5946
6549
|
}
|
|
5947
6550
|
}, [pendingState, renderDfd, router.window]);
|
|
6551
|
+
|
|
5948
6552
|
// When the new location finally renders and is committed to the DOM, this
|
|
5949
6553
|
// effect will run to resolve the transition
|
|
5950
6554
|
React.useEffect(() => {
|
|
@@ -5952,6 +6556,7 @@ function RouterProvider(_ref) {
|
|
|
5952
6556
|
renderDfd.resolve();
|
|
5953
6557
|
}
|
|
5954
6558
|
}, [renderDfd, transition, state.location, pendingState]);
|
|
6559
|
+
|
|
5955
6560
|
// If we get interrupted with a new navigation during a transition, we skip
|
|
5956
6561
|
// the active transition, let it cleanup, then kick it off again here
|
|
5957
6562
|
React.useEffect(() => {
|
|
@@ -5989,6 +6594,7 @@ function RouterProvider(_ref) {
|
|
|
5989
6594
|
static: false,
|
|
5990
6595
|
basename
|
|
5991
6596
|
}), [router, navigator, basename]);
|
|
6597
|
+
|
|
5992
6598
|
// The fragment and {null} here are important! We need them to keep React 18's
|
|
5993
6599
|
// useId happy when we are server-rendering since we may have a <script> here
|
|
5994
6600
|
// containing the hydrated server-side staticContext (from StaticRouterProvider).
|
|
@@ -6014,6 +6620,7 @@ function RouterProvider(_ref) {
|
|
|
6014
6620
|
state: state
|
|
6015
6621
|
})))))), null);
|
|
6016
6622
|
}
|
|
6623
|
+
|
|
6017
6624
|
// Memoize to avoid re-renders when updating `ViewTransitionContext`
|
|
6018
6625
|
const MemoizedDataRoutes = /*#__PURE__*/React.memo(DataRoutes$1);
|
|
6019
6626
|
function DataRoutes$1(_ref3) {
|
|
@@ -6024,6 +6631,11 @@ function DataRoutes$1(_ref3) {
|
|
|
6024
6631
|
} = _ref3;
|
|
6025
6632
|
return useRoutesImpl(routes, undefined, state);
|
|
6026
6633
|
}
|
|
6634
|
+
|
|
6635
|
+
/**
|
|
6636
|
+
* @category Types
|
|
6637
|
+
*/
|
|
6638
|
+
|
|
6027
6639
|
/**
|
|
6028
6640
|
* A `<Router>` that stores all entries in memory.
|
|
6029
6641
|
*
|
|
@@ -6061,6 +6673,11 @@ function MemoryRouter(_ref4) {
|
|
|
6061
6673
|
navigator: history
|
|
6062
6674
|
});
|
|
6063
6675
|
}
|
|
6676
|
+
|
|
6677
|
+
/**
|
|
6678
|
+
* @category Types
|
|
6679
|
+
*/
|
|
6680
|
+
|
|
6064
6681
|
/**
|
|
6065
6682
|
* A component-based version of {@link useNavigate} to use in a [`React.Component
|
|
6066
6683
|
* Class`](https://reactjs.org/docs/react-component.html) where hooks are not
|
|
@@ -6091,6 +6708,7 @@ function Navigate(_ref5) {
|
|
|
6091
6708
|
pathname: locationPathname
|
|
6092
6709
|
} = useLocation();
|
|
6093
6710
|
let navigate = useNavigate();
|
|
6711
|
+
|
|
6094
6712
|
// Resolve the path outside of the effect so that when effects run twice in
|
|
6095
6713
|
// StrictMode they navigate to the same place
|
|
6096
6714
|
let path = resolveTo(to, getResolveToMatches(matches), locationPathname, relative === "path");
|
|
@@ -6104,6 +6722,11 @@ function Navigate(_ref5) {
|
|
|
6104
6722
|
}, [navigate, jsonPath, relative, replace, state]);
|
|
6105
6723
|
return null;
|
|
6106
6724
|
}
|
|
6725
|
+
|
|
6726
|
+
/**
|
|
6727
|
+
* @category Types
|
|
6728
|
+
*/
|
|
6729
|
+
|
|
6107
6730
|
/**
|
|
6108
6731
|
Renders the matching child route of a parent route or nothing if no child route matches.
|
|
6109
6732
|
|
|
@@ -6125,6 +6748,19 @@ function Navigate(_ref5) {
|
|
|
6125
6748
|
function Outlet(props) {
|
|
6126
6749
|
return useOutlet(props.context);
|
|
6127
6750
|
}
|
|
6751
|
+
|
|
6752
|
+
/**
|
|
6753
|
+
* @category Types
|
|
6754
|
+
*/
|
|
6755
|
+
|
|
6756
|
+
/**
|
|
6757
|
+
* @category Types
|
|
6758
|
+
*/
|
|
6759
|
+
|
|
6760
|
+
/**
|
|
6761
|
+
* @category Types
|
|
6762
|
+
*/
|
|
6763
|
+
|
|
6128
6764
|
/**
|
|
6129
6765
|
* Configures an element to render when a pattern matches the current location.
|
|
6130
6766
|
* It must be rendered within a {@link Routes} element. Note that these routes
|
|
@@ -6136,6 +6772,11 @@ function Outlet(props) {
|
|
|
6136
6772
|
function Route(_props) {
|
|
6137
6773
|
process.env.NODE_ENV !== "production" ? invariant$2(false, "A <Route> is only ever to be used as the child of <Routes> element, " + "never rendered directly. Please wrap your <Route> in a <Routes>.") : invariant$2(false) ;
|
|
6138
6774
|
}
|
|
6775
|
+
|
|
6776
|
+
/**
|
|
6777
|
+
* @category Types
|
|
6778
|
+
*/
|
|
6779
|
+
|
|
6139
6780
|
/**
|
|
6140
6781
|
* Provides location context for the rest of the app.
|
|
6141
6782
|
*
|
|
@@ -6155,6 +6796,7 @@ function Router(_ref6) {
|
|
|
6155
6796
|
static: staticProp = false
|
|
6156
6797
|
} = _ref6;
|
|
6157
6798
|
!!useInRouterContext() ? process.env.NODE_ENV !== "production" ? invariant$2(false, "You cannot render a <Router> inside another <Router>." + " You should never have more than one in your app.") : invariant$2(false) : void 0;
|
|
6799
|
+
|
|
6158
6800
|
// Preserve trailing slashes on basename, so we can let the user control
|
|
6159
6801
|
// the enforcement of trailing slashes throughout the app
|
|
6160
6802
|
let basename = basenameProp.replace(/^\/*/, "/");
|
|
@@ -6201,6 +6843,11 @@ function Router(_ref6) {
|
|
|
6201
6843
|
value: locationContext
|
|
6202
6844
|
}));
|
|
6203
6845
|
}
|
|
6846
|
+
|
|
6847
|
+
/**
|
|
6848
|
+
* @category Types
|
|
6849
|
+
*/
|
|
6850
|
+
|
|
6204
6851
|
/**
|
|
6205
6852
|
Renders a branch of {@link Route | `<Routes>`} that best matches the current
|
|
6206
6853
|
location. Note that these routes do not participate in data loading, actions,
|
|
@@ -6225,6 +6872,11 @@ function Routes(_ref7) {
|
|
|
6225
6872
|
} = _ref7;
|
|
6226
6873
|
return useRoutes(createRoutesFromChildren(children), location);
|
|
6227
6874
|
}
|
|
6875
|
+
|
|
6876
|
+
/**
|
|
6877
|
+
* @category Types
|
|
6878
|
+
*/
|
|
6879
|
+
|
|
6228
6880
|
/**
|
|
6229
6881
|
Used to render promise values with automatic error handling.
|
|
6230
6882
|
|
|
@@ -6277,12 +6929,12 @@ function Await(_ref8) {
|
|
|
6277
6929
|
errorElement: errorElement
|
|
6278
6930
|
}, /*#__PURE__*/React.createElement(ResolveAwait, null, children));
|
|
6279
6931
|
}
|
|
6280
|
-
var AwaitRenderStatus
|
|
6281
|
-
(function (AwaitRenderStatus) {
|
|
6932
|
+
var AwaitRenderStatus = /*#__PURE__*/function (AwaitRenderStatus) {
|
|
6282
6933
|
AwaitRenderStatus[AwaitRenderStatus["pending"] = 0] = "pending";
|
|
6283
6934
|
AwaitRenderStatus[AwaitRenderStatus["success"] = 1] = "success";
|
|
6284
6935
|
AwaitRenderStatus[AwaitRenderStatus["error"] = 2] = "error";
|
|
6285
|
-
|
|
6936
|
+
return AwaitRenderStatus;
|
|
6937
|
+
}(AwaitRenderStatus || {});
|
|
6286
6938
|
class AwaitErrorBoundary extends React.Component {
|
|
6287
6939
|
constructor(props) {
|
|
6288
6940
|
super(props);
|
|
@@ -6361,10 +7013,12 @@ class AwaitErrorBoundary extends React.Component {
|
|
|
6361
7013
|
children: children
|
|
6362
7014
|
});
|
|
6363
7015
|
}
|
|
7016
|
+
|
|
6364
7017
|
// Throw to the suspense boundary
|
|
6365
7018
|
throw promise;
|
|
6366
7019
|
}
|
|
6367
7020
|
}
|
|
7021
|
+
|
|
6368
7022
|
/**
|
|
6369
7023
|
* @private
|
|
6370
7024
|
* Indirection to leverage useAsyncValue for a render-prop API on `<Await>`
|
|
@@ -6377,9 +7031,11 @@ function ResolveAwait(_ref9) {
|
|
|
6377
7031
|
let toRender = typeof children === "function" ? children(data) : children;
|
|
6378
7032
|
return /*#__PURE__*/React.createElement(React.Fragment, null, toRender);
|
|
6379
7033
|
}
|
|
7034
|
+
|
|
6380
7035
|
///////////////////////////////////////////////////////////////////////////////
|
|
6381
7036
|
// UTILS
|
|
6382
7037
|
///////////////////////////////////////////////////////////////////////////////
|
|
7038
|
+
|
|
6383
7039
|
/**
|
|
6384
7040
|
* Creates a route config from a React "children" object, which is usually
|
|
6385
7041
|
* either a `<Route>` element or an array of them. Used internally by
|
|
@@ -6431,6 +7087,7 @@ function createRoutesFromChildren(children, parentPath) {
|
|
|
6431
7087
|
});
|
|
6432
7088
|
return routes;
|
|
6433
7089
|
}
|
|
7090
|
+
|
|
6434
7091
|
/**
|
|
6435
7092
|
* Renders the result of `matchRoutes()` into a React element.
|
|
6436
7093
|
*
|
|
@@ -6518,6 +7175,9 @@ function getSearchParamsForLocation(locationSearch, defaultSearchParams) {
|
|
|
6518
7175
|
}
|
|
6519
7176
|
return searchParams;
|
|
6520
7177
|
}
|
|
7178
|
+
|
|
7179
|
+
// Thanks https://github.com/sindresorhus/type-fest!
|
|
7180
|
+
|
|
6521
7181
|
// One-time check for submitter support
|
|
6522
7182
|
let _formDataSupportsSubmitter = null;
|
|
6523
7183
|
function isFormDataSubmitterSupported() {
|
|
@@ -6533,6 +7193,19 @@ function isFormDataSubmitterSupported() {
|
|
|
6533
7193
|
}
|
|
6534
7194
|
return _formDataSupportsSubmitter;
|
|
6535
7195
|
}
|
|
7196
|
+
|
|
7197
|
+
/**
|
|
7198
|
+
* Submit options shared by both navigations and fetchers
|
|
7199
|
+
*/
|
|
7200
|
+
|
|
7201
|
+
/**
|
|
7202
|
+
* Submit options available to fetchers
|
|
7203
|
+
*/
|
|
7204
|
+
|
|
7205
|
+
/**
|
|
7206
|
+
* Submit options available to navigations
|
|
7207
|
+
*/
|
|
7208
|
+
|
|
6536
7209
|
const supportedFormEncTypes = new Set(["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"]);
|
|
6537
7210
|
function getFormEncType(encType) {
|
|
6538
7211
|
if (encType != null && !supportedFormEncTypes.has(encType)) {
|
|
@@ -6561,7 +7234,9 @@ function getFormSubmissionInfo(target, basename) {
|
|
|
6561
7234
|
if (form == null) {
|
|
6562
7235
|
throw new Error("Cannot submit a <button> or <input type=\"submit\"> without a <form>");
|
|
6563
7236
|
}
|
|
7237
|
+
|
|
6564
7238
|
// <button>/<input type="submit"> may override attributes of <form>
|
|
7239
|
+
|
|
6565
7240
|
// When grabbing the action from the element, it will have had the basename
|
|
6566
7241
|
// prefixed to ensure non-JS scenarios work, so strip it since we'll
|
|
6567
7242
|
// re-prefix in the router
|
|
@@ -6569,8 +7244,10 @@ function getFormSubmissionInfo(target, basename) {
|
|
|
6569
7244
|
action = attr ? stripBasename(attr, basename) : null;
|
|
6570
7245
|
method = target.getAttribute("formmethod") || form.getAttribute("method") || defaultMethod;
|
|
6571
7246
|
encType = getFormEncType(target.getAttribute("formenctype")) || getFormEncType(form.getAttribute("enctype")) || defaultEncType;
|
|
7247
|
+
|
|
6572
7248
|
// Build a FormData object populated from a form and submitter
|
|
6573
7249
|
formData = new FormData(form, target);
|
|
7250
|
+
|
|
6574
7251
|
// If this browser doesn't support the `FormData(el, submitter)` format,
|
|
6575
7252
|
// then tack on the submitter value at the end. This is a lightweight
|
|
6576
7253
|
// solution that is not 100% spec compliant. For complete support in older
|
|
@@ -6597,6 +7274,7 @@ function getFormSubmissionInfo(target, basename) {
|
|
|
6597
7274
|
encType = defaultEncType;
|
|
6598
7275
|
body = target;
|
|
6599
7276
|
}
|
|
7277
|
+
|
|
6600
7278
|
// Send body for <Form encType="text/plain" so we encode it into text
|
|
6601
7279
|
if (formData && encType === "text/plain") {
|
|
6602
7280
|
body = formData;
|
|
@@ -6617,6 +7295,105 @@ function invariant$1(value, message) {
|
|
|
6617
7295
|
}
|
|
6618
7296
|
}
|
|
6619
7297
|
|
|
7298
|
+
/**
|
|
7299
|
+
* A function that handles data mutations for a route on the client
|
|
7300
|
+
*/
|
|
7301
|
+
|
|
7302
|
+
/**
|
|
7303
|
+
* Arguments passed to a route `clientAction` function
|
|
7304
|
+
*/
|
|
7305
|
+
|
|
7306
|
+
/**
|
|
7307
|
+
* A function that loads data for a route on the client
|
|
7308
|
+
*/
|
|
7309
|
+
|
|
7310
|
+
/**
|
|
7311
|
+
* Arguments passed to a route `clientLoader` function
|
|
7312
|
+
*/
|
|
7313
|
+
|
|
7314
|
+
/**
|
|
7315
|
+
* ErrorBoundary to display for this route
|
|
7316
|
+
*/
|
|
7317
|
+
|
|
7318
|
+
/**
|
|
7319
|
+
* `<Route HydrateFallback>` component to render on initial loads
|
|
7320
|
+
* when client loaders are present
|
|
7321
|
+
*/
|
|
7322
|
+
|
|
7323
|
+
/**
|
|
7324
|
+
* Optional, root-only `<Route Layout>` component to wrap the root content in.
|
|
7325
|
+
* Useful for defining the <html>/<head>/<body> document shell shared by the
|
|
7326
|
+
* Component, HydrateFallback, and ErrorBoundary
|
|
7327
|
+
*/
|
|
7328
|
+
|
|
7329
|
+
/**
|
|
7330
|
+
* A function that defines `<link>` tags to be inserted into the `<head>` of
|
|
7331
|
+
* the document on route transitions.
|
|
7332
|
+
*
|
|
7333
|
+
* @see https://remix.run/route/meta
|
|
7334
|
+
*/
|
|
7335
|
+
|
|
7336
|
+
/**
|
|
7337
|
+
* A function that returns an array of data objects to use for rendering
|
|
7338
|
+
* metadata HTML tags in a route. These tags are not rendered on descendant
|
|
7339
|
+
* routes in the route hierarchy. In other words, they will only be rendered on
|
|
7340
|
+
* the route in which they are exported.
|
|
7341
|
+
*
|
|
7342
|
+
* @param Loader - The type of the current route's loader function
|
|
7343
|
+
* @param MatchLoaders - Mapping from a parent route's filepath to its loader
|
|
7344
|
+
* function type
|
|
7345
|
+
*
|
|
7346
|
+
* Note that parent route filepaths are relative to the `app/` directory.
|
|
7347
|
+
*
|
|
7348
|
+
* For example, if this meta function is for `/sales/customers/$customerId`:
|
|
7349
|
+
*
|
|
7350
|
+
* ```ts
|
|
7351
|
+
* // app/root.tsx
|
|
7352
|
+
* const loader = () => ({ hello: "world" })
|
|
7353
|
+
* export type Loader = typeof loader
|
|
7354
|
+
*
|
|
7355
|
+
* // app/routes/sales.tsx
|
|
7356
|
+
* const loader = () => ({ salesCount: 1074 })
|
|
7357
|
+
* export type Loader = typeof loader
|
|
7358
|
+
*
|
|
7359
|
+
* // app/routes/sales/customers.tsx
|
|
7360
|
+
* const loader = () => ({ customerCount: 74 })
|
|
7361
|
+
* export type Loader = typeof loader
|
|
7362
|
+
*
|
|
7363
|
+
* // app/routes/sales/customers/$customersId.tsx
|
|
7364
|
+
* import type { Loader as RootLoader } from "../../../root"
|
|
7365
|
+
* import type { Loader as SalesLoader } from "../../sales"
|
|
7366
|
+
* import type { Loader as CustomersLoader } from "../../sales/customers"
|
|
7367
|
+
*
|
|
7368
|
+
* const loader = () => ({ name: "Customer name" })
|
|
7369
|
+
*
|
|
7370
|
+
* const meta: MetaFunction<typeof loader, {
|
|
7371
|
+
* "root": RootLoader,
|
|
7372
|
+
* "routes/sales": SalesLoader,
|
|
7373
|
+
* "routes/sales/customers": CustomersLoader,
|
|
7374
|
+
* }> = ({ data, matches }) => {
|
|
7375
|
+
* const { name } = data
|
|
7376
|
+
* // ^? string
|
|
7377
|
+
* const { customerCount } = matches.find((match) => match.id === "routes/sales/customers").data
|
|
7378
|
+
* // ^? number
|
|
7379
|
+
* const { salesCount } = matches.find((match) => match.id === "routes/sales").data
|
|
7380
|
+
* // ^? number
|
|
7381
|
+
* const { hello } = matches.find((match) => match.id === "root").data
|
|
7382
|
+
* // ^? "world"
|
|
7383
|
+
* }
|
|
7384
|
+
* ```
|
|
7385
|
+
*/
|
|
7386
|
+
|
|
7387
|
+
/**
|
|
7388
|
+
* A React component that is rendered for a route.
|
|
7389
|
+
*/
|
|
7390
|
+
|
|
7391
|
+
/**
|
|
7392
|
+
* An arbitrary object that is associated with a route.
|
|
7393
|
+
*
|
|
7394
|
+
* @see https://remix.run/route/handle
|
|
7395
|
+
*/
|
|
7396
|
+
|
|
6620
7397
|
async function loadRouteModule(route, routeModulesCache) {
|
|
6621
7398
|
if (route.id in routeModulesCache) {
|
|
6622
7399
|
return routeModulesCache[route.id];
|
|
@@ -6634,6 +7411,7 @@ async function loadRouteModule(route, routeModulesCache) {
|
|
|
6634
7411
|
// - Or, the asset trying to be imported has an error (usually in vite dev
|
|
6635
7412
|
// mode), so the best we can do here is log the error for visibility
|
|
6636
7413
|
// (via `Preserve log`) and reload
|
|
7414
|
+
|
|
6637
7415
|
// Log the error so it can be accessed via the `Preserve Log` setting
|
|
6638
7416
|
console.error("Error loading route module `" + route.module + "`, reloading page...");
|
|
6639
7417
|
console.error(error);
|
|
@@ -6661,7 +7439,7 @@ function getKeyedLinksForMatches(matches, routeModules, manifest) {
|
|
|
6661
7439
|
let descriptors = matches.map(match => {
|
|
6662
7440
|
let module = routeModules[match.route.id];
|
|
6663
7441
|
let route = manifest.routes[match.route.id];
|
|
6664
|
-
return [route.css ? route.css.map(href => ({
|
|
7442
|
+
return [route && route.css ? route.css.map(href => ({
|
|
6665
7443
|
rel: "stylesheet",
|
|
6666
7444
|
href
|
|
6667
7445
|
})) : [], (module == null || module.links == null ? void 0 : module.links()) || []];
|
|
@@ -6691,6 +7469,7 @@ async function prefetchStyleLinks(route, routeModule) {
|
|
|
6691
7469
|
}));
|
|
6692
7470
|
}
|
|
6693
7471
|
}
|
|
7472
|
+
|
|
6694
7473
|
// don't block for non-matching media queries, or for stylesheets that are
|
|
6695
7474
|
// already in the DOM (active route revalidations)
|
|
6696
7475
|
let matchingLinks = styleLinks.filter(link => (!link.media || window.matchMedia(link.media).matches) && !document.querySelector("link[rel=\"stylesheet\"][href=\"" + link.href + "\"]"));
|
|
@@ -6719,6 +7498,7 @@ async function prefetchStyleLink(descriptor) {
|
|
|
6719
7498
|
document.head.appendChild(link);
|
|
6720
7499
|
});
|
|
6721
7500
|
}
|
|
7501
|
+
|
|
6722
7502
|
////////////////////////////////////////////////////////////////////////////////
|
|
6723
7503
|
function isPageLinkDescriptor(object) {
|
|
6724
7504
|
return object != null && typeof object.page === "string";
|
|
@@ -6727,6 +7507,7 @@ function isHtmlLinkDescriptor(object) {
|
|
|
6727
7507
|
if (object == null) {
|
|
6728
7508
|
return false;
|
|
6729
7509
|
}
|
|
7510
|
+
|
|
6730
7511
|
// <link> may not have an href if <link rel="preload"> is used with imageSrcSet + imageSizes
|
|
6731
7512
|
// https://github.com/remix-run/remix/issues/184
|
|
6732
7513
|
// https://html.spec.whatwg.org/commit-snapshots/cb4f5ff75de5f4cbd7013c4abad02f21c77d4d1c/#attr-link-imagesrcset
|
|
@@ -6737,8 +7518,12 @@ function isHtmlLinkDescriptor(object) {
|
|
|
6737
7518
|
}
|
|
6738
7519
|
async function getKeyedPrefetchLinks(matches, manifest, routeModules) {
|
|
6739
7520
|
let links = await Promise.all(matches.map(async match => {
|
|
6740
|
-
let
|
|
6741
|
-
|
|
7521
|
+
let route = manifest.routes[match.route.id];
|
|
7522
|
+
if (route) {
|
|
7523
|
+
let mod = await loadRouteModule(route, routeModules);
|
|
7524
|
+
return mod.links ? mod.links() : [];
|
|
7525
|
+
}
|
|
7526
|
+
return [];
|
|
6742
7527
|
}));
|
|
6743
7528
|
return dedupeLinkDescriptors(links.flat(1).filter(isHtmlLinkDescriptor).filter(link => link.rel === "stylesheet" || link.rel === "preload").map(link => link.rel === "stylesheet" ? _extends({}, link, {
|
|
6744
7529
|
rel: "prefetch",
|
|
@@ -6747,9 +7532,9 @@ async function getKeyedPrefetchLinks(matches, manifest, routeModules) {
|
|
|
6747
7532
|
rel: "prefetch"
|
|
6748
7533
|
})));
|
|
6749
7534
|
}
|
|
7535
|
+
|
|
6750
7536
|
// This is ridiculously identical to transition.ts `filterMatchesToLoad`
|
|
6751
7537
|
function getNewMatchesForLinks(page, nextMatches, currentMatches, manifest, location, mode) {
|
|
6752
|
-
let path = parsePathPatch(page);
|
|
6753
7538
|
let isNew = (match, index) => {
|
|
6754
7539
|
if (!currentMatches[index]) return true;
|
|
6755
7540
|
return match.route.id !== currentMatches[index].route.id;
|
|
@@ -6764,42 +7549,45 @@ function getNewMatchesForLinks(page, nextMatches, currentMatches, manifest, loca
|
|
|
6764
7549
|
((_currentMatches$index = currentMatches[index].route.path) == null ? void 0 : _currentMatches$index.endsWith("*")) && currentMatches[index].params["*"] !== match.params["*"]
|
|
6765
7550
|
);
|
|
6766
7551
|
};
|
|
6767
|
-
|
|
7552
|
+
if (mode === "assets") {
|
|
7553
|
+
return nextMatches.filter((match, index) => isNew(match, index) || matchPathChanged(match, index));
|
|
7554
|
+
}
|
|
7555
|
+
|
|
7556
|
+
// NOTE: keep this mostly up-to-date w/ the router data diff, but this
|
|
6768
7557
|
// version doesn't care about submissions
|
|
6769
|
-
|
|
6770
|
-
// this is really similar to stuff in transition.ts, maybe somebody smarter
|
|
7558
|
+
// TODO: this is really similar to stuff in router.ts, maybe somebody smarter
|
|
6771
7559
|
// than me (or in less of a hurry) can share some of it. You're the best.
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
if (isNew(match, index) || matchPathChanged(match, index)) {
|
|
6778
|
-
return true;
|
|
6779
|
-
}
|
|
6780
|
-
if (match.route.shouldRevalidate) {
|
|
6781
|
-
var _currentMatches$;
|
|
6782
|
-
let routeChoice = match.route.shouldRevalidate({
|
|
6783
|
-
currentUrl: new URL(location.pathname + location.search + location.hash, window.origin),
|
|
6784
|
-
currentParams: ((_currentMatches$ = currentMatches[0]) == null ? void 0 : _currentMatches$.params) || {},
|
|
6785
|
-
nextUrl: new URL(page, window.origin),
|
|
6786
|
-
nextParams: match.params,
|
|
6787
|
-
defaultShouldRevalidate: true
|
|
6788
|
-
});
|
|
6789
|
-
if (typeof routeChoice === "boolean") {
|
|
6790
|
-
return routeChoice;
|
|
7560
|
+
if (mode === "data") {
|
|
7561
|
+
return nextMatches.filter((match, index) => {
|
|
7562
|
+
let manifestRoute = manifest.routes[match.route.id];
|
|
7563
|
+
if (!manifestRoute || !manifestRoute.hasLoader) {
|
|
7564
|
+
return false;
|
|
6791
7565
|
}
|
|
6792
|
-
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
|
|
7566
|
+
if (isNew(match, index) || matchPathChanged(match, index)) {
|
|
7567
|
+
return true;
|
|
7568
|
+
}
|
|
7569
|
+
if (match.route.shouldRevalidate) {
|
|
7570
|
+
var _currentMatches$;
|
|
7571
|
+
let routeChoice = match.route.shouldRevalidate({
|
|
7572
|
+
currentUrl: new URL(location.pathname + location.search + location.hash, window.origin),
|
|
7573
|
+
currentParams: ((_currentMatches$ = currentMatches[0]) == null ? void 0 : _currentMatches$.params) || {},
|
|
7574
|
+
nextUrl: new URL(page, window.origin),
|
|
7575
|
+
nextParams: match.params,
|
|
7576
|
+
defaultShouldRevalidate: true
|
|
7577
|
+
});
|
|
7578
|
+
if (typeof routeChoice === "boolean") {
|
|
7579
|
+
return routeChoice;
|
|
7580
|
+
}
|
|
7581
|
+
}
|
|
7582
|
+
return true;
|
|
7583
|
+
});
|
|
7584
|
+
}
|
|
7585
|
+
return [];
|
|
6799
7586
|
}
|
|
6800
7587
|
function getModuleLinkHrefs(matches, manifestPatch) {
|
|
6801
7588
|
return dedupeHrefs(matches.map(match => {
|
|
6802
7589
|
let route = manifestPatch.routes[match.route.id];
|
|
7590
|
+
if (!route) return [];
|
|
6803
7591
|
let hrefs = [route.module];
|
|
6804
7592
|
if (route.imports) {
|
|
6805
7593
|
hrefs = hrefs.concat(route.imports);
|
|
@@ -6807,12 +7595,14 @@ function getModuleLinkHrefs(matches, manifestPatch) {
|
|
|
6807
7595
|
return hrefs;
|
|
6808
7596
|
}).flat(1));
|
|
6809
7597
|
}
|
|
7598
|
+
|
|
6810
7599
|
// The `<Script>` will render rel=modulepreload for the current page, we don't
|
|
6811
7600
|
// need to include them in a page prefetch, this gives us the list to remove
|
|
6812
7601
|
// while deduping.
|
|
6813
7602
|
function getCurrentPageModulePreloadHrefs(matches, manifest) {
|
|
6814
7603
|
return dedupeHrefs(matches.map(match => {
|
|
6815
7604
|
let route = manifest.routes[match.route.id];
|
|
7605
|
+
if (!route) return [];
|
|
6816
7606
|
let hrefs = [route.module];
|
|
6817
7607
|
if (route.imports) {
|
|
6818
7608
|
hrefs = hrefs.concat(route.imports);
|
|
@@ -6850,12 +7640,7 @@ function dedupeLinkDescriptors(descriptors, preloads) {
|
|
|
6850
7640
|
return deduped;
|
|
6851
7641
|
}, []);
|
|
6852
7642
|
}
|
|
6853
|
-
|
|
6854
|
-
function parsePathPatch(href) {
|
|
6855
|
-
let path = parsePath(href);
|
|
6856
|
-
if (path.search === undefined) path.search = "";
|
|
6857
|
-
return path;
|
|
6858
|
-
}
|
|
7643
|
+
|
|
6859
7644
|
// Detect if this browser supports <link rel="preload"> (or has it enabled).
|
|
6860
7645
|
// Originally added to handle the firefox `network.preload` config:
|
|
6861
7646
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1847811
|
|
@@ -6872,8 +7657,10 @@ function isPreloadSupported() {
|
|
|
6872
7657
|
|
|
6873
7658
|
// This escapeHtml utility is based on https://github.com/zertosh/htmlescape
|
|
6874
7659
|
// License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE
|
|
7660
|
+
|
|
6875
7661
|
// We've chosen to inline the utility here to reduce the number of npm dependencies we have,
|
|
6876
7662
|
// slightly decrease the code size compared the original package and make it esm compatible.
|
|
7663
|
+
|
|
6877
7664
|
const ESCAPE_LOOKUP$2 = {
|
|
6878
7665
|
"&": "\\u0026",
|
|
6879
7666
|
">": "\\u003e",
|
|
@@ -6891,9 +7678,6 @@ function createHtml(html) {
|
|
|
6891
7678
|
};
|
|
6892
7679
|
}
|
|
6893
7680
|
|
|
6894
|
-
function isResponse$1(value) {
|
|
6895
|
-
return value != null && typeof value.status === "number" && typeof value.statusText === "string" && typeof value.headers === "object" && typeof value.body !== "undefined";
|
|
6896
|
-
}
|
|
6897
7681
|
async function createRequestInit(request) {
|
|
6898
7682
|
let init = {
|
|
6899
7683
|
signal: request.signal
|
|
@@ -6901,6 +7685,7 @@ async function createRequestInit(request) {
|
|
|
6901
7685
|
if (request.method !== "GET") {
|
|
6902
7686
|
init.method = request.method;
|
|
6903
7687
|
let contentType = request.headers.get("Content-Type");
|
|
7688
|
+
|
|
6904
7689
|
// Check between word boundaries instead of startsWith() due to the last
|
|
6905
7690
|
// paragraph of https://httpwg.org/specs/rfc9110.html#field.content-type
|
|
6906
7691
|
if (contentType && /\bapplication\/json\b/.test(contentType)) {
|
|
@@ -6967,12 +7752,12 @@ function StreamTransfer(_ref) {
|
|
|
6967
7752
|
done,
|
|
6968
7753
|
value
|
|
6969
7754
|
} = promise.result;
|
|
6970
|
-
let scriptTag = value ?
|
|
7755
|
+
let scriptTag = value ? /*#__PURE__*/React.createElement("script", {
|
|
6971
7756
|
nonce: nonce,
|
|
6972
7757
|
dangerouslySetInnerHTML: {
|
|
6973
7758
|
__html: "window.__reactRouterContext.streamController.enqueue(" + escapeHtml$1(JSON.stringify(value)) + ");"
|
|
6974
7759
|
}
|
|
6975
|
-
})
|
|
7760
|
+
}) : null;
|
|
6976
7761
|
if (done) {
|
|
6977
7762
|
return /*#__PURE__*/React.createElement(React.Fragment, null, scriptTag, /*#__PURE__*/React.createElement("script", {
|
|
6978
7763
|
nonce: nonce,
|
|
@@ -7001,14 +7786,17 @@ function getSingleFetchDataStrategy$1(manifest, routeModules, getRouter) {
|
|
|
7001
7786
|
if (request.method !== "GET") {
|
|
7002
7787
|
return singleFetchActionStrategy(request, matches);
|
|
7003
7788
|
}
|
|
7789
|
+
|
|
7004
7790
|
// Fetcher loads are singular calls to one loader
|
|
7005
7791
|
if (fetcherKey) {
|
|
7006
7792
|
return singleFetchLoaderFetcherStrategy(request, matches);
|
|
7007
7793
|
}
|
|
7794
|
+
|
|
7008
7795
|
// Navigational loads are more complex...
|
|
7009
7796
|
return singleFetchLoaderNavigationStrategy(manifest, routeModules, getRouter(), request, matches);
|
|
7010
7797
|
};
|
|
7011
7798
|
}
|
|
7799
|
+
|
|
7012
7800
|
// Actions are simple since they're singular calls to the server for both
|
|
7013
7801
|
// navigations and fetchers)
|
|
7014
7802
|
async function singleFetchActionStrategy(request, matches) {
|
|
@@ -7028,11 +7816,12 @@ async function singleFetchActionStrategy(request, matches) {
|
|
|
7028
7816
|
});
|
|
7029
7817
|
return result;
|
|
7030
7818
|
});
|
|
7031
|
-
if (isResponse
|
|
7819
|
+
if (isResponse(result.result) || isRouteErrorResponse(result.result)) {
|
|
7032
7820
|
return {
|
|
7033
7821
|
[actionMatch.route.id]: result
|
|
7034
7822
|
};
|
|
7035
7823
|
}
|
|
7824
|
+
|
|
7036
7825
|
// For non-responses, proxy along the statusCode via data()
|
|
7037
7826
|
// (most notably for skipping action error revalidation)
|
|
7038
7827
|
return {
|
|
@@ -7042,30 +7831,37 @@ async function singleFetchActionStrategy(request, matches) {
|
|
|
7042
7831
|
}
|
|
7043
7832
|
};
|
|
7044
7833
|
}
|
|
7834
|
+
|
|
7045
7835
|
// Loaders are trickier since we only want to hit the server once, so we
|
|
7046
7836
|
// create a singular promise for all server-loader routes to latch onto.
|
|
7047
7837
|
async function singleFetchLoaderNavigationStrategy(manifest, routeModules, router, request, matches) {
|
|
7048
7838
|
// Track which routes need a server load - in case we need to tack on a
|
|
7049
7839
|
// `_routes` param
|
|
7050
7840
|
let routesParams = new Set();
|
|
7841
|
+
|
|
7051
7842
|
// We only add `_routes` when one or more routes opts out of a load via
|
|
7052
7843
|
// `shouldRevalidate` or `clientLoader`
|
|
7053
7844
|
let foundOptOutRoute = false;
|
|
7845
|
+
|
|
7054
7846
|
// Deferreds for each route so we can be sure they've all loaded via
|
|
7055
7847
|
// `match.resolve()`, and a singular promise that can tell us all routes
|
|
7056
7848
|
// have been resolved
|
|
7057
7849
|
let routeDfds = matches.map(() => createDeferred());
|
|
7058
7850
|
let routesLoadedPromise = Promise.all(routeDfds.map(d => d.promise));
|
|
7851
|
+
|
|
7059
7852
|
// Deferred that we'll use for the call to the server that each match can
|
|
7060
7853
|
// await and parse out it's specific result
|
|
7061
7854
|
let singleFetchDfd = createDeferred();
|
|
7855
|
+
|
|
7062
7856
|
// Base URL and RequestInit for calls to the server
|
|
7063
7857
|
let url = stripIndexParam$1(singleFetchUrl(request.url));
|
|
7064
7858
|
let init = await createRequestInit(request);
|
|
7859
|
+
|
|
7065
7860
|
// We'll build up this results object as we loop through matches
|
|
7066
7861
|
let results = {};
|
|
7067
7862
|
let resolvePromise = Promise.all(matches.map(async (m, i) => m.resolve(async handler => {
|
|
7068
7863
|
routeDfds[i].resolve();
|
|
7864
|
+
let manifestRoute = manifest.routes[m.route.id];
|
|
7069
7865
|
if (!m.shouldLoad) {
|
|
7070
7866
|
var _routeModules$m$route;
|
|
7071
7867
|
// If we're not yet initialized and this is the initial load, respect
|
|
@@ -7074,18 +7870,20 @@ async function singleFetchLoaderNavigationStrategy(manifest, routeModules, route
|
|
|
7074
7870
|
if (!router.state.initialized) {
|
|
7075
7871
|
return;
|
|
7076
7872
|
}
|
|
7873
|
+
|
|
7077
7874
|
// Otherwise, we opt out if we currently have data, a `loader`, and a
|
|
7078
7875
|
// `shouldRevalidate` function. This implies that the user opted out
|
|
7079
7876
|
// via `shouldRevalidate`
|
|
7080
|
-
if (m.route.id in router.state.loaderData &&
|
|
7877
|
+
if (m.route.id in router.state.loaderData && manifestRoute && manifestRoute.hasLoader && (_routeModules$m$route = routeModules[m.route.id]) != null && _routeModules$m$route.shouldRevalidate) {
|
|
7081
7878
|
foundOptOutRoute = true;
|
|
7082
7879
|
return;
|
|
7083
7880
|
}
|
|
7084
7881
|
}
|
|
7882
|
+
|
|
7085
7883
|
// When a route has a client loader, it opts out of the singular call and
|
|
7086
7884
|
// calls it's server loader via `serverLoader()` using a `?_routes` param
|
|
7087
|
-
if (
|
|
7088
|
-
if (
|
|
7885
|
+
if (manifestRoute && manifestRoute.hasClientLoader) {
|
|
7886
|
+
if (manifestRoute.hasLoader) {
|
|
7089
7887
|
foundOptOutRoute = true;
|
|
7090
7888
|
}
|
|
7091
7889
|
try {
|
|
@@ -7102,10 +7900,12 @@ async function singleFetchLoaderNavigationStrategy(manifest, routeModules, route
|
|
|
7102
7900
|
}
|
|
7103
7901
|
return;
|
|
7104
7902
|
}
|
|
7903
|
+
|
|
7105
7904
|
// Load this route on the server if it has a loader
|
|
7106
|
-
if (
|
|
7905
|
+
if (manifestRoute && manifestRoute.hasLoader) {
|
|
7107
7906
|
routesParams.add(m.route.id);
|
|
7108
7907
|
}
|
|
7908
|
+
|
|
7109
7909
|
// Lump this match in with the others on a singular promise
|
|
7110
7910
|
try {
|
|
7111
7911
|
let result = await handler(async () => {
|
|
@@ -7123,8 +7923,10 @@ async function singleFetchLoaderNavigationStrategy(manifest, routeModules, route
|
|
|
7123
7923
|
};
|
|
7124
7924
|
}
|
|
7125
7925
|
})));
|
|
7926
|
+
|
|
7126
7927
|
// Wait for all routes to resolve above before we make the HTTP call
|
|
7127
7928
|
await routesLoadedPromise;
|
|
7929
|
+
|
|
7128
7930
|
// We can skip the server call:
|
|
7129
7931
|
// - On initial hydration - only clientLoaders can pass through via `clientLoader.hydrate`
|
|
7130
7932
|
// - If there are no routes to fetch from the server
|
|
@@ -7151,6 +7953,7 @@ async function singleFetchLoaderNavigationStrategy(manifest, routeModules, route
|
|
|
7151
7953
|
await resolvePromise;
|
|
7152
7954
|
return results;
|
|
7153
7955
|
}
|
|
7956
|
+
|
|
7154
7957
|
// Fetcher loader calls are much simpler than navigational loader calls
|
|
7155
7958
|
async function singleFetchLoaderFetcherStrategy(request, matches) {
|
|
7156
7959
|
let fetcherMatch = matches.find(m => m.shouldLoad);
|
|
@@ -7202,6 +8005,7 @@ function singleFetchUrl(reqUrl) {
|
|
|
7202
8005
|
}
|
|
7203
8006
|
async function fetchAndDecode(url, init) {
|
|
7204
8007
|
let res = await fetch(url, init);
|
|
8008
|
+
|
|
7205
8009
|
// If this 404'd without hitting the running server (most likely in a
|
|
7206
8010
|
// pre-rendered app using a CDN), then bubble a standard 404 ErrorResponse
|
|
7207
8011
|
if (res.status === 404 && !res.headers.has("X-Remix-Response")) {
|
|
@@ -7224,6 +8028,7 @@ async function fetchAndDecode(url, init) {
|
|
|
7224
8028
|
throw new Error("Unable to decode turbo-stream response");
|
|
7225
8029
|
}
|
|
7226
8030
|
}
|
|
8031
|
+
|
|
7227
8032
|
// Note: If you change this function please change the corresponding
|
|
7228
8033
|
// encodeViaTurboStream function in server-runtime
|
|
7229
8034
|
function decodeViaTurboStream(body, global) {
|
|
@@ -7360,6 +8165,7 @@ class RemixErrorBoundary extends React.Component {
|
|
|
7360
8165
|
location: props.location
|
|
7361
8166
|
};
|
|
7362
8167
|
}
|
|
8168
|
+
|
|
7363
8169
|
// If we're not changing locations, preserve the location but still surface
|
|
7364
8170
|
// any new errors that may come through. We retain the existing error, we do
|
|
7365
8171
|
// this because the error provided from the app state may be cleared without
|
|
@@ -7380,6 +8186,7 @@ class RemixErrorBoundary extends React.Component {
|
|
|
7380
8186
|
}
|
|
7381
8187
|
}
|
|
7382
8188
|
}
|
|
8189
|
+
|
|
7383
8190
|
/**
|
|
7384
8191
|
* When app's don't provide a root level ErrorBoundary, we default to this.
|
|
7385
8192
|
*/
|
|
@@ -7437,16 +8244,19 @@ function BoundaryShell(_ref2) {
|
|
|
7437
8244
|
let {
|
|
7438
8245
|
routeModules
|
|
7439
8246
|
} = useFrameworkContext();
|
|
8247
|
+
|
|
7440
8248
|
// Generally speaking, when the root route has a Layout we want to use that
|
|
7441
8249
|
// as the app shell instead of the default `BoundaryShell` wrapper markup below.
|
|
7442
8250
|
// This is true for `loader`/`action` errors, most render errors, and
|
|
7443
8251
|
// `HydrateFallback` scenarios.
|
|
8252
|
+
|
|
7444
8253
|
// However, render errors thrown from the `Layout` present a bit of an issue
|
|
7445
8254
|
// because if the `Layout` itself throws during the `ErrorBoundary` pass and
|
|
7446
8255
|
// we bubble outside the `RouterProvider` to the wrapping `RemixErrorBoundary`,
|
|
7447
8256
|
// by returning only `children` here we'll be trying to append a `<div>` to
|
|
7448
8257
|
// the `document` and the DOM will throw, putting React into an error/hydration
|
|
7449
8258
|
// loop.
|
|
8259
|
+
|
|
7450
8260
|
// Instead, if we're ever rendering from the outermost `RemixErrorBoundary`
|
|
7451
8261
|
// during hydration that wraps `RouterProvider`, then we can't trust the
|
|
7452
8262
|
// `Layout` and should fallback to the default app shell so we're always
|
|
@@ -7489,11 +8299,13 @@ function RemixRootDefaultHydrateFallback() {
|
|
|
7489
8299
|
function groupRoutesByParentId$1(manifest) {
|
|
7490
8300
|
let routes = {};
|
|
7491
8301
|
Object.values(manifest).forEach(route => {
|
|
7492
|
-
|
|
7493
|
-
|
|
7494
|
-
routes[parentId]
|
|
8302
|
+
if (route) {
|
|
8303
|
+
let parentId = route.parentId || "";
|
|
8304
|
+
if (!routes[parentId]) {
|
|
8305
|
+
routes[parentId] = [];
|
|
8306
|
+
}
|
|
8307
|
+
routes[parentId].push(route);
|
|
7495
8308
|
}
|
|
7496
|
-
routes[parentId].push(route);
|
|
7497
8309
|
});
|
|
7498
8310
|
return routes;
|
|
7499
8311
|
}
|
|
@@ -7506,15 +8318,15 @@ function getRouteComponents(route, routeModule, isSpaMode) {
|
|
|
7506
8318
|
}) : undefined;
|
|
7507
8319
|
if (route.id === "root" && routeModule.Layout) {
|
|
7508
8320
|
return _extends({}, Component ? {
|
|
7509
|
-
element:
|
|
8321
|
+
element: /*#__PURE__*/React.createElement(routeModule.Layout, null, /*#__PURE__*/React.createElement(Component, null))
|
|
7510
8322
|
} : {
|
|
7511
8323
|
Component
|
|
7512
8324
|
}, ErrorBoundary ? {
|
|
7513
|
-
errorElement:
|
|
8325
|
+
errorElement: /*#__PURE__*/React.createElement(routeModule.Layout, null, /*#__PURE__*/React.createElement(ErrorBoundary, null))
|
|
7514
8326
|
} : {
|
|
7515
8327
|
ErrorBoundary
|
|
7516
8328
|
}, HydrateFallback ? {
|
|
7517
|
-
hydrateFallbackElement:
|
|
8329
|
+
hydrateFallbackElement: /*#__PURE__*/React.createElement(routeModule.Layout, null, /*#__PURE__*/React.createElement(HydrateFallback, null))
|
|
7518
8330
|
} : {
|
|
7519
8331
|
HydrateFallback
|
|
7520
8332
|
});
|
|
@@ -7633,7 +8445,7 @@ function createClientRoutes(manifest, routeModulesCache, initialState, isSpaMode
|
|
|
7633
8445
|
// Use critical path modules directly
|
|
7634
8446
|
Object.assign(dataRoute, _extends({}, dataRoute, getRouteComponents(route, routeModule, isSpaMode), {
|
|
7635
8447
|
handle: routeModule.handle,
|
|
7636
|
-
shouldRevalidate:
|
|
8448
|
+
shouldRevalidate: getShouldRevalidateFunction(routeModule, route.id, needsRevalidation)
|
|
7637
8449
|
}));
|
|
7638
8450
|
let hasInitialData = initialState && initialState.loaderData && route.id in initialState.loaderData;
|
|
7639
8451
|
let initialData = hasInitialData ? initialState == null || (_initialState$loaderD = initialState.loaderData) == null ? void 0 : _initialState$loaderD[route.id] : undefined;
|
|
@@ -7658,6 +8470,7 @@ function createClientRoutes(manifest, routeModulesCache, initialState, isSpaMode
|
|
|
7658
8470
|
params,
|
|
7659
8471
|
async serverLoader() {
|
|
7660
8472
|
preventInvalidServerHandlerCall("loader", route, isSpaMode);
|
|
8473
|
+
|
|
7661
8474
|
// On the first call, resolve with the server result
|
|
7662
8475
|
if (isHydrationRequest) {
|
|
7663
8476
|
if (hasInitialData) {
|
|
@@ -7667,6 +8480,7 @@ function createClientRoutes(manifest, routeModulesCache, initialState, isSpaMode
|
|
|
7667
8480
|
throw initialError;
|
|
7668
8481
|
}
|
|
7669
8482
|
}
|
|
8483
|
+
|
|
7670
8484
|
// Call the server loader for client-side navigations
|
|
7671
8485
|
return fetchServerLoader(singleFetch);
|
|
7672
8486
|
}
|
|
@@ -7679,6 +8493,7 @@ function createClientRoutes(manifest, routeModulesCache, initialState, isSpaMode
|
|
|
7679
8493
|
isHydrationRequest = false;
|
|
7680
8494
|
}
|
|
7681
8495
|
};
|
|
8496
|
+
|
|
7682
8497
|
// Let React Router know whether to run this on hydration
|
|
7683
8498
|
dataRoute.loader.hydrate = shouldHydrateRouteLoader(route, routeModule, isSpaMode);
|
|
7684
8499
|
dataRoute.action = (_ref2, singleFetch) => {
|
|
@@ -7726,6 +8541,7 @@ function createClientRoutes(manifest, routeModulesCache, initialState, isSpaMode
|
|
|
7726
8541
|
});
|
|
7727
8542
|
};
|
|
7728
8543
|
}
|
|
8544
|
+
|
|
7729
8545
|
// Load all other modules via route.lazy()
|
|
7730
8546
|
dataRoute.lazy = async () => {
|
|
7731
8547
|
let mod = await loadRouteModuleWithBlockingLinks(route, routeModulesCache);
|
|
@@ -7748,16 +8564,13 @@ function createClientRoutes(manifest, routeModulesCache, initialState, isSpaMode
|
|
|
7748
8564
|
}
|
|
7749
8565
|
}));
|
|
7750
8566
|
}
|
|
7751
|
-
if (needsRevalidation) {
|
|
7752
|
-
lazyRoute.shouldRevalidate = wrapShouldRevalidateForHdr(route.id, mod.shouldRevalidate, needsRevalidation);
|
|
7753
|
-
}
|
|
7754
8567
|
return _extends({}, lazyRoute.loader ? {
|
|
7755
8568
|
loader: lazyRoute.loader
|
|
7756
8569
|
} : {}, lazyRoute.action ? {
|
|
7757
8570
|
action: lazyRoute.action
|
|
7758
8571
|
} : {}, {
|
|
7759
8572
|
hasErrorBoundary: lazyRoute.hasErrorBoundary,
|
|
7760
|
-
shouldRevalidate: lazyRoute.
|
|
8573
|
+
shouldRevalidate: getShouldRevalidateFunction(lazyRoute, route.id, needsRevalidation),
|
|
7761
8574
|
handle: lazyRoute.handle,
|
|
7762
8575
|
// No need to wrap these in layout since the root route is never
|
|
7763
8576
|
// loaded via route.lazy()
|
|
@@ -7771,6 +8584,23 @@ function createClientRoutes(manifest, routeModulesCache, initialState, isSpaMode
|
|
|
7771
8584
|
return dataRoute;
|
|
7772
8585
|
});
|
|
7773
8586
|
}
|
|
8587
|
+
function getShouldRevalidateFunction(route, routeId, needsRevalidation) {
|
|
8588
|
+
// During HDR we force revalidation for updated routes
|
|
8589
|
+
if (needsRevalidation) {
|
|
8590
|
+
return wrapShouldRevalidateForHdr(routeId, route.shouldRevalidate, needsRevalidation);
|
|
8591
|
+
}
|
|
8592
|
+
|
|
8593
|
+
// Single fetch revalidates by default, so override the RR default value which
|
|
8594
|
+
// matches the multi-fetch behavior with `true`
|
|
8595
|
+
if (route.shouldRevalidate) {
|
|
8596
|
+
let fn = route.shouldRevalidate;
|
|
8597
|
+
return opts => fn(_extends({}, opts, {
|
|
8598
|
+
defaultShouldRevalidate: true
|
|
8599
|
+
}));
|
|
8600
|
+
}
|
|
8601
|
+
return route.shouldRevalidate;
|
|
8602
|
+
}
|
|
8603
|
+
|
|
7774
8604
|
// When an HMR / HDR update happens we opt out of all user-defined
|
|
7775
8605
|
// revalidation logic and force a revalidation on the first call
|
|
7776
8606
|
function wrapShouldRevalidateForHdr(routeId, routeShouldRevalidate, needsRevalidation) {
|
|
@@ -7786,6 +8616,7 @@ function wrapShouldRevalidateForHdr(routeId, routeShouldRevalidate, needsRevalid
|
|
|
7786
8616
|
async function loadRouteModuleWithBlockingLinks(route, routeModules) {
|
|
7787
8617
|
let routeModule = await loadRouteModule(route, routeModules);
|
|
7788
8618
|
await prefetchStyleLinks(route, routeModule);
|
|
8619
|
+
|
|
7789
8620
|
// Include all `browserSafeRouteExports` fields, except `HydrateFallback`
|
|
7790
8621
|
// since those aren't used on lazily loaded routes
|
|
7791
8622
|
return {
|
|
@@ -7799,6 +8630,7 @@ async function loadRouteModuleWithBlockingLinks(route, routeModules) {
|
|
|
7799
8630
|
shouldRevalidate: routeModule.shouldRevalidate
|
|
7800
8631
|
};
|
|
7801
8632
|
}
|
|
8633
|
+
|
|
7802
8634
|
// Our compiler generates the default export as `{}` when no default is provided,
|
|
7803
8635
|
// which can lead us to trying to use that as a Component in RR and calling
|
|
7804
8636
|
// createElement on it. Patching here as a quick fix and hoping it's no longer
|
|
@@ -7816,10 +8648,12 @@ function shouldHydrateRouteLoader(route, routeModule, isSpaMode) {
|
|
|
7816
8648
|
|
|
7817
8649
|
// Currently rendered links that may need prefetching
|
|
7818
8650
|
const nextPaths = new Set();
|
|
8651
|
+
|
|
7819
8652
|
// FIFO queue of previously discovered routes to prevent re-calling on
|
|
7820
8653
|
// subsequent navigations to the same path
|
|
7821
8654
|
const discoveredPathsMaxSize = 1000;
|
|
7822
8655
|
const discoveredPaths = new Set();
|
|
8656
|
+
|
|
7823
8657
|
// 7.5k to come in under the ~8k limit for most browsers
|
|
7824
8658
|
// https://stackoverflow.com/a/417184
|
|
7825
8659
|
const URL_LIMIT = 7680;
|
|
@@ -7831,8 +8665,10 @@ function getPartialManifest(manifest, router) {
|
|
|
7831
8665
|
let routeIds = new Set(router.state.matches.map(m => m.route.id));
|
|
7832
8666
|
let segments = router.state.location.pathname.split("/").filter(Boolean);
|
|
7833
8667
|
let paths = ["/"];
|
|
8668
|
+
|
|
7834
8669
|
// We've already matched to the last segment
|
|
7835
8670
|
segments.pop();
|
|
8671
|
+
|
|
7836
8672
|
// Traverse each path for our parents and match in case they have pathless/index
|
|
7837
8673
|
// children we need to include in the initial manifest
|
|
7838
8674
|
while (segments.length > 0) {
|
|
@@ -7874,6 +8710,7 @@ function useFogOFWarDiscovery(router, manifest, routeModules, isSpaMode) {
|
|
|
7874
8710
|
if (!isFogOfWarEnabled(isSpaMode) || ((_navigator$connection = navigator.connection) == null ? void 0 : _navigator$connection.saveData) === true) {
|
|
7875
8711
|
return;
|
|
7876
8712
|
}
|
|
8713
|
+
|
|
7877
8714
|
// Register a link href for patching
|
|
7878
8715
|
function registerElement(el) {
|
|
7879
8716
|
let path = el.tagName === "FORM" ? el.getAttribute("action") : el.getAttribute("href");
|
|
@@ -7885,6 +8722,7 @@ function useFogOFWarDiscovery(router, manifest, routeModules, isSpaMode) {
|
|
|
7885
8722
|
nextPaths.add(url.pathname);
|
|
7886
8723
|
}
|
|
7887
8724
|
}
|
|
8725
|
+
|
|
7888
8726
|
// Register and fetch patches for all initially-rendered links/forms
|
|
7889
8727
|
async function fetchPatches() {
|
|
7890
8728
|
let lazyPaths = Array.from(nextPaths.keys()).filter(path => {
|
|
@@ -7903,9 +8741,11 @@ function useFogOFWarDiscovery(router, manifest, routeModules, isSpaMode) {
|
|
|
7903
8741
|
console.error("Failed to fetch manifest patches", e);
|
|
7904
8742
|
}
|
|
7905
8743
|
}
|
|
8744
|
+
|
|
7906
8745
|
// Register and fetch patches for all initially-rendered links
|
|
7907
8746
|
document.body.querySelectorAll("a[data-discover], form[data-discover]").forEach(el => registerElement(el));
|
|
7908
8747
|
fetchPatches();
|
|
8748
|
+
|
|
7909
8749
|
// Setup a MutationObserver to fetch all subsequently rendered links/form
|
|
7910
8750
|
let debouncedFetchPatches = debounce(fetchPatches, 100);
|
|
7911
8751
|
function isElement(node) {
|
|
@@ -7943,6 +8783,7 @@ async function fetchAndApplyManifestPatches(paths, manifest, routeModules, isSpa
|
|
|
7943
8783
|
let url = new URL(manifestPath, window.location.origin);
|
|
7944
8784
|
paths.sort().forEach(path => url.searchParams.append("p", path));
|
|
7945
8785
|
url.searchParams.set("version", manifest.version);
|
|
8786
|
+
|
|
7946
8787
|
// If the URL is nearing the ~8k limit on GET requests, skip this optimization
|
|
7947
8788
|
// step and just let discovery happen on link click. We also wipe out the
|
|
7948
8789
|
// nextPaths Set here so we can start filling it with fresh links
|
|
@@ -7957,19 +8798,25 @@ async function fetchAndApplyManifestPatches(paths, manifest, routeModules, isSpa
|
|
|
7957
8798
|
throw new Error(await res.text());
|
|
7958
8799
|
}
|
|
7959
8800
|
let serverPatches = await res.json();
|
|
8801
|
+
|
|
7960
8802
|
// Patch routes we don't know about yet into the manifest
|
|
7961
8803
|
let knownRoutes = new Set(Object.keys(manifest.routes));
|
|
7962
|
-
let patches = Object.values(serverPatches).reduce((acc, route) =>
|
|
7963
|
-
|
|
7964
|
-
|
|
8804
|
+
let patches = Object.values(serverPatches).reduce((acc, route) => {
|
|
8805
|
+
if (route && !knownRoutes.has(route.id)) {
|
|
8806
|
+
acc[route.id] = route;
|
|
8807
|
+
}
|
|
8808
|
+
return acc;
|
|
8809
|
+
}, {});
|
|
7965
8810
|
Object.assign(manifest.routes, patches);
|
|
8811
|
+
|
|
7966
8812
|
// Track discovered paths so we don't have to fetch them again
|
|
7967
8813
|
paths.forEach(p => addToFifoQueue(p, discoveredPaths));
|
|
8814
|
+
|
|
7968
8815
|
// Identify all parentIds for which we have new children to add and patch
|
|
7969
8816
|
// in their new children
|
|
7970
8817
|
let parentIds = new Set();
|
|
7971
8818
|
Object.values(patches).forEach(patch => {
|
|
7972
|
-
if (!patch.parentId || !patches[patch.parentId]) {
|
|
8819
|
+
if (patch && (!patch.parentId || !patches[patch.parentId])) {
|
|
7973
8820
|
parentIds.add(patch.parentId);
|
|
7974
8821
|
}
|
|
7975
8822
|
});
|
|
@@ -7982,6 +8829,7 @@ function addToFifoQueue(path, queue) {
|
|
|
7982
8829
|
}
|
|
7983
8830
|
queue.add(path);
|
|
7984
8831
|
}
|
|
8832
|
+
|
|
7985
8833
|
// Thanks Josh!
|
|
7986
8834
|
// https://www.joshwcomeau.com/snippets/javascript/debounce/
|
|
7987
8835
|
function debounce(callback, wait) {
|
|
@@ -8008,8 +8856,10 @@ function useDataRouterStateContext() {
|
|
|
8008
8856
|
!context ? process.env.NODE_ENV !== "production" ? invariant$1(false, "You must render this element inside a <DataRouterStateContext.Provider> element") : invariant$1(false) : void 0;
|
|
8009
8857
|
return context;
|
|
8010
8858
|
}
|
|
8859
|
+
|
|
8011
8860
|
////////////////////////////////////////////////////////////////////////////////
|
|
8012
8861
|
// FrameworkContext
|
|
8862
|
+
|
|
8013
8863
|
const FrameworkContext = /*#__PURE__*/React.createContext(undefined);
|
|
8014
8864
|
FrameworkContext.displayName = "FrameworkContext";
|
|
8015
8865
|
function useFrameworkContext() {
|
|
@@ -8017,6 +8867,26 @@ function useFrameworkContext() {
|
|
|
8017
8867
|
!context ? process.env.NODE_ENV !== "production" ? invariant$1(false, "You must render this element inside a <HydratedRouter> element") : invariant$1(false) : void 0;
|
|
8018
8868
|
return context;
|
|
8019
8869
|
}
|
|
8870
|
+
|
|
8871
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
8872
|
+
// Public API
|
|
8873
|
+
|
|
8874
|
+
/**
|
|
8875
|
+
* Defines the discovery behavior of the link:
|
|
8876
|
+
*
|
|
8877
|
+
* - "render" - default, discover the route when the link renders
|
|
8878
|
+
* - "none" - don't eagerly discover, only discover if the link is clicked
|
|
8879
|
+
*/
|
|
8880
|
+
|
|
8881
|
+
/**
|
|
8882
|
+
* Defines the prefetching behavior of the link:
|
|
8883
|
+
*
|
|
8884
|
+
* - "none": Never fetched
|
|
8885
|
+
* - "intent": Fetched when the user focuses or hovers the link
|
|
8886
|
+
* - "render": Fetched when the link is rendered
|
|
8887
|
+
* - "viewport": Fetched when the link is in the viewport
|
|
8888
|
+
*/
|
|
8889
|
+
|
|
8020
8890
|
function usePrefetchBehavior(prefetch, theirElementProps) {
|
|
8021
8891
|
let frameworkContext = React.useContext(FrameworkContext);
|
|
8022
8892
|
let [maybePrefetch, setMaybePrefetch] = React.useState(false);
|
|
@@ -8065,6 +8935,7 @@ function usePrefetchBehavior(prefetch, theirElementProps) {
|
|
|
8065
8935
|
setMaybePrefetch(false);
|
|
8066
8936
|
setShouldPrefetch(false);
|
|
8067
8937
|
};
|
|
8938
|
+
|
|
8068
8939
|
// No prefetching if not using SSR
|
|
8069
8940
|
if (!frameworkContext) {
|
|
8070
8941
|
return [false, ref, {}];
|
|
@@ -8072,6 +8943,7 @@ function usePrefetchBehavior(prefetch, theirElementProps) {
|
|
|
8072
8943
|
if (prefetch !== "intent") {
|
|
8073
8944
|
return [shouldPrefetch, ref, {}];
|
|
8074
8945
|
}
|
|
8946
|
+
|
|
8075
8947
|
// When using prefetch="intent" we need to attach focus/hover listeners
|
|
8076
8948
|
return [shouldPrefetch, ref, {
|
|
8077
8949
|
onFocus: composeEventHandlers(onFocus, setIntent),
|
|
@@ -8089,6 +8961,7 @@ function composeEventHandlers(theirHandler, ourHandler) {
|
|
|
8089
8961
|
}
|
|
8090
8962
|
};
|
|
8091
8963
|
}
|
|
8964
|
+
|
|
8092
8965
|
// Return the matches actively being displayed:
|
|
8093
8966
|
// - In SPA Mode we only SSR/hydrate the root match, and include all matches
|
|
8094
8967
|
// after hydration. This lets the router handle initial match loads via lazy().
|
|
@@ -8104,6 +8977,7 @@ function getActiveMatches(matches, errors, isSpaMode) {
|
|
|
8104
8977
|
}
|
|
8105
8978
|
return matches;
|
|
8106
8979
|
}
|
|
8980
|
+
|
|
8107
8981
|
/**
|
|
8108
8982
|
Renders all of the `<link>` tags created by route module {@link LinksFunction} export. You should render it inside the `<head>` of your document.
|
|
8109
8983
|
|
|
@@ -8137,22 +9011,23 @@ function Links() {
|
|
|
8137
9011
|
} = useDataRouterStateContext();
|
|
8138
9012
|
let matches = getActiveMatches(routerMatches, errors, isSpaMode);
|
|
8139
9013
|
let keyedLinks = React.useMemo(() => getKeyedLinksForMatches(matches, routeModules, manifest), [matches, routeModules, manifest]);
|
|
8140
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null, criticalCss ?
|
|
9014
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, criticalCss ? /*#__PURE__*/React.createElement("style", {
|
|
8141
9015
|
dangerouslySetInnerHTML: {
|
|
8142
9016
|
__html: criticalCss
|
|
8143
9017
|
}
|
|
8144
|
-
})
|
|
9018
|
+
}) : null, keyedLinks.map(_ref => {
|
|
8145
9019
|
let {
|
|
8146
9020
|
key,
|
|
8147
9021
|
link
|
|
8148
9022
|
} = _ref;
|
|
8149
|
-
return isPageLinkDescriptor(link) ?
|
|
9023
|
+
return isPageLinkDescriptor(link) ? /*#__PURE__*/React.createElement(PrefetchPageLinks, _extends({
|
|
8150
9024
|
key: key
|
|
8151
|
-
}, link))
|
|
9025
|
+
}, link)) : /*#__PURE__*/React.createElement("link", _extends({
|
|
8152
9026
|
key: key
|
|
8153
|
-
}, link))
|
|
9027
|
+
}, link));
|
|
8154
9028
|
}));
|
|
8155
9029
|
}
|
|
9030
|
+
|
|
8156
9031
|
/**
|
|
8157
9032
|
Renders `<link rel=prefetch|modulepreload>` tags for modules and data of another page to enable an instant navigation to that page. {@link LinkProps.prefetch | `<Link prefetch>`} uses this internally, but you can render it to prefetch a page for any other reason.
|
|
8158
9033
|
|
|
@@ -8226,18 +9101,20 @@ function PrefetchPageLinksImpl(_ref3) {
|
|
|
8226
9101
|
// since it would always trigger a prefetch of the existing loaders
|
|
8227
9102
|
return [];
|
|
8228
9103
|
}
|
|
9104
|
+
|
|
8229
9105
|
// Single-fetch is harder :)
|
|
8230
9106
|
// This parallels the logic in the single fetch data strategy
|
|
8231
9107
|
let routesParams = new Set();
|
|
8232
9108
|
let foundOptOutRoute = false;
|
|
8233
9109
|
nextMatches.forEach(m => {
|
|
8234
9110
|
var _routeModules$m$route;
|
|
8235
|
-
|
|
9111
|
+
let manifestRoute = manifest.routes[m.route.id];
|
|
9112
|
+
if (!manifestRoute || !manifestRoute.hasLoader) {
|
|
8236
9113
|
return;
|
|
8237
9114
|
}
|
|
8238
9115
|
if (!newMatchesForData.some(m2 => m2.route.id === m.route.id) && m.route.id in loaderData && (_routeModules$m$route = routeModules[m.route.id]) != null && _routeModules$m$route.shouldRevalidate) {
|
|
8239
9116
|
foundOptOutRoute = true;
|
|
8240
|
-
} else if (
|
|
9117
|
+
} else if (manifestRoute.hasClientLoader) {
|
|
8241
9118
|
foundOptOutRoute = true;
|
|
8242
9119
|
} else {
|
|
8243
9120
|
routesParams.add(m.route.id);
|
|
@@ -8256,19 +9133,20 @@ function PrefetchPageLinksImpl(_ref3) {
|
|
|
8256
9133
|
return [url.pathname + url.search];
|
|
8257
9134
|
}, [loaderData, location, manifest, newMatchesForData, nextMatches, page, routeModules]);
|
|
8258
9135
|
let moduleHrefs = React.useMemo(() => getModuleLinkHrefs(newMatchesForAssets, manifest), [newMatchesForAssets, manifest]);
|
|
9136
|
+
|
|
8259
9137
|
// needs to be a hook with async behavior because we need the modules, not
|
|
8260
9138
|
// just the manifest like the other links in here.
|
|
8261
9139
|
let keyedPrefetchLinks = useKeyedPrefetchLinks(newMatchesForAssets);
|
|
8262
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null, dataHrefs.map(href =>
|
|
9140
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, dataHrefs.map(href => /*#__PURE__*/React.createElement("link", _extends({
|
|
8263
9141
|
key: href,
|
|
8264
9142
|
rel: "prefetch",
|
|
8265
9143
|
as: "fetch",
|
|
8266
9144
|
href: href
|
|
8267
|
-
}, linkProps)))
|
|
9145
|
+
}, linkProps))), moduleHrefs.map(href => /*#__PURE__*/React.createElement("link", _extends({
|
|
8268
9146
|
key: href,
|
|
8269
9147
|
rel: "modulepreload",
|
|
8270
9148
|
href: href
|
|
8271
|
-
}, linkProps)))
|
|
9149
|
+
}, linkProps))), keyedPrefetchLinks.map(_ref4 => {
|
|
8272
9150
|
let {
|
|
8273
9151
|
key,
|
|
8274
9152
|
link
|
|
@@ -8283,6 +9161,7 @@ function PrefetchPageLinksImpl(_ref3) {
|
|
|
8283
9161
|
);
|
|
8284
9162
|
}));
|
|
8285
9163
|
}
|
|
9164
|
+
|
|
8286
9165
|
/**
|
|
8287
9166
|
Renders all the `<meta>` tags created by route module {@link MetaFunction} exports. You should render it inside the `<head>` of your HTML.
|
|
8288
9167
|
|
|
@@ -8390,10 +9269,10 @@ function Meta() {
|
|
|
8390
9269
|
delete metaProps.charset;
|
|
8391
9270
|
}
|
|
8392
9271
|
if ("charSet" in metaProps && metaProps.charSet != null) {
|
|
8393
|
-
return typeof metaProps.charSet === "string" ?
|
|
9272
|
+
return typeof metaProps.charSet === "string" ? /*#__PURE__*/React.createElement("meta", {
|
|
8394
9273
|
key: "charSet",
|
|
8395
9274
|
charSet: metaProps.charSet
|
|
8396
|
-
})
|
|
9275
|
+
}) : null;
|
|
8397
9276
|
}
|
|
8398
9277
|
if ("script:ld+json" in metaProps) {
|
|
8399
9278
|
try {
|
|
@@ -8417,11 +9296,24 @@ function Meta() {
|
|
|
8417
9296
|
function isValidMetaTag(tagName) {
|
|
8418
9297
|
return typeof tagName === "string" && /^(meta|link)$/.test(tagName);
|
|
8419
9298
|
}
|
|
9299
|
+
|
|
8420
9300
|
/**
|
|
8421
9301
|
* Tracks whether hydration is finished, so scripts can be skipped
|
|
8422
9302
|
* during client-side updates.
|
|
8423
9303
|
*/
|
|
8424
9304
|
let isHydrated = false;
|
|
9305
|
+
|
|
9306
|
+
/**
|
|
9307
|
+
A couple common attributes:
|
|
9308
|
+
|
|
9309
|
+
- `<Scripts crossOrigin>` for hosting your static assets on a different server than your app.
|
|
9310
|
+
- `<Scripts nonce>` to support a [content security policy for scripts](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src) with [nonce-sources](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/Sources#sources) for your `<script>` tags.
|
|
9311
|
+
|
|
9312
|
+
You cannot pass through attributes such as `async`, `defer`, `src`, `type`, `noModule` because they are managed by React Router internally.
|
|
9313
|
+
|
|
9314
|
+
@category Types
|
|
9315
|
+
*/
|
|
9316
|
+
|
|
8425
9317
|
/**
|
|
8426
9318
|
Renders the client runtime of your app. It should be rendered inside the `<body>` of the document.
|
|
8427
9319
|
|
|
@@ -8460,6 +9352,7 @@ function Scripts(props) {
|
|
|
8460
9352
|
matches: routerMatches
|
|
8461
9353
|
} = useDataRouterStateContext();
|
|
8462
9354
|
let enableFogOfWar = isFogOfWarEnabled(isSpaMode);
|
|
9355
|
+
|
|
8463
9356
|
// Let <ServerRouter> know that we hydrated and we should render the single
|
|
8464
9357
|
// fetch streaming scripts
|
|
8465
9358
|
if (renderMeta) {
|
|
@@ -8492,23 +9385,23 @@ function Scripts(props) {
|
|
|
8492
9385
|
}, []);
|
|
8493
9386
|
let routePreloads = matches.map(match => {
|
|
8494
9387
|
let route = manifest.routes[match.route.id];
|
|
8495
|
-
return (route.imports || []).concat([route.module]);
|
|
9388
|
+
return route ? (route.imports || []).concat([route.module]) : [];
|
|
8496
9389
|
}).flat(1);
|
|
8497
9390
|
let preloads = isHydrated ? [] : manifest.entry.imports.concat(routePreloads);
|
|
8498
|
-
return isHydrated ? null :
|
|
9391
|
+
return isHydrated ? null : /*#__PURE__*/React.createElement(React.Fragment, null, !enableFogOfWar ? /*#__PURE__*/React.createElement("link", {
|
|
8499
9392
|
rel: "modulepreload",
|
|
8500
9393
|
href: manifest.url,
|
|
8501
9394
|
crossOrigin: props.crossOrigin
|
|
8502
|
-
})
|
|
9395
|
+
}) : null, /*#__PURE__*/React.createElement("link", {
|
|
8503
9396
|
rel: "modulepreload",
|
|
8504
9397
|
href: manifest.entry.module,
|
|
8505
9398
|
crossOrigin: props.crossOrigin
|
|
8506
|
-
}), dedupe(preloads).map(path =>
|
|
9399
|
+
}), dedupe(preloads).map(path => /*#__PURE__*/React.createElement("link", {
|
|
8507
9400
|
key: path,
|
|
8508
9401
|
rel: "modulepreload",
|
|
8509
9402
|
href: path,
|
|
8510
9403
|
crossOrigin: props.crossOrigin
|
|
8511
|
-
}))
|
|
9404
|
+
})), initialScripts);
|
|
8512
9405
|
}
|
|
8513
9406
|
function dedupe(array) {
|
|
8514
9407
|
return [...new Set(array)];
|
|
@@ -8535,7 +9428,9 @@ const _excluded$1 = ["onClick", "discover", "prefetch", "relative", "reloadDocum
|
|
|
8535
9428
|
////////////////////////////////////////////////////////////////////////////////
|
|
8536
9429
|
//#region Global Stuff
|
|
8537
9430
|
////////////////////////////////////////////////////////////////////////////////
|
|
9431
|
+
|
|
8538
9432
|
const isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
|
|
9433
|
+
|
|
8539
9434
|
// HEY YOU! DON'T TOUCH THIS VARIABLE!
|
|
8540
9435
|
//
|
|
8541
9436
|
// It is replaced with the proper version at build time via a babel plugin in
|
|
@@ -8553,6 +9448,12 @@ try {
|
|
|
8553
9448
|
} catch (e) {
|
|
8554
9449
|
// no-op
|
|
8555
9450
|
}
|
|
9451
|
+
//#endregion
|
|
9452
|
+
|
|
9453
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
9454
|
+
//#region Routers
|
|
9455
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
9456
|
+
|
|
8556
9457
|
/**
|
|
8557
9458
|
* @category Routers
|
|
8558
9459
|
*/
|
|
@@ -8571,6 +9472,7 @@ function createBrowserRouter(routes, opts) {
|
|
|
8571
9472
|
window: opts == null ? void 0 : opts.window
|
|
8572
9473
|
}).initialize();
|
|
8573
9474
|
}
|
|
9475
|
+
|
|
8574
9476
|
/**
|
|
8575
9477
|
* @category Routers
|
|
8576
9478
|
*/
|
|
@@ -8638,6 +9540,17 @@ function deserializeErrors$1(errors) {
|
|
|
8638
9540
|
}
|
|
8639
9541
|
return serialized;
|
|
8640
9542
|
}
|
|
9543
|
+
|
|
9544
|
+
//#endregion
|
|
9545
|
+
|
|
9546
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
9547
|
+
//#region Components
|
|
9548
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
9549
|
+
|
|
9550
|
+
/**
|
|
9551
|
+
* @category Types
|
|
9552
|
+
*/
|
|
9553
|
+
|
|
8641
9554
|
/**
|
|
8642
9555
|
* A `<Router>` for use in web browsers. Provides the cleanest URLs.
|
|
8643
9556
|
*
|
|
@@ -8673,6 +9586,11 @@ function BrowserRouter(_ref) {
|
|
|
8673
9586
|
navigator: history
|
|
8674
9587
|
});
|
|
8675
9588
|
}
|
|
9589
|
+
|
|
9590
|
+
/**
|
|
9591
|
+
* @category Types
|
|
9592
|
+
*/
|
|
9593
|
+
|
|
8676
9594
|
/**
|
|
8677
9595
|
* A `<Router>` for use in web browsers. Stores the location in the hash
|
|
8678
9596
|
* portion of the URL so it is not sent to the server.
|
|
@@ -8709,6 +9627,11 @@ function HashRouter(_ref2) {
|
|
|
8709
9627
|
navigator: history
|
|
8710
9628
|
});
|
|
8711
9629
|
}
|
|
9630
|
+
|
|
9631
|
+
/**
|
|
9632
|
+
* @category Types
|
|
9633
|
+
*/
|
|
9634
|
+
|
|
8712
9635
|
/**
|
|
8713
9636
|
* A `<Router>` that accepts a pre-instantiated history object. It's important
|
|
8714
9637
|
* to note that using your own history object is highly discouraged and may add
|
|
@@ -8741,7 +9664,13 @@ function HistoryRouter(_ref3) {
|
|
|
8741
9664
|
});
|
|
8742
9665
|
}
|
|
8743
9666
|
HistoryRouter.displayName = "unstable_HistoryRouter";
|
|
9667
|
+
|
|
9668
|
+
/**
|
|
9669
|
+
* @category Types
|
|
9670
|
+
*/
|
|
9671
|
+
|
|
8744
9672
|
const ABSOLUTE_URL_REGEX$1 = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
|
|
9673
|
+
|
|
8745
9674
|
/**
|
|
8746
9675
|
A progressively enhanced `<a href>` wrapper to enable navigation with client-side routing.
|
|
8747
9676
|
|
|
@@ -8780,12 +9709,14 @@ const Link = /*#__PURE__*/React.forwardRef(function LinkWithRef(_ref4, forwarded
|
|
|
8780
9709
|
basename
|
|
8781
9710
|
} = React.useContext(NavigationContext);
|
|
8782
9711
|
let isAbsolute = typeof to === "string" && ABSOLUTE_URL_REGEX$1.test(to);
|
|
9712
|
+
|
|
8783
9713
|
// Rendered into <a href> for absolute URLs
|
|
8784
9714
|
let absoluteHref;
|
|
8785
9715
|
let isExternal = false;
|
|
8786
9716
|
if (typeof to === "string" && isAbsolute) {
|
|
8787
9717
|
// Render the absolute href server- and client-side
|
|
8788
9718
|
absoluteHref = to;
|
|
9719
|
+
|
|
8789
9720
|
// Only check for external origins client-side
|
|
8790
9721
|
if (isBrowser) {
|
|
8791
9722
|
try {
|
|
@@ -8804,6 +9735,7 @@ const Link = /*#__PURE__*/React.forwardRef(function LinkWithRef(_ref4, forwarded
|
|
|
8804
9735
|
}
|
|
8805
9736
|
}
|
|
8806
9737
|
}
|
|
9738
|
+
|
|
8807
9739
|
// Rendered into <a href> for relative URLs
|
|
8808
9740
|
let href = useHref(to, {
|
|
8809
9741
|
relative
|
|
@@ -8833,11 +9765,51 @@ const Link = /*#__PURE__*/React.forwardRef(function LinkWithRef(_ref4, forwarded
|
|
|
8833
9765
|
target: target,
|
|
8834
9766
|
"data-discover": !isAbsolute && discover === "render" ? "true" : undefined
|
|
8835
9767
|
}));
|
|
8836
|
-
return shouldPrefetch && !isAbsolute ?
|
|
9768
|
+
return shouldPrefetch && !isAbsolute ? /*#__PURE__*/React.createElement(React.Fragment, null, link, /*#__PURE__*/React.createElement(PrefetchPageLinks, {
|
|
8837
9769
|
page: href
|
|
8838
|
-
}))
|
|
9770
|
+
})) : link;
|
|
8839
9771
|
});
|
|
8840
9772
|
Link.displayName = "Link";
|
|
9773
|
+
|
|
9774
|
+
/**
|
|
9775
|
+
The object passed to {@link NavLink} `children`, `className`, and `style` prop callbacks to render and style the link based on its state.
|
|
9776
|
+
|
|
9777
|
+
```
|
|
9778
|
+
// className
|
|
9779
|
+
<NavLink
|
|
9780
|
+
to="/messages"
|
|
9781
|
+
className={({ isActive, isPending }) =>
|
|
9782
|
+
isPending ? "pending" : isActive ? "active" : ""
|
|
9783
|
+
}
|
|
9784
|
+
>
|
|
9785
|
+
Messages
|
|
9786
|
+
</NavLink>
|
|
9787
|
+
|
|
9788
|
+
// style
|
|
9789
|
+
<NavLink
|
|
9790
|
+
to="/messages"
|
|
9791
|
+
style={({ isActive, isPending }) => {
|
|
9792
|
+
return {
|
|
9793
|
+
fontWeight: isActive ? "bold" : "",
|
|
9794
|
+
color: isPending ? "red" : "black",
|
|
9795
|
+
}
|
|
9796
|
+
)}
|
|
9797
|
+
/>
|
|
9798
|
+
|
|
9799
|
+
// children
|
|
9800
|
+
<NavLink to="/tasks">
|
|
9801
|
+
{({ isActive, isPending }) => (
|
|
9802
|
+
<span className={isActive ? "active" : ""}>Tasks</span>
|
|
9803
|
+
)}
|
|
9804
|
+
</NavLink>
|
|
9805
|
+
```
|
|
9806
|
+
|
|
9807
|
+
*/
|
|
9808
|
+
|
|
9809
|
+
/**
|
|
9810
|
+
* @category Types
|
|
9811
|
+
*/
|
|
9812
|
+
|
|
8841
9813
|
/**
|
|
8842
9814
|
Wraps {@link Link | `<Link>`} with additional props for styling active and pending states.
|
|
8843
9815
|
|
|
@@ -8900,6 +9872,7 @@ const NavLink = /*#__PURE__*/React.forwardRef(function NavLinkWithRef(_ref5, ref
|
|
|
8900
9872
|
if (nextLocationPathname && basename) {
|
|
8901
9873
|
nextLocationPathname = stripBasename(nextLocationPathname, basename) || nextLocationPathname;
|
|
8902
9874
|
}
|
|
9875
|
+
|
|
8903
9876
|
// If the `to` has a trailing slash, look at that exact spot. Otherwise,
|
|
8904
9877
|
// we're looking for a slash _after_ what's in `to`. For example:
|
|
8905
9878
|
//
|
|
@@ -8936,6 +9909,21 @@ const NavLink = /*#__PURE__*/React.forwardRef(function NavLinkWithRef(_ref5, ref
|
|
|
8936
9909
|
}), typeof children === "function" ? children(renderProps) : children);
|
|
8937
9910
|
});
|
|
8938
9911
|
NavLink.displayName = "NavLink";
|
|
9912
|
+
|
|
9913
|
+
/**
|
|
9914
|
+
* Form props shared by navigations and fetchers
|
|
9915
|
+
*/
|
|
9916
|
+
|
|
9917
|
+
/**
|
|
9918
|
+
* Form props available to fetchers
|
|
9919
|
+
* @category Types
|
|
9920
|
+
*/
|
|
9921
|
+
|
|
9922
|
+
/**
|
|
9923
|
+
* Form props available to navigations
|
|
9924
|
+
* @category Types
|
|
9925
|
+
*/
|
|
9926
|
+
|
|
8939
9927
|
/**
|
|
8940
9928
|
|
|
8941
9929
|
A progressively enhanced HTML [`<form>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form) that submits data to actions via `fetch`, activating pending states in `useNavigation` which enables advanced user interfaces beyond a basic HTML form. After a form's action completes, all data on the page is automatically revalidated to keep the UI in sync with the data.
|
|
@@ -9050,6 +10038,7 @@ function ScrollRestoration(_ref7) {
|
|
|
9050
10038
|
getKey,
|
|
9051
10039
|
storageKey
|
|
9052
10040
|
});
|
|
10041
|
+
|
|
9053
10042
|
// In order to support `getKey`, we need to compute a "key" here so we can
|
|
9054
10043
|
// hydrate that up so that SSR scroll restoration isn't waiting on React to
|
|
9055
10044
|
// hydrate. *However*, our key on the server is not the same as our key on
|
|
@@ -9064,6 +10053,7 @@ function ScrollRestoration(_ref7) {
|
|
|
9064
10053
|
// Nah, we only need this the first time for the SSR render
|
|
9065
10054
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
9066
10055
|
[]);
|
|
10056
|
+
|
|
9067
10057
|
// In SPA Mode, there's nothing to restore on initial render since we didn't
|
|
9068
10058
|
// render anything on the server
|
|
9069
10059
|
if (!remixContext || remixContext.isSpaMode) {
|
|
@@ -9096,24 +10086,24 @@ function ScrollRestoration(_ref7) {
|
|
|
9096
10086
|
}
|
|
9097
10087
|
ScrollRestoration.displayName = "ScrollRestoration";
|
|
9098
10088
|
//#endregion
|
|
10089
|
+
|
|
9099
10090
|
////////////////////////////////////////////////////////////////////////////////
|
|
9100
10091
|
//#region Hooks
|
|
9101
10092
|
////////////////////////////////////////////////////////////////////////////////
|
|
9102
|
-
var DataRouterHook
|
|
9103
|
-
(function (DataRouterHook) {
|
|
10093
|
+
var DataRouterHook = /*#__PURE__*/function (DataRouterHook) {
|
|
9104
10094
|
DataRouterHook["UseScrollRestoration"] = "useScrollRestoration";
|
|
9105
10095
|
DataRouterHook["UseSubmit"] = "useSubmit";
|
|
9106
10096
|
DataRouterHook["UseSubmitFetcher"] = "useSubmitFetcher";
|
|
9107
10097
|
DataRouterHook["UseFetcher"] = "useFetcher";
|
|
9108
10098
|
DataRouterHook["useViewTransitionState"] = "useViewTransitionState";
|
|
9109
|
-
|
|
9110
|
-
|
|
9111
|
-
|
|
10099
|
+
return DataRouterHook;
|
|
10100
|
+
}(DataRouterHook || {});
|
|
10101
|
+
var DataRouterStateHook = /*#__PURE__*/function (DataRouterStateHook) {
|
|
9112
10102
|
DataRouterStateHook["UseFetcher"] = "useFetcher";
|
|
9113
10103
|
DataRouterStateHook["UseFetchers"] = "useFetchers";
|
|
9114
10104
|
DataRouterStateHook["UseScrollRestoration"] = "useScrollRestoration";
|
|
9115
|
-
|
|
9116
|
-
// Internal hooks
|
|
10105
|
+
return DataRouterStateHook;
|
|
10106
|
+
}(DataRouterStateHook || {}); // Internal hooks
|
|
9117
10107
|
function getDataRouterConsoleError(hookName) {
|
|
9118
10108
|
return hookName + " must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.";
|
|
9119
10109
|
}
|
|
@@ -9127,7 +10117,9 @@ function useDataRouterState(hookName) {
|
|
|
9127
10117
|
!state ? process.env.NODE_ENV !== "production" ? invariant$2(false, getDataRouterConsoleError(hookName)) : invariant$2(false) : void 0;
|
|
9128
10118
|
return state;
|
|
9129
10119
|
}
|
|
10120
|
+
|
|
9130
10121
|
// External hooks
|
|
10122
|
+
|
|
9131
10123
|
/**
|
|
9132
10124
|
* Handles the click behavior for router `<Link>` components. This is useful if
|
|
9133
10125
|
* you need to create custom `<Link>` components with the same click behavior we
|
|
@@ -9152,6 +10144,7 @@ function useLinkClickHandler(to, _temp) {
|
|
|
9152
10144
|
return React.useCallback(event => {
|
|
9153
10145
|
if (shouldProcessLinkClick(event, target)) {
|
|
9154
10146
|
event.preventDefault();
|
|
10147
|
+
|
|
9155
10148
|
// If the URL hasn't changed, a regular <a> will do a replace instead of
|
|
9156
10149
|
// a push, so do the same here unless the replace prop is explicitly set
|
|
9157
10150
|
let replace = replaceProp !== undefined ? replaceProp : createPath(location) === createPath(path);
|
|
@@ -9165,6 +10158,7 @@ function useLinkClickHandler(to, _temp) {
|
|
|
9165
10158
|
}
|
|
9166
10159
|
}, [location, navigate, path, replaceProp, state, target, to, preventScrollReset, relative, viewTransition]);
|
|
9167
10160
|
}
|
|
10161
|
+
|
|
9168
10162
|
/**
|
|
9169
10163
|
Returns a tuple of the current URL's {@link URLSearchParams} and a function to update them. Setting the search params causes a navigation.
|
|
9170
10164
|
|
|
@@ -9197,8 +10191,47 @@ function useSearchParams(defaultInit) {
|
|
|
9197
10191
|
}, [navigate, searchParams]);
|
|
9198
10192
|
return [searchParams, setSearchParams];
|
|
9199
10193
|
}
|
|
10194
|
+
|
|
10195
|
+
/**
|
|
10196
|
+
Sets new search params and causes a navigation when called.
|
|
10197
|
+
|
|
10198
|
+
```tsx
|
|
10199
|
+
<button
|
|
10200
|
+
onClick={() => {
|
|
10201
|
+
const params = new URLSearchParams();
|
|
10202
|
+
params.set("someKey", "someValue");
|
|
10203
|
+
setSearchParams(params, {
|
|
10204
|
+
preventScrollReset: true,
|
|
10205
|
+
});
|
|
10206
|
+
}}
|
|
10207
|
+
/>
|
|
10208
|
+
```
|
|
10209
|
+
|
|
10210
|
+
It also supports a function for setting new search params.
|
|
10211
|
+
|
|
10212
|
+
```tsx
|
|
10213
|
+
<button
|
|
10214
|
+
onClick={() => {
|
|
10215
|
+
setSearchParams((prev) => {
|
|
10216
|
+
prev.set("someKey", "someValue");
|
|
10217
|
+
return prev;
|
|
10218
|
+
});
|
|
10219
|
+
}}
|
|
10220
|
+
/>
|
|
10221
|
+
```
|
|
10222
|
+
*/
|
|
10223
|
+
|
|
10224
|
+
/**
|
|
10225
|
+
* Submits a HTML `<form>` to the server without reloading the page.
|
|
10226
|
+
*/
|
|
10227
|
+
|
|
10228
|
+
/**
|
|
10229
|
+
* Submits a fetcher `<form>` to the server without reloading the page.
|
|
10230
|
+
*/
|
|
10231
|
+
|
|
9200
10232
|
let fetcherId = 0;
|
|
9201
10233
|
let getUniqueFetcherId = () => "__" + String(++fetcherId) + "__";
|
|
10234
|
+
|
|
9202
10235
|
/**
|
|
9203
10236
|
The imperative version of {@link Form | `<Form>`} that lets you submit a form from code instead of a user interaction.
|
|
9204
10237
|
|
|
@@ -9264,6 +10297,7 @@ function useSubmit() {
|
|
|
9264
10297
|
}
|
|
9265
10298
|
}, [router, basename, currentRouteId]);
|
|
9266
10299
|
}
|
|
10300
|
+
|
|
9267
10301
|
// v7: Eventually we should deprecate this entirely in favor of using the
|
|
9268
10302
|
// router method directly?
|
|
9269
10303
|
/**
|
|
@@ -9304,6 +10338,7 @@ action, _temp2) {
|
|
|
9304
10338
|
let path = _extends({}, useResolvedPath(action ? action : ".", {
|
|
9305
10339
|
relative
|
|
9306
10340
|
}));
|
|
10341
|
+
|
|
9307
10342
|
// If no action was specified, browsers will persist current search params
|
|
9308
10343
|
// when determining the path, so match that behavior
|
|
9309
10344
|
// https://github.com/remix-run/remix/issues/927
|
|
@@ -9312,6 +10347,7 @@ action, _temp2) {
|
|
|
9312
10347
|
// Safe to write to this directly here since if action was undefined, we
|
|
9313
10348
|
// would have called useResolvedPath(".") which will never include a search
|
|
9314
10349
|
path.search = location.search;
|
|
10350
|
+
|
|
9315
10351
|
// When grabbing search params from the URL, remove any included ?index param
|
|
9316
10352
|
// since it might not apply to our contextual route. We add it back based
|
|
9317
10353
|
// on match.route.index below
|
|
@@ -9328,6 +10364,7 @@ action, _temp2) {
|
|
|
9328
10364
|
if ((!action || action === ".") && match.route.index) {
|
|
9329
10365
|
path.search = path.search ? path.search.replace(/^\?/, "?index&") : "?index";
|
|
9330
10366
|
}
|
|
10367
|
+
|
|
9331
10368
|
// If we're operating within a basename, prepend it to the pathname prior
|
|
9332
10369
|
// to creating the form action. If this is a root navigation, then just use
|
|
9333
10370
|
// the raw basename which allows the basename to have full control over the
|
|
@@ -9337,7 +10374,17 @@ action, _temp2) {
|
|
|
9337
10374
|
}
|
|
9338
10375
|
return createPath(path);
|
|
9339
10376
|
}
|
|
10377
|
+
|
|
10378
|
+
/**
|
|
10379
|
+
The return value of `useFetcher` that keeps track of the state of a fetcher.
|
|
10380
|
+
|
|
10381
|
+
```tsx
|
|
10382
|
+
let fetcher = useFetcher();
|
|
10383
|
+
```
|
|
10384
|
+
*/
|
|
10385
|
+
|
|
9340
10386
|
// TODO: (v7) Change the useFetcher generic default from `any` to `unknown`
|
|
10387
|
+
|
|
9341
10388
|
/**
|
|
9342
10389
|
Useful for creating complex, dynamic user interfaces that require multiple, concurrent data interactions without causing a navigation.
|
|
9343
10390
|
|
|
@@ -9385,17 +10432,20 @@ function useFetcher(_temp3) {
|
|
|
9385
10432
|
!fetcherData ? process.env.NODE_ENV !== "production" ? invariant$2(false, "useFetcher must be used inside a FetchersContext") : invariant$2(false) : void 0;
|
|
9386
10433
|
!route ? process.env.NODE_ENV !== "production" ? invariant$2(false, "useFetcher must be used inside a RouteContext") : invariant$2(false) : void 0;
|
|
9387
10434
|
!(routeId != null) ? process.env.NODE_ENV !== "production" ? invariant$2(false, "useFetcher can only be used on routes that contain a unique \"id\"") : invariant$2(false) : void 0;
|
|
10435
|
+
|
|
9388
10436
|
// Fetcher key handling
|
|
9389
10437
|
let defaultKey = React.useId();
|
|
9390
10438
|
let [fetcherKey, setFetcherKey] = React.useState(key || defaultKey);
|
|
9391
10439
|
if (key && key !== fetcherKey) {
|
|
9392
10440
|
setFetcherKey(key);
|
|
9393
10441
|
}
|
|
10442
|
+
|
|
9394
10443
|
// Registration/cleanup
|
|
9395
10444
|
React.useEffect(() => {
|
|
9396
10445
|
router.getFetcher(fetcherKey);
|
|
9397
10446
|
return () => router.deleteFetcher(fetcherKey);
|
|
9398
10447
|
}, [router, fetcherKey]);
|
|
10448
|
+
|
|
9399
10449
|
// Fetcher additions
|
|
9400
10450
|
let load = React.useCallback(async (href, opts) => {
|
|
9401
10451
|
!routeId ? process.env.NODE_ENV !== "production" ? invariant$2(false, "No routeId available for fetcher.load()") : invariant$2(false) : void 0;
|
|
@@ -9419,6 +10469,7 @@ function useFetcher(_temp3) {
|
|
|
9419
10469
|
FetcherForm.displayName = "fetcher.Form";
|
|
9420
10470
|
return FetcherForm;
|
|
9421
10471
|
}, [fetcherKey]);
|
|
10472
|
+
|
|
9422
10473
|
// Exposed FetcherWithComponents
|
|
9423
10474
|
let fetcher = state.fetchers.get(fetcherKey) || IDLE_FETCHER;
|
|
9424
10475
|
let data = fetcherData.get(fetcherKey);
|
|
@@ -9431,6 +10482,7 @@ function useFetcher(_temp3) {
|
|
|
9431
10482
|
}), [FetcherForm, submit, load, fetcher, data]);
|
|
9432
10483
|
return fetcherWithComponents;
|
|
9433
10484
|
}
|
|
10485
|
+
|
|
9434
10486
|
/**
|
|
9435
10487
|
Returns an array of all in-flight fetchers. This is useful for components throughout the app that didn't create the fetchers but want to use their submissions to participate in optimistic UI.
|
|
9436
10488
|
|
|
@@ -9474,6 +10526,7 @@ function getScrollRestorationKey(location, matches, basename, getKey) {
|
|
|
9474
10526
|
}
|
|
9475
10527
|
return key;
|
|
9476
10528
|
}
|
|
10529
|
+
|
|
9477
10530
|
/**
|
|
9478
10531
|
* When rendered inside a RouterProvider, will restore scroll positions on navigations
|
|
9479
10532
|
*/
|
|
@@ -9495,6 +10548,7 @@ function useScrollRestoration(_temp4) {
|
|
|
9495
10548
|
let location = useLocation();
|
|
9496
10549
|
let matches = useMatches();
|
|
9497
10550
|
let navigation = useNavigation();
|
|
10551
|
+
|
|
9498
10552
|
// Trigger manual scroll restoration while we're active
|
|
9499
10553
|
React.useEffect(() => {
|
|
9500
10554
|
window.history.scrollRestoration = "manual";
|
|
@@ -9502,6 +10556,7 @@ function useScrollRestoration(_temp4) {
|
|
|
9502
10556
|
window.history.scrollRestoration = "auto";
|
|
9503
10557
|
};
|
|
9504
10558
|
}, []);
|
|
10559
|
+
|
|
9505
10560
|
// Save positions on pagehide
|
|
9506
10561
|
usePageHide(React.useCallback(() => {
|
|
9507
10562
|
if (navigation.state === "idle") {
|
|
@@ -9515,6 +10570,7 @@ function useScrollRestoration(_temp4) {
|
|
|
9515
10570
|
}
|
|
9516
10571
|
window.history.scrollRestoration = "auto";
|
|
9517
10572
|
}, [navigation.state, getKey, basename, location, matches, storageKey]));
|
|
10573
|
+
|
|
9518
10574
|
// Read in any saved scroll locations
|
|
9519
10575
|
if (typeof document !== "undefined") {
|
|
9520
10576
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
@@ -9528,12 +10584,14 @@ function useScrollRestoration(_temp4) {
|
|
|
9528
10584
|
// no-op, use default empty object
|
|
9529
10585
|
}
|
|
9530
10586
|
}, [storageKey]);
|
|
10587
|
+
|
|
9531
10588
|
// Enable scroll restoration in the router
|
|
9532
10589
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
9533
10590
|
React.useLayoutEffect(() => {
|
|
9534
10591
|
let disableScrollRestoration = router == null ? void 0 : router.enableScrollRestoration(savedScrollPositions, () => window.scrollY, getKey ? (location, matches) => getScrollRestorationKey(location, matches, basename, getKey) : undefined);
|
|
9535
10592
|
return () => disableScrollRestoration && disableScrollRestoration();
|
|
9536
10593
|
}, [router, basename, getKey]);
|
|
10594
|
+
|
|
9537
10595
|
// Restore scrolling when state.restoreScrollPosition changes
|
|
9538
10596
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
9539
10597
|
React.useLayoutEffect(() => {
|
|
@@ -9541,11 +10599,13 @@ function useScrollRestoration(_temp4) {
|
|
|
9541
10599
|
if (restoreScrollPosition === false) {
|
|
9542
10600
|
return;
|
|
9543
10601
|
}
|
|
10602
|
+
|
|
9544
10603
|
// been here before, scroll to it
|
|
9545
10604
|
if (typeof restoreScrollPosition === "number") {
|
|
9546
10605
|
window.scrollTo(0, restoreScrollPosition);
|
|
9547
10606
|
return;
|
|
9548
10607
|
}
|
|
10608
|
+
|
|
9549
10609
|
// try to scroll to the hash
|
|
9550
10610
|
if (location.hash) {
|
|
9551
10611
|
let el = document.getElementById(decodeURIComponent(location.hash.slice(1)));
|
|
@@ -9554,15 +10614,18 @@ function useScrollRestoration(_temp4) {
|
|
|
9554
10614
|
return;
|
|
9555
10615
|
}
|
|
9556
10616
|
}
|
|
10617
|
+
|
|
9557
10618
|
// Don't reset if this navigation opted out
|
|
9558
10619
|
if (preventScrollReset === true) {
|
|
9559
10620
|
return;
|
|
9560
10621
|
}
|
|
10622
|
+
|
|
9561
10623
|
// otherwise go to the top on new locations
|
|
9562
10624
|
window.scrollTo(0, 0);
|
|
9563
10625
|
}, [location, restoreScrollPosition, preventScrollReset]);
|
|
9564
10626
|
}
|
|
9565
10627
|
}
|
|
10628
|
+
|
|
9566
10629
|
/**
|
|
9567
10630
|
* Setup a callback to be fired on the window's `beforeunload` event.
|
|
9568
10631
|
*
|
|
@@ -9582,6 +10645,7 @@ function useBeforeUnload(callback, options) {
|
|
|
9582
10645
|
};
|
|
9583
10646
|
}, [callback, capture]);
|
|
9584
10647
|
}
|
|
10648
|
+
|
|
9585
10649
|
/**
|
|
9586
10650
|
* Setup a callback to be fired on the window's `pagehide` event. This is
|
|
9587
10651
|
* useful for saving some data to `window.localStorage` just before the page
|
|
@@ -9604,6 +10668,7 @@ function usePageHide(callback, options) {
|
|
|
9604
10668
|
};
|
|
9605
10669
|
}, [callback, capture]);
|
|
9606
10670
|
}
|
|
10671
|
+
|
|
9607
10672
|
/**
|
|
9608
10673
|
Wrapper around useBlocker to show a window.confirm prompt to users instead of building a custom UI with {@link useBlocker}.
|
|
9609
10674
|
|
|
@@ -9665,6 +10730,7 @@ function usePrompt(_ref9) {
|
|
|
9665
10730
|
}
|
|
9666
10731
|
}, [blocker, when]);
|
|
9667
10732
|
}
|
|
10733
|
+
|
|
9668
10734
|
/**
|
|
9669
10735
|
This hook returns `true` when there is an active [View Transition](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API) to the specified location. This can be used to apply finer-grained styles to elements to further customize the view transition. This requires that view transitions have been enabled for the given navigation via {@link LinkProps.viewTransition} (or the `Form`, `submit`, or `navigate` call)
|
|
9670
10736
|
|
|
@@ -9688,6 +10754,7 @@ function useViewTransitionState(to, opts) {
|
|
|
9688
10754
|
}
|
|
9689
10755
|
let currentPath = stripBasename(vtContext.currentLocation.pathname, basename) || vtContext.currentLocation.pathname;
|
|
9690
10756
|
let nextPath = stripBasename(vtContext.nextLocation.pathname, basename) || vtContext.nextLocation.pathname;
|
|
10757
|
+
|
|
9691
10758
|
// Transition is active if we're going to or coming from the indicated
|
|
9692
10759
|
// destination. This ensures that other PUSH navigations that reverse
|
|
9693
10760
|
// an indicated transition apply. I.e., on the list view you have:
|
|
@@ -9703,6 +10770,7 @@ function useViewTransitionState(to, opts) {
|
|
|
9703
10770
|
// (even though this isn't strictly a POP reverse)
|
|
9704
10771
|
return matchPath(path.pathname, nextPath) != null || matchPath(path.pathname, currentPath) != null;
|
|
9705
10772
|
}
|
|
10773
|
+
|
|
9706
10774
|
//#endregion
|
|
9707
10775
|
|
|
9708
10776
|
/**
|
|
@@ -9797,13 +10865,13 @@ function StaticRouterProvider(_ref2) {
|
|
|
9797
10865
|
routes: router.routes,
|
|
9798
10866
|
future: router.future,
|
|
9799
10867
|
state: state
|
|
9800
|
-
})))))), hydrateScript ?
|
|
10868
|
+
})))))), hydrateScript ? /*#__PURE__*/React.createElement("script", {
|
|
9801
10869
|
suppressHydrationWarning: true,
|
|
9802
10870
|
nonce: nonce,
|
|
9803
10871
|
dangerouslySetInnerHTML: {
|
|
9804
10872
|
__html: hydrateScript
|
|
9805
10873
|
}
|
|
9806
|
-
})
|
|
10874
|
+
}) : null);
|
|
9807
10875
|
}
|
|
9808
10876
|
function DataRoutes(_ref3) {
|
|
9809
10877
|
let {
|
|
@@ -9867,6 +10935,7 @@ function createStaticHandler(routes, opts) {
|
|
|
9867
10935
|
mapRouteProperties
|
|
9868
10936
|
}));
|
|
9869
10937
|
}
|
|
10938
|
+
|
|
9870
10939
|
/**
|
|
9871
10940
|
* @category Routers
|
|
9872
10941
|
*/
|
|
@@ -9876,6 +10945,7 @@ function createStaticRouter(routes, context, opts) {
|
|
|
9876
10945
|
}
|
|
9877
10946
|
let manifest = {};
|
|
9878
10947
|
let dataRoutes = convertRoutesToDataRoutes(routes, mapRouteProperties, undefined, manifest);
|
|
10948
|
+
|
|
9879
10949
|
// Because our context matches may be from a framework-agnostic set of
|
|
9880
10950
|
// routes passed to createStaticHandler(), we update them here with our
|
|
9881
10951
|
// newly created/enhanced data routes
|
|
@@ -9978,6 +11048,7 @@ function encodeLocation(to) {
|
|
|
9978
11048
|
};
|
|
9979
11049
|
}
|
|
9980
11050
|
const ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
|
|
11051
|
+
|
|
9981
11052
|
// This utility is based on https://github.com/zertosh/htmlescape
|
|
9982
11053
|
// License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE
|
|
9983
11054
|
const ESCAPE_LOOKUP$1 = {
|
|
@@ -10016,6 +11087,7 @@ function ServerRouter(_ref) {
|
|
|
10016
11087
|
serverHandoffString
|
|
10017
11088
|
} = context;
|
|
10018
11089
|
let routes = createServerRoutes(manifest.routes, routeModules, context.future, context.isSpaMode);
|
|
11090
|
+
|
|
10019
11091
|
// Create a shallow clone of `loaderData` we can mutate for partial hydration.
|
|
10020
11092
|
// When a route exports a `clientLoader` and a `HydrateFallback`, we want to
|
|
10021
11093
|
// render the fallback on the server so we clear our the `loaderData` during SSR.
|
|
@@ -10030,7 +11102,7 @@ function ServerRouter(_ref) {
|
|
|
10030
11102
|
// route opted into clientLoader hydration and either:
|
|
10031
11103
|
// * gave us a HydrateFallback
|
|
10032
11104
|
// * or doesn't have a server loader and we have no data to render
|
|
10033
|
-
if (route && shouldHydrateRouteLoader(manifestRoute, route, context.isSpaMode) && (route.HydrateFallback || !manifestRoute.hasLoader)) {
|
|
11105
|
+
if (route && manifestRoute && shouldHydrateRouteLoader(manifestRoute, route, context.isSpaMode) && (route.HydrateFallback || !manifestRoute.hasLoader)) {
|
|
10034
11106
|
delete context.staticHandlerContext.loaderData[routeId];
|
|
10035
11107
|
}
|
|
10036
11108
|
}
|
|
@@ -10053,13 +11125,13 @@ function ServerRouter(_ref) {
|
|
|
10053
11125
|
router: router,
|
|
10054
11126
|
context: context.staticHandlerContext,
|
|
10055
11127
|
hydrate: false
|
|
10056
|
-
}))), context.serverHandoffStream ?
|
|
11128
|
+
}))), context.serverHandoffStream ? /*#__PURE__*/React.createElement(React.Suspense, null, /*#__PURE__*/React.createElement(StreamTransfer, {
|
|
10057
11129
|
context: context,
|
|
10058
11130
|
identifier: 0,
|
|
10059
11131
|
reader: context.serverHandoffStream.getReader(),
|
|
10060
11132
|
textDecoder: new TextDecoder(),
|
|
10061
11133
|
nonce: nonce
|
|
10062
|
-
}))
|
|
11134
|
+
})) : null);
|
|
10063
11135
|
}
|
|
10064
11136
|
|
|
10065
11137
|
/**
|
|
@@ -10093,6 +11165,7 @@ function createRoutesStub(routes, context) {
|
|
|
10093
11165
|
routeModules: {},
|
|
10094
11166
|
isSpaMode: false
|
|
10095
11167
|
};
|
|
11168
|
+
|
|
10096
11169
|
// Update the routes to include context in the loader/action and populate
|
|
10097
11170
|
// the manifest and routeModules during the walk
|
|
10098
11171
|
let patched = processRoutes(
|
|
@@ -10116,6 +11189,7 @@ function processRoutes(routes, context, manifest, routeModules, parentId) {
|
|
|
10116
11189
|
if (!route.id) {
|
|
10117
11190
|
throw new Error("Expected a route.id in @remix-run/testing processRoutes() function");
|
|
10118
11191
|
}
|
|
11192
|
+
|
|
10119
11193
|
// Patch in the Remix context to loaders/actions
|
|
10120
11194
|
let {
|
|
10121
11195
|
loader,
|
|
@@ -10137,6 +11211,7 @@ function processRoutes(routes, context, manifest, routeModules, parentId) {
|
|
|
10137
11211
|
handle: route.handle,
|
|
10138
11212
|
shouldRevalidate: route.shouldRevalidate
|
|
10139
11213
|
};
|
|
11214
|
+
|
|
10140
11215
|
// Add the EntryRoute to the manifest
|
|
10141
11216
|
let entryRoute = {
|
|
10142
11217
|
id: route.id,
|
|
@@ -10154,6 +11229,7 @@ function processRoutes(routes, context, manifest, routeModules, parentId) {
|
|
|
10154
11229
|
module: "build/stub-path-to-module.js" // any need for this?
|
|
10155
11230
|
};
|
|
10156
11231
|
manifest.routes[newRoute.id] = entryRoute;
|
|
11232
|
+
|
|
10157
11233
|
// Add the route to routeModules
|
|
10158
11234
|
routeModules[route.id] = {
|
|
10159
11235
|
default: route.Component || Outlet,
|
|
@@ -10201,6 +11277,18 @@ function byteStringToUint8Array(byteString) {
|
|
|
10201
11277
|
}
|
|
10202
11278
|
|
|
10203
11279
|
const _excluded = ["secrets"];
|
|
11280
|
+
|
|
11281
|
+
/**
|
|
11282
|
+
* A HTTP cookie.
|
|
11283
|
+
*
|
|
11284
|
+
* A Cookie is a logical container for metadata about a HTTP cookie; its name
|
|
11285
|
+
* and options. But it doesn't contain a value. Instead, it has `parse()` and
|
|
11286
|
+
* `serialize()` methods that allow a single instance to be reused for
|
|
11287
|
+
* parsing/encoding multiple different values.
|
|
11288
|
+
*
|
|
11289
|
+
* @see https://remix.run/utils/cookies#cookie-api
|
|
11290
|
+
*/
|
|
11291
|
+
|
|
10204
11292
|
/**
|
|
10205
11293
|
* Creates a logical container for managing a browser cookie from the server.
|
|
10206
11294
|
*/
|
|
@@ -10231,7 +11319,17 @@ const createCookie = function createCookie(name, cookieOptions) {
|
|
|
10231
11319
|
async parse(cookieHeader, parseOptions) {
|
|
10232
11320
|
if (!cookieHeader) return null;
|
|
10233
11321
|
let cookies = parse(cookieHeader, _extends({}, options, parseOptions));
|
|
10234
|
-
|
|
11322
|
+
if (name in cookies) {
|
|
11323
|
+
let value = cookies[name];
|
|
11324
|
+
if (typeof value === "string" && value !== "") {
|
|
11325
|
+
let decoded = await decodeCookieValue(value, secrets);
|
|
11326
|
+
return decoded;
|
|
11327
|
+
} else {
|
|
11328
|
+
return "";
|
|
11329
|
+
}
|
|
11330
|
+
} else {
|
|
11331
|
+
return null;
|
|
11332
|
+
}
|
|
10235
11333
|
},
|
|
10236
11334
|
async serialize(value, serializeOptions) {
|
|
10237
11335
|
return serialize(name, value === "" ? "" : await encodeCookieValue(value, secrets), _extends({}, options, serializeOptions));
|
|
@@ -10275,6 +11373,7 @@ function decodeData(value) {
|
|
|
10275
11373
|
return {};
|
|
10276
11374
|
}
|
|
10277
11375
|
}
|
|
11376
|
+
|
|
10278
11377
|
// See: https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/es.escape.js
|
|
10279
11378
|
function myEscape(value) {
|
|
10280
11379
|
let str = value.toString();
|
|
@@ -10301,6 +11400,7 @@ function hex(code, length) {
|
|
|
10301
11400
|
while (result.length < length) result = "0" + result;
|
|
10302
11401
|
return result;
|
|
10303
11402
|
}
|
|
11403
|
+
|
|
10304
11404
|
// See: https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/es.unescape.js
|
|
10305
11405
|
function myUnescape(value) {
|
|
10306
11406
|
let str = value.toString();
|
|
@@ -10336,7 +11436,10 @@ function warnOnceAboutExpiresCookie(name, expires) {
|
|
|
10336
11436
|
|
|
10337
11437
|
function createEntryRouteModules(manifest) {
|
|
10338
11438
|
return Object.keys(manifest).reduce((memo, routeId) => {
|
|
10339
|
-
|
|
11439
|
+
let route = manifest[routeId];
|
|
11440
|
+
if (route) {
|
|
11441
|
+
memo[routeId] = route.module;
|
|
11442
|
+
}
|
|
10340
11443
|
return memo;
|
|
10341
11444
|
}, {});
|
|
10342
11445
|
}
|
|
@@ -10344,12 +11447,12 @@ function createEntryRouteModules(manifest) {
|
|
|
10344
11447
|
/**
|
|
10345
11448
|
* The mode to use when running the server.
|
|
10346
11449
|
*/
|
|
10347
|
-
|
|
10348
|
-
(function (ServerMode) {
|
|
11450
|
+
let ServerMode = /*#__PURE__*/function (ServerMode) {
|
|
10349
11451
|
ServerMode["Development"] = "development";
|
|
10350
11452
|
ServerMode["Production"] = "production";
|
|
10351
11453
|
ServerMode["Test"] = "test";
|
|
10352
|
-
|
|
11454
|
+
return ServerMode;
|
|
11455
|
+
}({});
|
|
10353
11456
|
function isServerMode(value) {
|
|
10354
11457
|
return value === ServerMode.Development || value === ServerMode.Production || value === ServerMode.Test;
|
|
10355
11458
|
}
|
|
@@ -10395,6 +11498,7 @@ function isServerMode(value) {
|
|
|
10395
11498
|
* because it came first, and that just wouldn't be fair to let errors cut in
|
|
10396
11499
|
* line.
|
|
10397
11500
|
*/
|
|
11501
|
+
|
|
10398
11502
|
function sanitizeError(error, serverMode) {
|
|
10399
11503
|
if (error instanceof Error && serverMode !== ServerMode.Development) {
|
|
10400
11504
|
let sanitized = new Error("Unexpected Server Error");
|
|
@@ -10411,6 +11515,10 @@ function sanitizeErrors(errors, serverMode) {
|
|
|
10411
11515
|
});
|
|
10412
11516
|
}, {});
|
|
10413
11517
|
}
|
|
11518
|
+
|
|
11519
|
+
// must be type alias due to inference issues on interfaces
|
|
11520
|
+
// https://github.com/microsoft/TypeScript/issues/15300
|
|
11521
|
+
|
|
10414
11522
|
function serializeError(error, serverMode) {
|
|
10415
11523
|
let sanitized = sanitizeError(error, serverMode);
|
|
10416
11524
|
return {
|
|
@@ -10456,27 +11564,11 @@ function matchServerRoutes(routes, pathname, basename) {
|
|
|
10456
11564
|
}
|
|
10457
11565
|
|
|
10458
11566
|
/**
|
|
10459
|
-
*
|
|
10460
|
-
*
|
|
10461
|
-
*
|
|
10462
|
-
*
|
|
11567
|
+
* An object of unknown type for route loaders and actions provided by the
|
|
11568
|
+
* server's `getLoadContext()` function. This is defined as an empty interface
|
|
11569
|
+
* specifically so apps can leverage declaration merging to augment this type
|
|
11570
|
+
* globally: https://www.typescriptlang.org/docs/handbook/declaration-merging.html
|
|
10463
11571
|
*/
|
|
10464
|
-
const json = function json(data, init) {
|
|
10465
|
-
if (init === void 0) {
|
|
10466
|
-
init = {};
|
|
10467
|
-
}
|
|
10468
|
-
return json$1(data, init);
|
|
10469
|
-
};
|
|
10470
|
-
function isResponse(value) {
|
|
10471
|
-
return value != null && typeof value.status === "number" && typeof value.statusText === "string" && typeof value.headers === "object" && typeof value.body !== "undefined";
|
|
10472
|
-
}
|
|
10473
|
-
const redirectStatusCodes = new Set([301, 302, 303, 307, 308]);
|
|
10474
|
-
function isRedirectStatusCode(statusCode) {
|
|
10475
|
-
return redirectStatusCodes.has(statusCode);
|
|
10476
|
-
}
|
|
10477
|
-
function isRedirectResponse(response) {
|
|
10478
|
-
return isRedirectStatusCode(response.status);
|
|
10479
|
-
}
|
|
10480
11572
|
|
|
10481
11573
|
// Need to use RR's version here to permit the optional context even
|
|
10482
11574
|
// though we know it'll always be provided in remix
|
|
@@ -10486,12 +11578,14 @@ async function callRouteHandler(handler, args) {
|
|
|
10486
11578
|
params: args.params,
|
|
10487
11579
|
context: args.context
|
|
10488
11580
|
});
|
|
11581
|
+
|
|
10489
11582
|
// If they returned a redirect via data(), re-throw it as a Response
|
|
10490
11583
|
if (isDataWithResponseInit(result) && result.init && result.init.status && isRedirectStatusCode(result.init.status)) {
|
|
10491
11584
|
throw new Response(null, result.init);
|
|
10492
11585
|
}
|
|
10493
11586
|
return result;
|
|
10494
11587
|
}
|
|
11588
|
+
|
|
10495
11589
|
// TODO: Document these search params better
|
|
10496
11590
|
// and stop stripping these in V2. These break
|
|
10497
11591
|
// support for running in a SW and also expose
|
|
@@ -10538,7 +11632,7 @@ function stripRoutesParam(request) {
|
|
|
10538
11632
|
|
|
10539
11633
|
function invariant(value, message) {
|
|
10540
11634
|
if (value === false || value === null || typeof value === "undefined") {
|
|
10541
|
-
console.error("The following error is a bug in
|
|
11635
|
+
console.error("The following error is a bug in React Router; please open an issue! https://github.com/remix-run/react-router/issues/new/choose");
|
|
10542
11636
|
throw new Error(message);
|
|
10543
11637
|
}
|
|
10544
11638
|
}
|
|
@@ -10546,14 +11640,17 @@ function invariant(value, message) {
|
|
|
10546
11640
|
function groupRoutesByParentId(manifest) {
|
|
10547
11641
|
let routes = {};
|
|
10548
11642
|
Object.values(manifest).forEach(route => {
|
|
10549
|
-
|
|
10550
|
-
|
|
10551
|
-
routes[parentId]
|
|
11643
|
+
if (route) {
|
|
11644
|
+
let parentId = route.parentId || "";
|
|
11645
|
+
if (!routes[parentId]) {
|
|
11646
|
+
routes[parentId] = [];
|
|
11647
|
+
}
|
|
11648
|
+
routes[parentId].push(route);
|
|
10552
11649
|
}
|
|
10553
|
-
routes[parentId].push(route);
|
|
10554
11650
|
});
|
|
10555
11651
|
return routes;
|
|
10556
11652
|
}
|
|
11653
|
+
|
|
10557
11654
|
// Create a map of routes by parentId to use recursively instead of
|
|
10558
11655
|
// repeatedly filtering the manifest.
|
|
10559
11656
|
function createRoutes(manifest, parentId, routesByParentId) {
|
|
@@ -10567,6 +11664,7 @@ function createRoutes(manifest, parentId, routesByParentId) {
|
|
|
10567
11664
|
children: createRoutes(manifest, route.id, routesByParentId)
|
|
10568
11665
|
}));
|
|
10569
11666
|
}
|
|
11667
|
+
|
|
10570
11668
|
// Convert the Remix ServerManifest into DataRouteObject's for use with
|
|
10571
11669
|
// createStaticHandler
|
|
10572
11670
|
function createStaticHandlerDataRoutes(manifest, future, parentId, routesByParentId) {
|
|
@@ -10621,8 +11719,10 @@ function createStaticHandlerDataRoutes(manifest, future, parentId, routesByParen
|
|
|
10621
11719
|
|
|
10622
11720
|
// This escapeHtml utility is based on https://github.com/zertosh/htmlescape
|
|
10623
11721
|
// License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE
|
|
11722
|
+
|
|
10624
11723
|
// We've chosen to inline the utility here to reduce the number of npm dependencies we have,
|
|
10625
11724
|
// slightly decrease the code size compared the original package and make it esm compatible.
|
|
11725
|
+
|
|
10626
11726
|
const ESCAPE_LOOKUP = {
|
|
10627
11727
|
"&": "\\u0026",
|
|
10628
11728
|
">": "\\u003e",
|
|
@@ -10679,16 +11779,20 @@ function getDocumentHeaders(build, context) {
|
|
|
10679
11779
|
let {
|
|
10680
11780
|
id
|
|
10681
11781
|
} = match.route;
|
|
10682
|
-
let
|
|
11782
|
+
let route = build.routes[id];
|
|
11783
|
+
!route ? process.env.NODE_ENV !== "production" ? invariant(false, "Route with id \"" + id + "\" not found in build") : invariant(false) : void 0;
|
|
11784
|
+
let routeModule = route.module;
|
|
10683
11785
|
let loaderHeaders = context.loaderHeaders[id] || new Headers();
|
|
10684
11786
|
let actionHeaders = context.actionHeaders[id] || new Headers();
|
|
11787
|
+
|
|
10685
11788
|
// Only expose errorHeaders to the leaf headers() function to
|
|
10686
11789
|
// avoid duplication via parentHeaders
|
|
10687
|
-
let includeErrorHeaders = errorHeaders !=
|
|
11790
|
+
let includeErrorHeaders = errorHeaders != null && idx === matches.length - 1;
|
|
10688
11791
|
// Only prepend cookies from errorHeaders at the leaf renderable route
|
|
10689
11792
|
// when it's not the same as loaderHeaders/actionHeaders to avoid
|
|
10690
11793
|
// duplicate cookies
|
|
10691
11794
|
let includeErrorCookies = includeErrorHeaders && errorHeaders !== loaderHeaders && errorHeaders !== actionHeaders;
|
|
11795
|
+
|
|
10692
11796
|
// Use the parent headers for any route without a `headers` export
|
|
10693
11797
|
if (routeModule.headers == null) {
|
|
10694
11798
|
let headers = new Headers(parentHeaders);
|
|
@@ -10705,6 +11809,7 @@ function getDocumentHeaders(build, context) {
|
|
|
10705
11809
|
actionHeaders,
|
|
10706
11810
|
errorHeaders: includeErrorHeaders ? errorHeaders : undefined
|
|
10707
11811
|
}) : routeModule.headers : undefined);
|
|
11812
|
+
|
|
10708
11813
|
// Automatically preserve Set-Cookie headers from bubbled responses,
|
|
10709
11814
|
// loaders, errors, and parent routes
|
|
10710
11815
|
if (includeErrorCookies) {
|
|
@@ -10746,6 +11851,7 @@ function getSingleFetchDataStrategy(_temp) {
|
|
|
10746
11851
|
if (isActionDataRequest && request.method === "GET") {
|
|
10747
11852
|
return {};
|
|
10748
11853
|
}
|
|
11854
|
+
|
|
10749
11855
|
// Only run opt-in loaders when fine-grained revalidation is enabled
|
|
10750
11856
|
let matchesToLoad = loadRouteIds ? matches.filter(m => loadRouteIds.includes(m.route.id)) : matches;
|
|
10751
11857
|
let results = await Promise.all(matchesToLoad.map(match => match.resolve()));
|
|
@@ -10771,6 +11877,7 @@ async function singleFetchAction(build, serverMode, staticHandler, request, hand
|
|
|
10771
11877
|
isActionDataRequest: true
|
|
10772
11878
|
})
|
|
10773
11879
|
});
|
|
11880
|
+
|
|
10774
11881
|
// Unlike `handleDataRequest`, when singleFetch is enabled, query does
|
|
10775
11882
|
// let non-Response return values through
|
|
10776
11883
|
if (isResponse(result)) {
|
|
@@ -10789,6 +11896,7 @@ async function singleFetchAction(build, serverMode, staticHandler, request, hand
|
|
|
10789
11896
|
status: SINGLE_FETCH_REDIRECT_STATUS
|
|
10790
11897
|
};
|
|
10791
11898
|
}
|
|
11899
|
+
|
|
10792
11900
|
// Sanitize errors outside of development environments
|
|
10793
11901
|
if (context.errors) {
|
|
10794
11902
|
Object.values(context.errors).forEach(err => {
|
|
@@ -10861,6 +11969,7 @@ async function singleFetchLoaders(build, serverMode, staticHandler, request, han
|
|
|
10861
11969
|
status: SINGLE_FETCH_REDIRECT_STATUS
|
|
10862
11970
|
};
|
|
10863
11971
|
}
|
|
11972
|
+
|
|
10864
11973
|
// Sanitize errors outside of development environments
|
|
10865
11974
|
if (context.errors) {
|
|
10866
11975
|
Object.values(context.errors).forEach(err => {
|
|
@@ -10871,6 +11980,7 @@ async function singleFetchLoaders(build, serverMode, staticHandler, request, han
|
|
|
10871
11980
|
});
|
|
10872
11981
|
context.errors = sanitizeErrors(context.errors, serverMode);
|
|
10873
11982
|
}
|
|
11983
|
+
|
|
10874
11984
|
// Aggregate results based on the matches we intended to load since we get
|
|
10875
11985
|
// `null` values back in `context.loaderData` for routes we didn't load
|
|
10876
11986
|
let results = {};
|
|
@@ -10929,6 +12039,7 @@ function getSingleFetchRedirect(status, headers, basename) {
|
|
|
10929
12039
|
replace: headers.has("X-Remix-Replace")
|
|
10930
12040
|
};
|
|
10931
12041
|
}
|
|
12042
|
+
|
|
10932
12043
|
// Note: If you change this function please change the corresponding
|
|
10933
12044
|
// decodeViaTurboStream function in server-runtime
|
|
10934
12045
|
function encodeViaTurboStream(data, requestSignal, streamTimeout, serverMode) {
|
|
@@ -11038,6 +12149,7 @@ const createRequestHandler = (build, mode) => {
|
|
|
11038
12149
|
request
|
|
11039
12150
|
});
|
|
11040
12151
|
};
|
|
12152
|
+
|
|
11041
12153
|
// Manifest request for fog of war
|
|
11042
12154
|
let manifestUrl = (((_build$basename = _build.basename) != null ? _build$basename : "/") + "/__manifest").replace(/\/+/g, "/");
|
|
11043
12155
|
if (url.pathname === manifestUrl) {
|
|
@@ -11107,15 +12219,18 @@ async function handleManifestRequest(build, routes, url) {
|
|
|
11107
12219
|
if (matches) {
|
|
11108
12220
|
for (let match of matches) {
|
|
11109
12221
|
let routeId = match.route.id;
|
|
11110
|
-
|
|
12222
|
+
let route = build.assets.routes[routeId];
|
|
12223
|
+
if (route) {
|
|
12224
|
+
patches[routeId] = route;
|
|
12225
|
+
}
|
|
11111
12226
|
}
|
|
11112
12227
|
}
|
|
11113
12228
|
}
|
|
11114
|
-
return json(patches, {
|
|
12229
|
+
return Response.json(patches, {
|
|
11115
12230
|
headers: {
|
|
11116
12231
|
"Cache-Control": "public, max-age=31536000, immutable"
|
|
11117
12232
|
}
|
|
11118
|
-
});
|
|
12233
|
+
});
|
|
11119
12234
|
}
|
|
11120
12235
|
return new Response("Invalid Request", {
|
|
11121
12236
|
status: 400
|
|
@@ -11127,10 +12242,12 @@ async function handleSingleFetchRequest(serverMode, build, staticHandler, reques
|
|
|
11127
12242
|
headers,
|
|
11128
12243
|
status
|
|
11129
12244
|
} = request.method !== "GET" ? await singleFetchAction(build, serverMode, staticHandler, request, handlerUrl, loadContext, handleError) : await singleFetchLoaders(build, serverMode, staticHandler, request, handlerUrl, loadContext, handleError);
|
|
12245
|
+
|
|
11130
12246
|
// Mark all successful responses with a header so we can identify in-flight
|
|
11131
12247
|
// network errors that are missing this header
|
|
11132
12248
|
let resultHeaders = new Headers(headers);
|
|
11133
12249
|
resultHeaders.set("X-Remix-Response", "yes");
|
|
12250
|
+
|
|
11134
12251
|
// 304 responses should not have a body
|
|
11135
12252
|
if (status === 304) {
|
|
11136
12253
|
return new Response(null, {
|
|
@@ -11138,6 +12255,7 @@ async function handleSingleFetchRequest(serverMode, build, staticHandler, reques
|
|
|
11138
12255
|
headers: resultHeaders
|
|
11139
12256
|
});
|
|
11140
12257
|
}
|
|
12258
|
+
|
|
11141
12259
|
// We use a less-descriptive `text/x-script` here instead of something like
|
|
11142
12260
|
// `text/x-turbo` to enable compression when deployed via Cloudflare. See:
|
|
11143
12261
|
// - https://github.com/remix-run/remix/issues/9884
|
|
@@ -11164,6 +12282,7 @@ async function handleDocumentRequest(serverMode, build, staticHandler, request,
|
|
|
11164
12282
|
return context;
|
|
11165
12283
|
}
|
|
11166
12284
|
let headers = getDocumentHeaders(build, context);
|
|
12285
|
+
|
|
11167
12286
|
// 304 responses should not have a body or a content-type
|
|
11168
12287
|
if (context.statusCode === 304) {
|
|
11169
12288
|
return new Response(null, {
|
|
@@ -11171,6 +12290,7 @@ async function handleDocumentRequest(serverMode, build, staticHandler, request,
|
|
|
11171
12290
|
headers
|
|
11172
12291
|
});
|
|
11173
12292
|
}
|
|
12293
|
+
|
|
11174
12294
|
// Sanitize errors outside of development environments
|
|
11175
12295
|
if (context.errors) {
|
|
11176
12296
|
Object.values(context.errors).forEach(err => {
|
|
@@ -11181,6 +12301,7 @@ async function handleDocumentRequest(serverMode, build, staticHandler, request,
|
|
|
11181
12301
|
});
|
|
11182
12302
|
context.errors = sanitizeErrors(context.errors, serverMode);
|
|
11183
12303
|
}
|
|
12304
|
+
|
|
11184
12305
|
// Server UI state to send to the client.
|
|
11185
12306
|
// - When single fetch is enabled, this is streamed down via `serverHandoffStream`
|
|
11186
12307
|
// - Otherwise it's stringified into `serverHandoffString`
|
|
@@ -11212,6 +12333,7 @@ async function handleDocumentRequest(serverMode, build, staticHandler, request,
|
|
|
11212
12333
|
} catch (error) {
|
|
11213
12334
|
handleError(error);
|
|
11214
12335
|
let errorForSecondRender = error;
|
|
12336
|
+
|
|
11215
12337
|
// If they threw a response, unwrap it into an ErrorResponse like we would
|
|
11216
12338
|
// have for a loader/action
|
|
11217
12339
|
if (isResponse(error)) {
|
|
@@ -11222,12 +12344,15 @@ async function handleDocumentRequest(serverMode, build, staticHandler, request,
|
|
|
11222
12344
|
// If we can't unwrap the response - just leave it as-is
|
|
11223
12345
|
}
|
|
11224
12346
|
}
|
|
12347
|
+
|
|
11225
12348
|
// Get a new StaticHandlerContext that contains the error at the right boundary
|
|
11226
12349
|
context = getStaticContextFromError(staticHandler.dataRoutes, context, errorForSecondRender);
|
|
12350
|
+
|
|
11227
12351
|
// Sanitize errors outside of development environments
|
|
11228
12352
|
if (context.errors) {
|
|
11229
12353
|
context.errors = sanitizeErrors(context.errors, serverMode);
|
|
11230
12354
|
}
|
|
12355
|
+
|
|
11231
12356
|
// Get a new entryContext for the second render pass
|
|
11232
12357
|
// Server UI state to send to the client.
|
|
11233
12358
|
// - When single fetch is enabled, this is streamed down via `serverHandoffStream`
|
|
@@ -11284,7 +12409,7 @@ async function handleResourceRequest(serverMode, build, staticHandler, routeId,
|
|
|
11284
12409
|
}
|
|
11285
12410
|
}
|
|
11286
12411
|
function errorResponseToJson(errorResponse, serverMode) {
|
|
11287
|
-
return json
|
|
12412
|
+
return Response.json(serializeError(
|
|
11288
12413
|
// @ts-expect-error This is "private" from users but intended for internal use
|
|
11289
12414
|
errorResponse.error || new Error("Unexpected Server Error"), serverMode), {
|
|
11290
12415
|
status: errorResponse.status,
|
|
@@ -11299,6 +12424,7 @@ function returnLastResortErrorResponse(error, serverMode) {
|
|
|
11299
12424
|
if (serverMode !== ServerMode.Production) {
|
|
11300
12425
|
message += "\n\n" + String(error);
|
|
11301
12426
|
}
|
|
12427
|
+
|
|
11302
12428
|
// Good grief folks, get your act together 😂!
|
|
11303
12429
|
return new Response(message, {
|
|
11304
12430
|
status: 500,
|
|
@@ -11314,6 +12440,16 @@ function unwrapResponse(response) {
|
|
|
11314
12440
|
return contentType && /\bapplication\/json\b/.test(contentType) ? response.body == null ? null : response.json() : response.text();
|
|
11315
12441
|
}
|
|
11316
12442
|
|
|
12443
|
+
/**
|
|
12444
|
+
* An object of name/value pairs to be used in the session.
|
|
12445
|
+
*/
|
|
12446
|
+
|
|
12447
|
+
/**
|
|
12448
|
+
* Session persists data across HTTP requests.
|
|
12449
|
+
*
|
|
12450
|
+
* @see https://remix.run/utils/sessions#session-api
|
|
12451
|
+
*/
|
|
12452
|
+
|
|
11317
12453
|
function flash(name) {
|
|
11318
12454
|
return "__flash_" + name + "__";
|
|
11319
12455
|
}
|
|
@@ -11372,6 +12508,25 @@ const createSession = function createSession(initialData, id) {
|
|
|
11372
12508
|
const isSession = object => {
|
|
11373
12509
|
return object != null && typeof object.id === "string" && typeof object.data !== "undefined" && typeof object.has === "function" && typeof object.get === "function" && typeof object.set === "function" && typeof object.flash === "function" && typeof object.unset === "function";
|
|
11374
12510
|
};
|
|
12511
|
+
|
|
12512
|
+
/**
|
|
12513
|
+
* SessionStorage stores session data between HTTP requests and knows how to
|
|
12514
|
+
* parse and create cookies.
|
|
12515
|
+
*
|
|
12516
|
+
* A SessionStorage creates Session objects using a `Cookie` header as input.
|
|
12517
|
+
* Then, later it generates the `Set-Cookie` header to be used in the response.
|
|
12518
|
+
*/
|
|
12519
|
+
|
|
12520
|
+
/**
|
|
12521
|
+
* SessionIdStorageStrategy is designed to allow anyone to easily build their
|
|
12522
|
+
* own SessionStorage using `createSessionStorage(strategy)`.
|
|
12523
|
+
*
|
|
12524
|
+
* This strategy describes a common scenario where the session id is stored in
|
|
12525
|
+
* a cookie but the actual session data is stored elsewhere, usually in a
|
|
12526
|
+
* database or on disk. A set of create, read, update, and delete operations
|
|
12527
|
+
* are provided for managing the session data.
|
|
12528
|
+
*/
|
|
12529
|
+
|
|
11375
12530
|
/**
|
|
11376
12531
|
* Creates a SessionStorage object using a SessionIdStorageStrategy.
|
|
11377
12532
|
*
|
|
@@ -11486,6 +12641,7 @@ function createMemorySessionStorage(_temp) {
|
|
|
11486
12641
|
if (!expires || expires > new Date()) {
|
|
11487
12642
|
return data;
|
|
11488
12643
|
}
|
|
12644
|
+
|
|
11489
12645
|
// Remove expired session data.
|
|
11490
12646
|
if (expires) map.delete(id);
|
|
11491
12647
|
}
|
|
@@ -11539,5 +12695,5 @@ function deserializeErrors(errors) {
|
|
|
11539
12695
|
return serialized;
|
|
11540
12696
|
}
|
|
11541
12697
|
|
|
11542
|
-
export { Await, BrowserRouter, Form, HashRouter, IDLE_BLOCKER, IDLE_FETCHER, IDLE_NAVIGATION, Link, Links, MemoryRouter, Meta, NavLink, Navigate, Action as NavigationType, Outlet, PrefetchPageLinks, Route, Router, RouterProvider, Routes, Scripts, ScrollRestoration, ServerRouter, StaticRouter, StaticRouterProvider, DataRouterContext as UNSAFE_DataRouterContext, DataRouterStateContext as UNSAFE_DataRouterStateContext, ErrorResponseImpl as UNSAFE_ErrorResponseImpl, FetchersContext as UNSAFE_FetchersContext, FrameworkContext as UNSAFE_FrameworkContext, LocationContext as UNSAFE_LocationContext, NavigationContext as UNSAFE_NavigationContext, RemixErrorBoundary as UNSAFE_RemixErrorBoundary, RouteContext as UNSAFE_RouteContext, ServerMode as UNSAFE_ServerMode, SingleFetchRedirectSymbol as UNSAFE_SingleFetchRedirectSymbol, ViewTransitionContext as UNSAFE_ViewTransitionContext, createBrowserHistory as UNSAFE_createBrowserHistory, createClientRoutes as UNSAFE_createClientRoutes, createClientRoutesWithHMRRevalidationOptOut as UNSAFE_createClientRoutesWithHMRRevalidationOptOut, createRouter as UNSAFE_createRouter, decodeViaTurboStream as UNSAFE_decodeViaTurboStream, deserializeErrors as UNSAFE_deserializeErrors, getPatchRoutesOnNavigationFunction as UNSAFE_getPatchRoutesOnNavigationFunction, getSingleFetchDataStrategy$1 as UNSAFE_getSingleFetchDataStrategy, invariant$2 as UNSAFE_invariant, mapRouteProperties as UNSAFE_mapRouteProperties, shouldHydrateRouteLoader as UNSAFE_shouldHydrateRouteLoader, useFogOFWarDiscovery as UNSAFE_useFogOFWarDiscovery, useScrollRestoration as UNSAFE_useScrollRestoration, createBrowserRouter, createCookie, createCookieSessionStorage, createHashRouter, createMemoryRouter, createMemorySessionStorage, createPath, createRequestHandler, createRoutesFromChildren, createRoutesFromChildren as createRoutesFromElements, createRoutesStub, createSearchParams, createSession, createSessionStorage, createStaticHandler, createStaticRouter, data, generatePath, isCookie, isRouteErrorResponse, isSession,
|
|
12698
|
+
export { Await, BrowserRouter, Form, HashRouter, IDLE_BLOCKER, IDLE_FETCHER, IDLE_NAVIGATION, Link, Links, MemoryRouter, Meta, NavLink, Navigate, Action as NavigationType, Outlet, PrefetchPageLinks, Route, Router, RouterProvider, Routes, Scripts, ScrollRestoration, ServerRouter, StaticRouter, StaticRouterProvider, DataRouterContext as UNSAFE_DataRouterContext, DataRouterStateContext as UNSAFE_DataRouterStateContext, ErrorResponseImpl as UNSAFE_ErrorResponseImpl, FetchersContext as UNSAFE_FetchersContext, FrameworkContext as UNSAFE_FrameworkContext, LocationContext as UNSAFE_LocationContext, NavigationContext as UNSAFE_NavigationContext, RemixErrorBoundary as UNSAFE_RemixErrorBoundary, RouteContext as UNSAFE_RouteContext, ServerMode as UNSAFE_ServerMode, SingleFetchRedirectSymbol as UNSAFE_SingleFetchRedirectSymbol, ViewTransitionContext as UNSAFE_ViewTransitionContext, createBrowserHistory as UNSAFE_createBrowserHistory, createClientRoutes as UNSAFE_createClientRoutes, createClientRoutesWithHMRRevalidationOptOut as UNSAFE_createClientRoutesWithHMRRevalidationOptOut, createRouter as UNSAFE_createRouter, decodeViaTurboStream as UNSAFE_decodeViaTurboStream, deserializeErrors as UNSAFE_deserializeErrors, getPatchRoutesOnNavigationFunction as UNSAFE_getPatchRoutesOnNavigationFunction, getSingleFetchDataStrategy$1 as UNSAFE_getSingleFetchDataStrategy, invariant$2 as UNSAFE_invariant, mapRouteProperties as UNSAFE_mapRouteProperties, shouldHydrateRouteLoader as UNSAFE_shouldHydrateRouteLoader, useFogOFWarDiscovery as UNSAFE_useFogOFWarDiscovery, useScrollRestoration as UNSAFE_useScrollRestoration, createBrowserRouter, createCookie, createCookieSessionStorage, createHashRouter, createMemoryRouter, createMemorySessionStorage, createPath, createRequestHandler, createRoutesFromChildren, createRoutesFromChildren as createRoutesFromElements, createRoutesStub, createSearchParams, createSession, createSessionStorage, createStaticHandler, createStaticRouter, data, generatePath, isCookie, isRouteErrorResponse, isSession, matchPath, matchRoutes, parsePath, redirect, redirectDocument, renderMatches, replace, resolvePath, HistoryRouter as unstable_HistoryRouter, setDevServerHooks as unstable_setDevServerHooks, usePrompt as unstable_usePrompt, useActionData, useAsyncError, useAsyncValue, useBeforeUnload, useBlocker, useFetcher, useFetchers, useFormAction, useHref, useInRouterContext, useLinkClickHandler, useLoaderData, useLocation, useMatch, useMatches, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useRouteLoaderData, useRoutes, useSearchParams, useSubmit, useViewTransitionState };
|
|
11543
12699
|
//# sourceMappingURL=index.mjs.map
|