@remix-run/router 1.8.0 → 1.9.0-pre.1

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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @remix-run/router v1.8.0
2
+ * @remix-run/router v1.9.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -47,25 +47,23 @@
47
47
  * The pathname, search, and hash values of a URL.
48
48
  */
49
49
 
50
+ // TODO: (v7) Change the Location generic default from `any` to `unknown` and
51
+ // remove Remix `useLocation` wrapper.
50
52
  /**
51
53
  * An entry in a history stack. A location contains information about the
52
54
  * URL path, as well as possibly some arbitrary state and a key.
53
55
  */
54
-
55
56
  /**
56
57
  * A change to the current location.
57
58
  */
58
-
59
59
  /**
60
60
  * A function that receives notifications about location changes.
61
61
  */
62
-
63
62
  /**
64
63
  * Describes a location that is the destination of some navigation, either via
65
64
  * `history.push` or `history.replace`. May be either a URL or the pieces of a
66
65
  * URL path.
67
66
  */
68
-
69
67
  /**
70
68
  * A history is an interface to the navigation stack. The history serves as the
71
69
  * source of truth for the current location, as well as provides a set of
@@ -74,7 +72,6 @@
74
72
  * It is similar to the DOM's `window.history` object, but with a smaller, more
75
73
  * focused API.
76
74
  */
77
-
78
75
  const PopStateEventType = "popstate";
79
76
  //#endregion
80
77
 
@@ -607,28 +604,28 @@
607
604
  * this as a private implementation detail in case they diverge in the future.
608
605
  */
609
606
 
607
+ // TODO: (v7) Change the defaults from any to unknown in and remove Remix wrappers:
608
+ // ActionFunction, ActionFunctionArgs, LoaderFunction, LoaderFunctionArgs
610
609
  /**
611
610
  * Arguments passed to loader functions
612
611
  */
613
-
614
612
  /**
615
613
  * Arguments passed to action functions
616
614
  */
617
-
618
615
  /**
619
616
  * Loaders and actions can return anything except `undefined` (`null` is a
620
617
  * valid return value if there is no data to return). Responses are preferred
621
618
  * and will ease any future migration to Remix
622
619
  */
623
-
624
620
  /**
625
621
  * Route loader function signature
626
622
  */
627
-
628
623
  /**
629
624
  * Route action function signature
630
625
  */
631
-
626
+ /**
627
+ * Arguments passed to shouldRevalidate function
628
+ */
632
629
  /**
633
630
  * Route shouldRevalidate function signature. This runs after any submission
634
631
  * (navigation or fetcher), so we flatten the navigation/fetcher submission
@@ -636,25 +633,21 @@
636
633
  * or a fetcher, what really matters is the URLs and the formData since loaders
637
634
  * have to re-run based on the data models that were potentially mutated.
638
635
  */
639
-
640
636
  /**
641
637
  * Function provided by the framework-aware layers to set `hasErrorBoundary`
642
638
  * from the framework-aware `errorElement` prop
643
639
  *
644
640
  * @deprecated Use `mapRouteProperties` instead
645
641
  */
646
-
647
642
  /**
648
643
  * Function provided by the framework-aware layers to set any framework-specific
649
644
  * properties from framework-agnostic properties
650
645
  */
651
-
652
646
  /**
653
647
  * Keys we cannot change from within a lazy() function. We spread all other keys
654
648
  * onto the route. Either they're meaningful to the router, or they'll get
655
649
  * ignored.
656
650
  */
657
-
658
651
  const immutableRouteKeys = new Set(["lazy", "caseSensitive", "path", "id", "index", "children"]);
659
652
 
660
653
  /**
@@ -771,6 +764,20 @@
771
764
  }
772
765
  return matches;
773
766
  }
767
+ function convertRouteMatchToUiMatch(match, loaderData) {
768
+ let {
769
+ route,
770
+ pathname,
771
+ params
772
+ } = match;
773
+ return {
774
+ id: route.id,
775
+ pathname,
776
+ params,
777
+ data: loaderData[route.id],
778
+ handle: route.handle
779
+ };
780
+ }
774
781
  function flattenRoutes(routes, branches, parentsMeta, parentPath) {
775
782
  if (branches === void 0) {
776
783
  branches = [];
@@ -1467,7 +1474,7 @@
1467
1474
  * @private
1468
1475
  * Utility class we use to hold auto-unwrapped 4xx/5xx Response bodies
1469
1476
  */
1470
- class ErrorResponse {
1477
+ class ErrorResponseImpl {
1471
1478
  constructor(status, statusText, data, internal) {
1472
1479
  if (internal === void 0) {
1473
1480
  internal = false;
@@ -1484,6 +1491,9 @@
1484
1491
  }
1485
1492
  }
1486
1493
 
1494
+ // We don't want the class exported since usage of it at runtime is an
1495
+ // implementation detail, but we do want to export the shape so folks can
1496
+ // build their own abstractions around instances via isRouteErrorResponse()
1487
1497
  /**
1488
1498
  * Check if the given error is an ErrorResponse generated from a 4xx/5xx
1489
1499
  * Response thrown from an action/loader
@@ -2468,8 +2478,7 @@
2468
2478
  fetchers: new Map(state.fetchers)
2469
2479
  });
2470
2480
  return startRedirectNavigation(state, actionResult, {
2471
- submission,
2472
- isFetchActionRedirect: true
2481
+ fetcherSubmission: submission
2473
2482
  });
2474
2483
  }
2475
2484
  }
@@ -2684,18 +2693,15 @@
2684
2693
  async function startRedirectNavigation(state, redirect, _temp) {
2685
2694
  let {
2686
2695
  submission,
2687
- replace,
2688
- isFetchActionRedirect
2696
+ fetcherSubmission,
2697
+ replace
2689
2698
  } = _temp === void 0 ? {} : _temp;
2690
2699
  if (redirect.revalidate) {
2691
2700
  isRevalidationRequired = true;
2692
2701
  }
2693
- let redirectLocation = createLocation(state.location, redirect.location, // TODO: This can be removed once we get rid of useTransition in Remix v2
2694
- _extends({
2702
+ let redirectLocation = createLocation(state.location, redirect.location, {
2695
2703
  _isRedirect: true
2696
- }, isFetchActionRedirect ? {
2697
- _isFetchActionRedirect: true
2698
- } : {}));
2704
+ });
2699
2705
  invariant(redirectLocation, "Expected a location on the redirect navigation");
2700
2706
  if (isBrowser) {
2701
2707
  let isDocumentReload = false;
@@ -2727,11 +2733,19 @@
2727
2733
 
2728
2734
  // Use the incoming submission if provided, fallback on the active one in
2729
2735
  // state.navigation
2730
- let activeSubmission = submission || getSubmissionFromNavigation(state.navigation);
2736
+ let {
2737
+ formMethod,
2738
+ formAction,
2739
+ formEncType
2740
+ } = state.navigation;
2741
+ if (!submission && !fetcherSubmission && formMethod && formAction && formEncType) {
2742
+ submission = getSubmissionFromNavigation(state.navigation);
2743
+ }
2731
2744
 
2732
2745
  // If this was a 307/308 submission we want to preserve the HTTP method and
2733
2746
  // re-submit the GET/POST/PUT/PATCH/DELETE as a submission navigation to the
2734
2747
  // redirected location
2748
+ let activeSubmission = submission || fetcherSubmission;
2735
2749
  if (redirectPreserveMethodStatusCodes.has(redirect.status) && activeSubmission && isMutationMethod(activeSubmission.formMethod)) {
2736
2750
  await startNavigation(redirectHistoryAction, redirectLocation, {
2737
2751
  submission: _extends({}, activeSubmission, {
@@ -2740,20 +2754,14 @@
2740
2754
  // Preserve this flag across redirects
2741
2755
  preventScrollReset: pendingPreventScrollReset
2742
2756
  });
2743
- } else if (isFetchActionRedirect) {
2744
- // For a fetch action redirect, we kick off a new loading navigation
2745
- // without the fetcher submission, but we send it along for shouldRevalidate
2746
- await startNavigation(redirectHistoryAction, redirectLocation, {
2747
- overrideNavigation: getLoadingNavigation(redirectLocation),
2748
- fetcherSubmission: activeSubmission,
2749
- // Preserve this flag across redirects
2750
- preventScrollReset: pendingPreventScrollReset
2751
- });
2752
2757
  } else {
2753
- // If we have a submission, we will preserve it through the redirect navigation
2754
- let overrideNavigation = getLoadingNavigation(redirectLocation, activeSubmission);
2758
+ // If we have a navigation submission, we will preserve it through the
2759
+ // redirect navigation
2760
+ let overrideNavigation = getLoadingNavigation(redirectLocation, submission);
2755
2761
  await startNavigation(redirectHistoryAction, redirectLocation, {
2756
2762
  overrideNavigation,
2763
+ // Send fetcher submissions through for shouldRevalidate
2764
+ fetcherSubmission,
2757
2765
  // Preserve this flag across redirects
2758
2766
  preventScrollReset: pendingPreventScrollReset
2759
2767
  });
@@ -2969,7 +2977,7 @@
2969
2977
  }
2970
2978
  function getScrollKey(location, matches) {
2971
2979
  if (getScrollRestorationKey) {
2972
- let key = getScrollRestorationKey(location, matches.map(m => createUseMatchesMatch(m, state.loaderData)));
2980
+ let key = getScrollRestorationKey(location, matches.map(m => convertRouteMatchToUiMatch(m, state.loaderData)));
2973
2981
  return key || location.key;
2974
2982
  }
2975
2983
  return location.key;
@@ -3272,7 +3280,7 @@
3272
3280
  });
3273
3281
  if (request.signal.aborted) {
3274
3282
  let method = isRouteRequest ? "queryRoute" : "query";
3275
- throw new Error(method + "() call aborted");
3283
+ throw new Error(method + "() call aborted: " + request.method + " " + request.url);
3276
3284
  }
3277
3285
  }
3278
3286
  if (isRedirectResult(result)) {
@@ -3391,7 +3399,7 @@
3391
3399
  }))]);
3392
3400
  if (request.signal.aborted) {
3393
3401
  let method = isRouteRequest ? "queryRoute" : "query";
3394
- throw new Error(method + "() call aborted");
3402
+ throw new Error(method + "() call aborted: " + request.method + " " + request.url);
3395
3403
  }
3396
3404
 
3397
3405
  // Process and commit output from loaders
@@ -3848,7 +3856,17 @@
3848
3856
  if (match.route.lazy) {
3849
3857
  if (handler) {
3850
3858
  // Run statically defined handler in parallel with lazy()
3851
- let values = await Promise.all([runHandler(handler), loadLazyRouteModule(match.route, mapRouteProperties, manifest)]);
3859
+ let handlerError;
3860
+ let values = await Promise.all([
3861
+ // If the handler throws, don't let it immediately bubble out,
3862
+ // since we need to let the lazy() execution finish so we know if this
3863
+ // route has a boundary that can handle the error
3864
+ runHandler(handler).catch(e => {
3865
+ handlerError = e;
3866
+ }), loadLazyRouteModule(match.route, mapRouteProperties, manifest)]);
3867
+ if (handlerError) {
3868
+ throw handlerError;
3869
+ }
3852
3870
  result = values[0];
3853
3871
  } else {
3854
3872
  // Load lazy route module, then run any returned handler
@@ -3956,7 +3974,7 @@
3956
3974
  if (resultType === ResultType.error) {
3957
3975
  return {
3958
3976
  type: resultType,
3959
- error: new ErrorResponse(status, result.statusText, data),
3977
+ error: new ErrorResponseImpl(status, result.statusText, data),
3960
3978
  headers: result.headers
3961
3979
  };
3962
3980
  }
@@ -4235,7 +4253,7 @@
4235
4253
  errorMessage = "Invalid request method \"" + method.toUpperCase() + "\"";
4236
4254
  }
4237
4255
  }
4238
- return new ErrorResponse(status || 500, statusText, new Error(errorMessage), true);
4256
+ return new ErrorResponseImpl(status || 500, statusText, new Error(errorMessage), true);
4239
4257
  }
4240
4258
 
4241
4259
  // Find any returned redirect errors, starting from the lowest match
@@ -4364,23 +4382,6 @@
4364
4382
  function hasNakedIndexQuery(search) {
4365
4383
  return new URLSearchParams(search).getAll("index").some(v => v === "");
4366
4384
  }
4367
-
4368
- // Note: This should match the format exported by useMatches, so if you change
4369
- // this please also change that :) Eventually we'll DRY this up
4370
- function createUseMatchesMatch(match, loaderData) {
4371
- let {
4372
- route,
4373
- pathname,
4374
- params
4375
- } = match;
4376
- return {
4377
- id: route.id,
4378
- pathname,
4379
- params,
4380
- data: loaderData[route.id],
4381
- handle: route.handle
4382
- };
4383
- }
4384
4385
  function getTargetMatch(matches, location) {
4385
4386
  let search = typeof location === "string" ? parsePath(location).search : location.search;
4386
4387
  if (matches[matches.length - 1].route.index && hasNakedIndexQuery(search || "")) {
@@ -4483,8 +4484,7 @@
4483
4484
  formData: submission.formData,
4484
4485
  json: submission.json,
4485
4486
  text: submission.text,
4486
- data,
4487
- " _hasFetcherDoneAnything ": true
4487
+ data
4488
4488
  };
4489
4489
  return fetcher;
4490
4490
  } else {
@@ -4496,8 +4496,7 @@
4496
4496
  formData: undefined,
4497
4497
  json: undefined,
4498
4498
  text: undefined,
4499
- data,
4500
- " _hasFetcherDoneAnything ": true
4499
+ data
4501
4500
  };
4502
4501
  return fetcher;
4503
4502
  }
@@ -4511,8 +4510,7 @@
4511
4510
  formData: submission.formData,
4512
4511
  json: submission.json,
4513
4512
  text: submission.text,
4514
- data: existingFetcher ? existingFetcher.data : undefined,
4515
- " _hasFetcherDoneAnything ": true
4513
+ data: existingFetcher ? existingFetcher.data : undefined
4516
4514
  };
4517
4515
  return fetcher;
4518
4516
  }
@@ -4525,8 +4523,7 @@
4525
4523
  formData: undefined,
4526
4524
  json: undefined,
4527
4525
  text: undefined,
4528
- data,
4529
- " _hasFetcherDoneAnything ": true
4526
+ data
4530
4527
  };
4531
4528
  return fetcher;
4532
4529
  }
@@ -4534,12 +4531,13 @@
4534
4531
 
4535
4532
  exports.AbortedDeferredError = AbortedDeferredError;
4536
4533
  exports.Action = Action;
4537
- exports.ErrorResponse = ErrorResponse;
4538
4534
  exports.IDLE_BLOCKER = IDLE_BLOCKER;
4539
4535
  exports.IDLE_FETCHER = IDLE_FETCHER;
4540
4536
  exports.IDLE_NAVIGATION = IDLE_NAVIGATION;
4541
4537
  exports.UNSAFE_DEFERRED_SYMBOL = UNSAFE_DEFERRED_SYMBOL;
4542
4538
  exports.UNSAFE_DeferredData = DeferredData;
4539
+ exports.UNSAFE_ErrorResponseImpl = ErrorResponseImpl;
4540
+ exports.UNSAFE_convertRouteMatchToUiMatch = convertRouteMatchToUiMatch;
4543
4541
  exports.UNSAFE_convertRoutesToDataRoutes = convertRoutesToDataRoutes;
4544
4542
  exports.UNSAFE_getPathContributingMatches = getPathContributingMatches;
4545
4543
  exports.UNSAFE_invariant = invariant;