@remix-run/router 1.4.0 → 1.5.0-pre.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/router.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { History, Location, Path, To } from "./history";
2
2
  import { Action as HistoryAction } from "./history";
3
- import type { AgnosticDataRouteMatch, AgnosticDataRouteObject, FormEncType, FormMethod, DetectErrorBoundaryFunction, RouteData, AgnosticRouteObject, AgnosticRouteMatch } from "./utils";
3
+ import type { AgnosticDataRouteMatch, AgnosticDataRouteObject, FormEncType, FormMethod, DetectErrorBoundaryFunction, RouteData, AgnosticRouteObject, AgnosticRouteMatch, V7_FormMethod, HTMLFormMethod } from "./utils";
4
4
  import { DeferredData } from "./utils";
5
5
  /**
6
6
  * A Router instance manages all navigation and data loading/mutations
@@ -236,15 +236,22 @@ export interface RouterState {
236
236
  * Data that can be passed into hydrate a Router from SSR
237
237
  */
238
238
  export declare type HydrationState = Partial<Pick<RouterState, "loaderData" | "actionData" | "errors">>;
239
+ /**
240
+ * Future flags to toggle new feature behavior
241
+ */
242
+ export interface FutureConfig {
243
+ v7_normalizeFormMethod: boolean;
244
+ }
239
245
  /**
240
246
  * Initialization options for createRouter
241
247
  */
242
248
  export interface RouterInit {
243
- basename?: string;
244
249
  routes: AgnosticRouteObject[];
245
250
  history: History;
246
- hydrationData?: HydrationState;
251
+ basename?: string;
247
252
  detectErrorBoundary?: DetectErrorBoundaryFunction;
253
+ future?: FutureConfig;
254
+ hydrationData?: HydrationState;
248
255
  }
249
256
  /**
250
257
  * State returned from a server-side query() call
@@ -316,7 +323,7 @@ declare type SubmissionNavigateOptions = {
316
323
  replace?: boolean;
317
324
  state?: any;
318
325
  preventScrollReset?: boolean;
319
- formMethod?: FormMethod;
326
+ formMethod?: HTMLFormMethod;
320
327
  formEncType?: FormEncType;
321
328
  formData: FormData;
322
329
  };
@@ -343,7 +350,7 @@ export declare type NavigationStates = {
343
350
  Loading: {
344
351
  state: "loading";
345
352
  location: Location;
346
- formMethod: FormMethod | undefined;
353
+ formMethod: FormMethod | V7_FormMethod | undefined;
347
354
  formAction: string | undefined;
348
355
  formEncType: FormEncType | undefined;
349
356
  formData: FormData | undefined;
@@ -351,7 +358,7 @@ export declare type NavigationStates = {
351
358
  Submitting: {
352
359
  state: "submitting";
353
360
  location: Location;
354
- formMethod: FormMethod;
361
+ formMethod: FormMethod | V7_FormMethod;
355
362
  formAction: string;
356
363
  formEncType: FormEncType;
357
364
  formData: FormData;
@@ -374,7 +381,7 @@ declare type FetcherStates<TData = any> = {
374
381
  };
375
382
  Loading: {
376
383
  state: "loading";
377
- formMethod: FormMethod | undefined;
384
+ formMethod: FormMethod | V7_FormMethod | undefined;
378
385
  formAction: string | undefined;
379
386
  formEncType: FormEncType | undefined;
380
387
  formData: FormData | undefined;
@@ -383,7 +390,7 @@ declare type FetcherStates<TData = any> = {
383
390
  };
384
391
  Submitting: {
385
392
  state: "submitting";
386
- formMethod: FormMethod;
393
+ formMethod: FormMethod | V7_FormMethod;
387
394
  formAction: string;
388
395
  formEncType: FormEncType;
389
396
  formData: FormData;
package/dist/router.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @remix-run/router v1.4.0
2
+ * @remix-run/router v1.5.0-pre.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1436,7 +1436,12 @@ function createRouter(init) {
1436
1436
  let manifest = {}; // Routes in tree format for matching
1437
1437
 
1438
1438
  let dataRoutes = convertRoutesToDataRoutes(init.routes, detectErrorBoundary, undefined, manifest);
1439
- let inFlightDataRoutes; // Cleanup function for history
1439
+ let inFlightDataRoutes; // Config driven behavior flags
1440
+
1441
+ let future = _extends({
1442
+ v7_normalizeFormMethod: false
1443
+ }, init.future); // Cleanup function for history
1444
+
1440
1445
 
1441
1446
  let unlistenHistory = null; // Externally-provided functions to call on all state changes
1442
1447
 
@@ -1600,35 +1605,16 @@ function createRouter(init) {
1600
1605
  }
1601
1606
 
1602
1607
  return startNavigation(historyAction, location);
1603
- });
1608
+ }); // Kick off initial data load if needed. Use Pop to avoid modifying history
1609
+ // Note we don't do any handling of lazy here. For SPA's it'll get handled
1610
+ // in the normal navigation flow. For SSR it's expected that lazy modules are
1611
+ // resolved prior to router creation since we can't go into a fallbackElement
1612
+ // UI for SSR'd apps
1604
1613
 
1605
- if (state.initialized) {
1606
- return router;
1607
- }
1608
-
1609
- let lazyMatches = state.matches.filter(m => m.route.lazy);
1610
-
1611
- if (lazyMatches.length === 0) {
1612
- // Kick off initial data load if needed. Use Pop to avoid modifying history
1614
+ if (!state.initialized) {
1613
1615
  startNavigation(Action.Pop, state.location);
1614
- return router;
1615
- } // Load lazy modules, then kick off initial data load if needed
1616
-
1617
-
1618
- let lazyPromises = lazyMatches.map(m => loadLazyRouteModule(m.route, detectErrorBoundary, manifest));
1619
- Promise.all(lazyPromises).then(() => {
1620
- let initialized = !state.matches.some(m => m.route.loader) || init.hydrationData != null;
1616
+ }
1621
1617
 
1622
- if (initialized) {
1623
- // We already have required loaderData so we can just set initialized
1624
- updateState({
1625
- initialized: true
1626
- });
1627
- } else {
1628
- // We still need to kick off initial data loads
1629
- startNavigation(Action.Pop, state.location);
1630
- }
1631
- });
1632
1618
  return router;
1633
1619
  } // Clean up a router and it's side effects
1634
1620
 
@@ -1744,7 +1730,7 @@ function createRouter(init) {
1744
1730
  path,
1745
1731
  submission,
1746
1732
  error
1747
- } = normalizeNavigateOptions(to, opts);
1733
+ } = normalizeNavigateOptions(to, future, opts);
1748
1734
  let currentLocation = state.location;
1749
1735
  let nextLocation = createLocation(state.location, path, opts && opts.state); // When using navigate as a PUSH/REPLACE we aren't reading an already-encoded
1750
1736
  // URL from window.location, so we need to encode it here so the behavior
@@ -1936,7 +1922,7 @@ function createRouter(init) {
1936
1922
  shortCircuited,
1937
1923
  loaderData,
1938
1924
  errors
1939
- } = await handleLoaders(request, location, matches, loadingNavigation, opts && opts.submission, opts && opts.replace, pendingActionData, pendingError);
1925
+ } = await handleLoaders(request, location, matches, loadingNavigation, opts && opts.submission, opts && opts.fetcherSubmission, opts && opts.replace, pendingActionData, pendingError);
1940
1926
 
1941
1927
  if (shortCircuited) {
1942
1928
  return;
@@ -2049,7 +2035,7 @@ function createRouter(init) {
2049
2035
  // errors, etc.
2050
2036
 
2051
2037
 
2052
- async function handleLoaders(request, location, matches, overrideNavigation, submission, replace, pendingActionData, pendingError) {
2038
+ async function handleLoaders(request, location, matches, overrideNavigation, submission, fetcherSubmission, replace, pendingActionData, pendingError) {
2053
2039
  // Figure out the right navigation we want to use for data loading
2054
2040
  let loadingNavigation = overrideNavigation;
2055
2041
 
@@ -2068,7 +2054,7 @@ function createRouter(init) {
2068
2054
  // we have it on the loading navigation so use that if available
2069
2055
 
2070
2056
 
2071
- let activeSubmission = submission ? submission : loadingNavigation.formMethod && loadingNavigation.formAction && loadingNavigation.formData && loadingNavigation.formEncType ? {
2057
+ let activeSubmission = submission || fetcherSubmission ? submission || fetcherSubmission : loadingNavigation.formMethod && loadingNavigation.formAction && loadingNavigation.formData && loadingNavigation.formEncType ? {
2072
2058
  formMethod: loadingNavigation.formMethod,
2073
2059
  formAction: loadingNavigation.formAction,
2074
2060
  formData: loadingNavigation.formData,
@@ -2205,7 +2191,7 @@ function createRouter(init) {
2205
2191
  let {
2206
2192
  path,
2207
2193
  submission
2208
- } = normalizeNavigateOptions(href, opts, true);
2194
+ } = normalizeNavigateOptions(href, future, opts, true);
2209
2195
  let match = getTargetMatch(matches, path);
2210
2196
  pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
2211
2197
 
@@ -2285,6 +2271,7 @@ function createRouter(init) {
2285
2271
  fetchers: new Map(state.fetchers)
2286
2272
  });
2287
2273
  return startRedirectNavigation(state, actionResult, {
2274
+ submission,
2288
2275
  isFetchActionRedirect: true
2289
2276
  });
2290
2277
  } // Process any non-redirect errors thrown
@@ -2575,6 +2562,22 @@ function createRouter(init) {
2575
2562
  // Preserve this flag across redirects
2576
2563
  preventScrollReset: pendingPreventScrollReset
2577
2564
  });
2565
+ } else if (isFetchActionRedirect) {
2566
+ // For a fetch action redirect, we kick off a new loading navigation
2567
+ // without the fetcher submission, but we send it along for shouldRevalidate
2568
+ await startNavigation(redirectHistoryAction, redirectLocation, {
2569
+ overrideNavigation: {
2570
+ state: "loading",
2571
+ location: redirectLocation,
2572
+ formMethod: undefined,
2573
+ formAction: undefined,
2574
+ formEncType: undefined,
2575
+ formData: undefined
2576
+ },
2577
+ fetcherSubmission: submission,
2578
+ // Preserve this flag across redirects
2579
+ preventScrollReset: pendingPreventScrollReset
2580
+ });
2578
2581
  } else {
2579
2582
  // Otherwise, we kick off a new loading navigation, preserving the
2580
2583
  // submission info for the duration of this navigation
@@ -2920,11 +2923,11 @@ function createStaticHandler(routes, opts) {
2920
2923
  requestContext
2921
2924
  } = _temp2 === void 0 ? {} : _temp2;
2922
2925
  let url = new URL(request.url);
2923
- let method = request.method.toLowerCase();
2926
+ let method = request.method;
2924
2927
  let location = createLocation("", createPath(url), null, "default");
2925
2928
  let matches = matchRoutes(dataRoutes, location, basename); // SSR supports HEAD requests while SPA doesn't
2926
2929
 
2927
- if (!isValidMethod(method) && method !== "head") {
2930
+ if (!isValidMethod(method) && method !== "HEAD") {
2928
2931
  let error = getInternalRouterError(405, {
2929
2932
  method
2930
2933
  });
@@ -3012,11 +3015,11 @@ function createStaticHandler(routes, opts) {
3012
3015
  requestContext
3013
3016
  } = _temp3 === void 0 ? {} : _temp3;
3014
3017
  let url = new URL(request.url);
3015
- let method = request.method.toLowerCase();
3018
+ let method = request.method;
3016
3019
  let location = createLocation("", createPath(url), null, "default");
3017
3020
  let matches = matchRoutes(dataRoutes, location, basename); // SSR supports HEAD requests while SPA doesn't
3018
3021
 
3019
- if (!isValidMethod(method) && method !== "head" && method !== "options") {
3022
+ if (!isValidMethod(method) && method !== "HEAD" && method !== "OPTIONS") {
3020
3023
  throw getInternalRouterError(405, {
3021
3024
  method
3022
3025
  });
@@ -3309,7 +3312,7 @@ function isSubmissionNavigation(opts) {
3309
3312
  // URLSearchParams so they behave identically to links with query params
3310
3313
 
3311
3314
 
3312
- function normalizeNavigateOptions(to, opts, isFetcher) {
3315
+ function normalizeNavigateOptions(to, future, opts, isFetcher) {
3313
3316
  if (isFetcher === void 0) {
3314
3317
  isFetcher = false;
3315
3318
  }
@@ -3335,8 +3338,9 @@ function normalizeNavigateOptions(to, opts, isFetcher) {
3335
3338
  let submission;
3336
3339
 
3337
3340
  if (opts.formData) {
3341
+ let formMethod = opts.formMethod || "get";
3338
3342
  submission = {
3339
- formMethod: opts.formMethod || "get",
3343
+ formMethod: future.v7_normalizeFormMethod ? formMethod.toUpperCase() : formMethod.toLowerCase(),
3340
3344
  formAction: stripHashFromPath(path),
3341
3345
  formEncType: opts && opts.formEncType || "application/x-www-form-urlencoded",
3342
3346
  formData: opts.formData
@@ -3776,7 +3780,10 @@ function createClientSideRequest(history, location, signal, submission) {
3776
3780
  formMethod,
3777
3781
  formEncType,
3778
3782
  formData
3779
- } = submission;
3783
+ } = submission; // Didn't think we needed this but it turns out unlike other methods, patch
3784
+ // won't be properly normalized to uppercase and results in a 405 error.
3785
+ // See: https://fetch.spec.whatwg.org/#concept-method
3786
+
3780
3787
  init.method = formMethod.toUpperCase();
3781
3788
  init.body = formEncType === "application/x-www-form-urlencoded" ? convertFormDataToSearchParams(formData) : formData;
3782
3789
  } // Content-Type is inferred (https://fetch.spec.whatwg.org/#dom-request)
@@ -4065,11 +4072,11 @@ function isQueryRouteResponse(obj) {
4065
4072
  }
4066
4073
 
4067
4074
  function isValidMethod(method) {
4068
- return validRequestMethods.has(method);
4075
+ return validRequestMethods.has(method.toLowerCase());
4069
4076
  }
4070
4077
 
4071
4078
  function isMutationMethod(method) {
4072
- return validMutationMethods.has(method);
4079
+ return validMutationMethods.has(method.toLowerCase());
4073
4080
  }
4074
4081
 
4075
4082
  async function resolveDeferredResults(currentMatches, matchesToLoad, results, signal, isFetcher, currentLoaderData) {