react-router-dom 0.0.0-experimental-a077dc2d → 0.0.0-experimental-e192105b

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 CHANGED
@@ -1,5 +1,26 @@
1
1
  # `react-router-dom`
2
2
 
3
+ ## 6.18.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Add support for manual fetcher key specification via `useFetcher({ key: string })` so you can access the same fetcher instance from different components in your application without prop-drilling ([RFC](https://github.com/remix-run/remix/discussions/7698)) ([#10960](https://github.com/remix-run/react-router/pull/10960))
8
+
9
+ - Fetcher keys are now also exposed on the fetchers returned from `useFetchers` so that they can be looked up by `key`
10
+
11
+ - Add `navigate`/`fetcherKey` params/props to `useSumbit`/`Form` to support kicking off a fetcher submission under the hood with an optionally user-specified `key` ([#10960](https://github.com/remix-run/react-router/pull/10960))
12
+
13
+ - Invoking a fetcher in this way is ephemeral and stateless
14
+ - If you need to access the state of one of these fetchers, you will need to leverage `useFetcher({ key })` to look it up elsewhere
15
+
16
+ ### Patch Changes
17
+
18
+ - Adds a fetcher context to `RouterProvider` that holds completed fetcher data, in preparation for the upcoming future flag that will change the fetcher persistence/cleanup behavior ([#10961](https://github.com/remix-run/react-router/pull/10961))
19
+ - Fix the `future` prop on `BrowserRouter`, `HashRouter` and `MemoryRouter` so that it accepts a `Partial<FutureConfig>` instead of requiring all flags to be included. ([#10962](https://github.com/remix-run/react-router/pull/10962))
20
+ - Updated dependencies:
21
+ - `@remix-run/router@1.11.0`
22
+ - `react-router@6.18.0`
23
+
3
24
  ## 6.17.0
4
25
 
5
26
  ### Minor Changes
package/dist/dom.d.ts CHANGED
@@ -85,6 +85,10 @@ export interface SubmitOptions {
85
85
  * navigation when using the <ScrollRestoration> component
86
86
  */
87
87
  preventScrollReset?: boolean;
88
+ /**
89
+ * Enable flushSync for this navigation's state updates
90
+ */
91
+ unstable_flushSync?: boolean;
88
92
  /**
89
93
  * Enable view transitions on this submission navigation
90
94
  */
package/dist/index.d.ts CHANGED
@@ -4,13 +4,13 @@
4
4
  */
5
5
  import * as React from "react";
6
6
  import type { FutureConfig, Location, NavigateOptions, RelativeRoutingType, RouteObject, RouterProviderProps, To } from "react-router";
7
- import type { Fetcher, FormEncType, FormMethod, FutureConfig as RouterFutureConfig, GetScrollRestorationKeyFunction, History, HTMLFormMethod, HydrationState, Router as RemixRouter, V7_FormMethod } from "@remix-run/router";
7
+ import type { Fetcher, FormEncType, FormMethod, FutureConfig as RouterFutureConfig, GetScrollRestorationKeyFunction, History, HTMLFormMethod, HydrationState, Router as RemixRouter, V7_FormMethod, BlockerFunction } from "@remix-run/router";
8
8
  import type { SubmitOptions, ParamKeyValuePair, URLSearchParamsInit, SubmitTarget } from "./dom";
9
9
  import { createSearchParams } from "./dom";
10
10
  export type { FormEncType, FormMethod, GetScrollRestorationKeyFunction, ParamKeyValuePair, SubmitOptions, URLSearchParamsInit, V7_FormMethod, };
11
11
  export { createSearchParams };
12
12
  export type { ActionFunction, ActionFunctionArgs, AwaitProps, unstable_Blocker, unstable_BlockerFunction, DataRouteMatch, DataRouteObject, ErrorResponse, Fetcher, Hash, IndexRouteObject, IndexRouteProps, JsonFunction, LazyRouteFunction, LayoutRouteProps, LoaderFunction, LoaderFunctionArgs, Location, MemoryRouterProps, NavigateFunction, NavigateOptions, NavigateProps, Navigation, Navigator, NonIndexRouteObject, OutletProps, Params, ParamParseKey, Path, PathMatch, Pathname, PathPattern, PathRouteProps, RedirectFunction, RelativeRoutingType, RouteMatch, RouteObject, RouteProps, RouterProps, RouterProviderProps, RoutesProps, Search, ShouldRevalidateFunction, ShouldRevalidateFunctionArgs, To, UIMatch, } from "react-router";
13
- export { AbortedDeferredError, Await, MemoryRouter, Navigate, NavigationType, Outlet, Route, Router, Routes, createMemoryRouter, createPath, createRoutesFromChildren, createRoutesFromElements, defer, isRouteErrorResponse, generatePath, json, matchPath, matchRoutes, parsePath, redirect, redirectDocument, renderMatches, resolvePath, useActionData, useAsyncError, useAsyncValue, unstable_useBlocker, useHref, useInRouterContext, useLoaderData, useLocation, useMatch, useMatches, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useRouteLoaderData, useRoutes, } from "react-router";
13
+ export { AbortedDeferredError, Await, MemoryRouter, Navigate, NavigationType, Outlet, Route, Router, Routes, createMemoryRouter, createPath, createRoutesFromChildren, createRoutesFromElements, defer, isRouteErrorResponse, generatePath, json, matchPath, matchRoutes, parsePath, redirect, redirectDocument, renderMatches, resolvePath, useActionData, useAsyncError, useAsyncValue, useBlocker, useHref, useInRouterContext, useLoaderData, useLocation, useMatch, useMatches, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useRouteLoaderData, useRoutes, } from "react-router";
14
14
  /** @internal */
15
15
  export { UNSAFE_DataRouterContext, UNSAFE_DataRouterStateContext, UNSAFE_NavigationContext, UNSAFE_LocationContext, UNSAFE_RouteContext, UNSAFE_useRouteId, } from "react-router";
16
16
  declare global {
@@ -31,17 +31,14 @@ type ViewTransitionContextObject = {
31
31
  isTransitioning: false;
32
32
  } | {
33
33
  isTransitioning: true;
34
+ flushSync: boolean;
34
35
  currentLocation: Location;
35
36
  nextLocation: Location;
36
37
  };
37
38
  declare const ViewTransitionContext: React.Context<ViewTransitionContextObject>;
38
39
  export { ViewTransitionContext as UNSAFE_ViewTransitionContext };
39
- type FetchersContextObject = {
40
- fetcherData: Map<string, any>;
41
- register: (key: string) => void;
42
- unregister: (key: string) => void;
43
- };
44
- declare const FetchersContext: React.Context<FetchersContextObject | null>;
40
+ type FetchersContextObject = Map<string, any>;
41
+ declare const FetchersContext: React.Context<FetchersContextObject>;
45
42
  export { FetchersContext as UNSAFE_FetchersContext };
46
43
  interface ViewTransition {
47
44
  finished: Promise<void>;
@@ -98,6 +95,7 @@ export interface LinkProps extends Omit<React.AnchorHTMLAttributes<HTMLAnchorEle
98
95
  preventScrollReset?: boolean;
99
96
  relative?: RelativeRoutingType;
100
97
  to: To;
98
+ unstable_flushSync?: boolean;
101
99
  unstable_viewTransition?: boolean;
102
100
  }
103
101
  /**
@@ -115,7 +113,6 @@ export interface NavLinkProps extends Omit<LinkProps, "className" | "style" | "c
115
113
  className?: string | ((props: NavLinkRenderProps) => string | undefined);
116
114
  end?: boolean;
117
115
  style?: React.CSSProperties | ((props: NavLinkRenderProps) => React.CSSProperties | undefined);
118
- unstable_viewTransition?: boolean;
119
116
  }
120
117
  /**
121
118
  * A `<Link>` wrapper that knows if it's "active" or not.
@@ -176,6 +173,10 @@ export interface FormProps extends FetcherFormProps {
176
173
  * State object to add to the history stack entry for this navigation
177
174
  */
178
175
  state?: any;
176
+ /**
177
+ * Enable flushSync navigation's staten updates
178
+ */
179
+ unstable_flushSync?: boolean;
179
180
  /**
180
181
  * Enable view transitions on this Form navigation
181
182
  */
@@ -205,12 +206,13 @@ export declare namespace ScrollRestoration {
205
206
  * you need to create custom `<Link>` components with the same click behavior we
206
207
  * use in our exported `<Link>`.
207
208
  */
208
- export declare function useLinkClickHandler<E extends Element = HTMLAnchorElement>(to: To, { target, replace: replaceProp, state, preventScrollReset, relative, unstable_viewTransition, }?: {
209
+ export declare function useLinkClickHandler<E extends Element = HTMLAnchorElement>(to: To, { target, replace: replaceProp, state, preventScrollReset, relative, unstable_flushSync, unstable_viewTransition, }?: {
209
210
  target?: React.HTMLAttributeAnchorTarget;
210
211
  replace?: boolean;
211
212
  state?: any;
212
213
  preventScrollReset?: boolean;
213
214
  relative?: RelativeRoutingType;
215
+ unstable_flushSync?: boolean;
214
216
  unstable_viewTransition?: boolean;
215
217
  }): (event: React.MouseEvent<E, MouseEvent>) => void;
216
218
  /**
@@ -299,8 +301,8 @@ export declare function useBeforeUnload(callback: (event: BeforeUnloadEvent) =>
299
301
  * very incorrectly in some cases) across browsers if user click addition
300
302
  * back/forward navigations while the confirm is open. Use at your own risk.
301
303
  */
302
- declare function usePrompt({ when, message }: {
303
- when: boolean;
304
+ declare function usePrompt({ when, message, }: {
305
+ when: boolean | BlockerFunction;
304
306
  message: string;
305
307
  }): void;
306
308
  export { usePrompt as unstable_usePrompt };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * React Router DOM v0.0.0-experimental-a077dc2d
2
+ * React Router DOM v0.0.0-experimental-e192105b
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -9,8 +9,9 @@
9
9
  * @license MIT
10
10
  */
11
11
  import * as React from 'react';
12
- import { UNSAFE_mapRouteProperties, UNSAFE_DataRouterContext, UNSAFE_DataRouterStateContext, Router, UNSAFE_useRoutesImpl, UNSAFE_NavigationContext, useHref, useResolvedPath, useLocation, useNavigate, createPath, UNSAFE_useRouteId, UNSAFE_RouteContext, useMatches, useNavigation, unstable_useBlocker } from 'react-router';
13
- export { AbortedDeferredError, Await, MemoryRouter, Navigate, NavigationType, Outlet, Route, Router, Routes, UNSAFE_DataRouterContext, UNSAFE_DataRouterStateContext, UNSAFE_LocationContext, UNSAFE_NavigationContext, UNSAFE_RouteContext, UNSAFE_useRouteId, createMemoryRouter, createPath, createRoutesFromChildren, createRoutesFromElements, defer, generatePath, isRouteErrorResponse, json, matchPath, matchRoutes, parsePath, redirect, redirectDocument, renderMatches, resolvePath, unstable_useBlocker, useActionData, useAsyncError, useAsyncValue, useHref, useInRouterContext, useLoaderData, useLocation, useMatch, useMatches, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useRouteLoaderData, useRoutes } from 'react-router';
12
+ import * as ReactDOM from 'react-dom';
13
+ import { UNSAFE_mapRouteProperties, UNSAFE_DataRouterContext, UNSAFE_DataRouterStateContext, Router, UNSAFE_useRoutesImpl, UNSAFE_NavigationContext, useHref, useResolvedPath, useLocation, useNavigate, createPath, UNSAFE_useRouteId, UNSAFE_RouteContext, useMatches, useNavigation, useBlocker } from 'react-router';
14
+ export { AbortedDeferredError, Await, MemoryRouter, Navigate, NavigationType, Outlet, Route, Router, Routes, UNSAFE_DataRouterContext, UNSAFE_DataRouterStateContext, UNSAFE_LocationContext, UNSAFE_NavigationContext, UNSAFE_RouteContext, UNSAFE_useRouteId, createMemoryRouter, createPath, createRoutesFromChildren, createRoutesFromElements, defer, generatePath, isRouteErrorResponse, json, matchPath, matchRoutes, parsePath, redirect, redirectDocument, renderMatches, resolvePath, useActionData, useAsyncError, useAsyncValue, useBlocker, useHref, useInRouterContext, useLoaderData, useLocation, useMatch, useMatches, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useRouteLoaderData, useRoutes } from 'react-router';
14
15
  import { stripBasename, UNSAFE_warning, createRouter, createBrowserHistory, createHashHistory, UNSAFE_ErrorResponseImpl, UNSAFE_invariant, joinPaths, IDLE_FETCHER, matchPath } from '@remix-run/router';
15
16
 
16
17
  function _extends() {
@@ -206,9 +207,9 @@ function getFormSubmissionInfo(target, basename) {
206
207
  };
207
208
  }
208
209
 
209
- const _excluded = ["onClick", "relative", "reloadDocument", "replace", "state", "target", "to", "preventScrollReset", "unstable_viewTransition"],
210
+ const _excluded = ["onClick", "relative", "reloadDocument", "replace", "state", "target", "to", "preventScrollReset", "unstable_flushSync", "unstable_viewTransition"],
210
211
  _excluded2 = ["aria-current", "caseSensitive", "className", "end", "style", "to", "unstable_viewTransition", "children"],
211
- _excluded3 = ["fetcherKey", "navigate", "reloadDocument", "replace", "state", "method", "action", "onSubmit", "relative", "preventScrollReset", "unstable_viewTransition"];
212
+ _excluded3 = ["fetcherKey", "navigate", "reloadDocument", "replace", "state", "method", "action", "onSubmit", "relative", "preventScrollReset", "unstable_flushSync", "unstable_viewTransition"];
212
213
  function createBrowserRouter(routes, opts) {
213
214
  return createRouter({
214
215
  basename: opts == null ? void 0 : opts.basename,
@@ -294,7 +295,7 @@ const ViewTransitionContext = /*#__PURE__*/React.createContext({
294
295
  if (process.env.NODE_ENV !== "production") {
295
296
  ViewTransitionContext.displayName = "ViewTransition";
296
297
  }
297
- const FetchersContext = /*#__PURE__*/React.createContext(null);
298
+ const FetchersContext = /*#__PURE__*/React.createContext(new Map());
298
299
  if (process.env.NODE_ENV !== "production") {
299
300
  FetchersContext.displayName = "Fetchers";
300
301
  }
@@ -325,6 +326,8 @@ if (process.env.NODE_ENV !== "production") {
325
326
  */
326
327
  const START_TRANSITION = "startTransition";
327
328
  const startTransitionImpl = React[START_TRANSITION];
329
+ const FLUSH_SYNC = "flushSync";
330
+ const flushSyncImpl = ReactDOM[FLUSH_SYNC];
328
331
  function startTransitionSafe(cb) {
329
332
  if (startTransitionImpl) {
330
333
  startTransitionImpl(cb);
@@ -332,6 +335,13 @@ function startTransitionSafe(cb) {
332
335
  cb();
333
336
  }
334
337
  }
338
+ function flushSyncSafe(cb) {
339
+ if (flushSyncImpl) {
340
+ flushSyncImpl(cb);
341
+ } else {
342
+ cb();
343
+ }
344
+ }
335
345
  class Deferred {
336
346
  constructor() {
337
347
  this.status = "pending";
@@ -360,10 +370,6 @@ function RouterProvider(_ref) {
360
370
  router,
361
371
  future
362
372
  } = _ref;
363
- let {
364
- fetcherContext,
365
- fetcherData
366
- } = useFetcherDataLayer();
367
373
  let [state, setStateImpl] = React.useState(router.state);
368
374
  let [pendingState, setPendingState] = React.useState();
369
375
  let [vtContext, setVtContext] = React.useState({
@@ -372,6 +378,7 @@ function RouterProvider(_ref) {
372
378
  let [renderDfd, setRenderDfd] = React.useState();
373
379
  let [transition, setTransition] = React.useState();
374
380
  let [interruption, setInterruption] = React.useState();
381
+ let fetcherData = React.useRef(new Map());
375
382
  let {
376
383
  v7_startTransition
377
384
  } = future || {};
@@ -384,20 +391,66 @@ function RouterProvider(_ref) {
384
391
  }, [v7_startTransition]);
385
392
  let setState = React.useCallback((newState, _ref2) => {
386
393
  let {
394
+ deletedFetchers,
395
+ unstable_flushSync: flushSync,
387
396
  unstable_viewTransitionOpts: viewTransitionOpts
388
397
  } = _ref2;
398
+ deletedFetchers.forEach(key => fetcherData.current.delete(key));
389
399
  newState.fetchers.forEach((fetcher, key) => {
390
400
  if (fetcher.data !== undefined) {
391
401
  fetcherData.current.set(key, fetcher.data);
392
402
  }
393
403
  });
394
- if (!viewTransitionOpts || router.window == null || typeof router.window.document.startViewTransition !== "function") {
395
- // Mid-navigation state update, or startViewTransition isn't available
396
- optInStartTransition(() => setStateImpl(newState));
397
- } else if (transition && renderDfd) {
404
+ let isViewTransitionUnavailable = router.window == null || typeof router.window.document.startViewTransition !== "function";
405
+ // If this isn't a view transition or it's not available in this browser,
406
+ // just update and be done with it
407
+ if (!viewTransitionOpts || isViewTransitionUnavailable) {
408
+ if (flushSync) {
409
+ flushSyncSafe(() => setStateImpl(newState));
410
+ } else {
411
+ optInStartTransition(() => setStateImpl(newState));
412
+ }
413
+ return;
414
+ }
415
+ // flushSync + startViewTransition
416
+ if (flushSync) {
417
+ // Flush through the context to mark DOM elements as transition=ing
418
+ flushSyncSafe(() => {
419
+ // Cancel any pending transitions
420
+ if (transition) {
421
+ renderDfd && renderDfd.resolve();
422
+ transition.skipTransition();
423
+ }
424
+ setVtContext({
425
+ isTransitioning: true,
426
+ flushSync: true,
427
+ currentLocation: viewTransitionOpts.currentLocation,
428
+ nextLocation: viewTransitionOpts.nextLocation
429
+ });
430
+ });
431
+ // Update the DOM
432
+ let t = router.window.document.startViewTransition(() => {
433
+ flushSyncSafe(() => setStateImpl(newState));
434
+ });
435
+ // Clean up after the animation completes
436
+ t.finished.finally(() => {
437
+ flushSyncSafe(() => {
438
+ setRenderDfd(undefined);
439
+ setTransition(undefined);
440
+ setPendingState(undefined);
441
+ setVtContext({
442
+ isTransitioning: false
443
+ });
444
+ });
445
+ });
446
+ flushSyncSafe(() => setTransition(t));
447
+ return;
448
+ }
449
+ // startTransition + startViewTransition
450
+ if (transition) {
398
451
  // Interrupting an in-progress transition, cancel and let everything flush
399
452
  // out, and then kick off a new transition from the interruption state
400
- renderDfd.resolve();
453
+ renderDfd && renderDfd.resolve();
401
454
  transition.skipTransition();
402
455
  setInterruption({
403
456
  state: newState,
@@ -409,6 +462,7 @@ function RouterProvider(_ref) {
409
462
  setPendingState(newState);
410
463
  setVtContext({
411
464
  isTransitioning: true,
465
+ flushSync: false,
412
466
  currentLocation: viewTransitionOpts.currentLocation,
413
467
  nextLocation: viewTransitionOpts.nextLocation
414
468
  });
@@ -420,10 +474,10 @@ function RouterProvider(_ref) {
420
474
  // When we start a view transition, create a Deferred we can use for the
421
475
  // eventual "completed" render
422
476
  React.useEffect(() => {
423
- if (vtContext.isTransitioning) {
477
+ if (vtContext.isTransitioning && !vtContext.flushSync) {
424
478
  setRenderDfd(new Deferred());
425
479
  }
426
- }, [vtContext.isTransitioning]);
480
+ }, [vtContext]);
427
481
  // Once the deferred is created, kick off startViewTransition() to update the
428
482
  // DOM and then wait on the Deferred to resolve (indicating the DOM update has
429
483
  // happened)
@@ -460,6 +514,7 @@ function RouterProvider(_ref) {
460
514
  setPendingState(interruption.state);
461
515
  setVtContext({
462
516
  isTransitioning: true,
517
+ flushSync: false,
463
518
  currentLocation: interruption.currentLocation,
464
519
  nextLocation: interruption.nextLocation
465
520
  });
@@ -500,7 +555,7 @@ function RouterProvider(_ref) {
500
555
  }, /*#__PURE__*/React.createElement(UNSAFE_DataRouterStateContext.Provider, {
501
556
  value: state
502
557
  }, /*#__PURE__*/React.createElement(FetchersContext.Provider, {
503
- value: fetcherContext
558
+ value: fetcherData.current
504
559
  }, /*#__PURE__*/React.createElement(ViewTransitionContext.Provider, {
505
560
  value: vtContext
506
561
  }, /*#__PURE__*/React.createElement(Router, {
@@ -645,6 +700,7 @@ const Link = /*#__PURE__*/React.forwardRef(function LinkWithRef(_ref7, ref) {
645
700
  target,
646
701
  to,
647
702
  preventScrollReset,
703
+ unstable_flushSync,
648
704
  unstable_viewTransition
649
705
  } = _ref7,
650
706
  rest = _objectWithoutPropertiesLoose(_ref7, _excluded);
@@ -685,6 +741,7 @@ const Link = /*#__PURE__*/React.forwardRef(function LinkWithRef(_ref7, ref) {
685
741
  target,
686
742
  preventScrollReset,
687
743
  relative,
744
+ unstable_flushSync,
688
745
  unstable_viewTransition
689
746
  });
690
747
  function handleClick(event) {
@@ -742,7 +799,13 @@ const NavLink = /*#__PURE__*/React.forwardRef(function NavLinkWithRef(_ref8, ref
742
799
  nextLocationPathname = nextLocationPathname ? nextLocationPathname.toLowerCase() : null;
743
800
  toPathname = toPathname.toLowerCase();
744
801
  }
745
- let isActive = locationPathname === toPathname || !end && locationPathname.startsWith(toPathname) && locationPathname.charAt(toPathname.length) === "/";
802
+ // If the `to` has a trailing slash, look at that exact spot. Otherwise,
803
+ // we're looking for a slash _after_ what's in `to`. For example:
804
+ //
805
+ // <NavLink to="/users"> and <NavLink to="/users/">
806
+ // both want to look for a / at index 6 to match URL `/users/matt`
807
+ const endSlashPosition = toPathname !== "/" && toPathname.endsWith("/") ? toPathname.length - 1 : toPathname.length;
808
+ let isActive = locationPathname === toPathname || !end && locationPathname.startsWith(toPathname) && locationPathname.charAt(endSlashPosition) === "/";
746
809
  let isPending = nextLocationPathname != null && (nextLocationPathname === toPathname || !end && nextLocationPathname.startsWith(toPathname) && nextLocationPathname.charAt(toPathname.length) === "/");
747
810
  let renderProps = {
748
811
  isActive,
@@ -792,6 +855,7 @@ const Form = /*#__PURE__*/React.forwardRef((_ref9, forwardedRef) => {
792
855
  onSubmit,
793
856
  relative,
794
857
  preventScrollReset,
858
+ unstable_flushSync,
795
859
  unstable_viewTransition
796
860
  } = _ref9,
797
861
  props = _objectWithoutPropertiesLoose(_ref9, _excluded3);
@@ -814,6 +878,7 @@ const Form = /*#__PURE__*/React.forwardRef((_ref9, forwardedRef) => {
814
878
  state,
815
879
  relative,
816
880
  preventScrollReset,
881
+ unstable_flushSync,
817
882
  unstable_viewTransition
818
883
  });
819
884
  };
@@ -877,36 +942,6 @@ function useDataRouterState(hookName) {
877
942
  !state ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, getDataRouterConsoleError(hookName)) : UNSAFE_invariant(false) : void 0;
878
943
  return state;
879
944
  }
880
- function useFetcherDataLayer() {
881
- let fetcherRefs = React.useRef(new Map());
882
- let fetcherData = React.useRef(new Map());
883
- let registerFetcher = React.useCallback(key => {
884
- let count = fetcherRefs.current.get(key);
885
- if (count == null) {
886
- fetcherRefs.current.set(key, 1);
887
- } else {
888
- fetcherRefs.current.set(key, count + 1);
889
- }
890
- }, [fetcherRefs]);
891
- let unregisterFetcher = React.useCallback(key => {
892
- let count = fetcherRefs.current.get(key);
893
- if (count == null || count <= 1) {
894
- fetcherRefs.current.delete(key);
895
- fetcherData.current.delete(key);
896
- } else {
897
- fetcherRefs.current.set(key, count - 1);
898
- }
899
- }, [fetcherData, fetcherRefs]);
900
- let fetcherContext = React.useMemo(() => ({
901
- fetcherData: fetcherData.current,
902
- register: registerFetcher,
903
- unregister: unregisterFetcher
904
- }), [fetcherData, registerFetcher, unregisterFetcher]);
905
- return {
906
- fetcherContext,
907
- fetcherData
908
- };
909
- }
910
945
  // External hooks
911
946
  /**
912
947
  * Handles the click behavior for router `<Link>` components. This is useful if
@@ -920,6 +955,7 @@ function useLinkClickHandler(to, _temp) {
920
955
  state,
921
956
  preventScrollReset,
922
957
  relative,
958
+ unstable_flushSync,
923
959
  unstable_viewTransition
924
960
  } = _temp === void 0 ? {} : _temp;
925
961
  let navigate = useNavigate();
@@ -938,10 +974,11 @@ function useLinkClickHandler(to, _temp) {
938
974
  state,
939
975
  preventScrollReset,
940
976
  relative,
977
+ unstable_flushSync,
941
978
  unstable_viewTransition
942
979
  });
943
980
  }
944
- }, [location, navigate, path, replaceProp, state, target, to, preventScrollReset, relative, unstable_viewTransition]);
981
+ }, [location, navigate, path, replaceProp, state, target, to, preventScrollReset, relative, unstable_flushSync, unstable_viewTransition]);
945
982
  }
946
983
  /**
947
984
  * A convenient wrapper for reading and writing search parameters via the
@@ -1003,7 +1040,8 @@ function useSubmit() {
1003
1040
  formData,
1004
1041
  body,
1005
1042
  formMethod: options.method || method,
1006
- formEncType: options.encType || encType
1043
+ formEncType: options.encType || encType,
1044
+ unstable_flushSync: options.unstable_flushSync
1007
1045
  });
1008
1046
  } else {
1009
1047
  router.navigate(options.action || action, {
@@ -1015,6 +1053,7 @@ function useSubmit() {
1015
1053
  replace: options.replace,
1016
1054
  state: options.state,
1017
1055
  fromRouteId: currentRouteId,
1056
+ unstable_flushSync: options.unstable_flushSync,
1018
1057
  unstable_viewTransition: options.unstable_viewTransition
1019
1058
  });
1020
1059
  }
@@ -1037,10 +1076,8 @@ function useFormAction(action, _temp2) {
1037
1076
  let path = _extends({}, useResolvedPath(action ? action : ".", {
1038
1077
  relative
1039
1078
  }));
1040
- // Previously we set the default action to ".". The problem with this is that
1041
- // `useResolvedPath(".")` excludes search params of the resolved URL. This is
1042
- // the intended behavior of when "." is specifically provided as
1043
- // the form action, but inconsistent w/ browsers when the action is omitted.
1079
+ // If no action was specified, browsers will persist current search params
1080
+ // when determining the path, so match that behavior
1044
1081
  // https://github.com/remix-run/remix/issues/927
1045
1082
  let location = useLocation();
1046
1083
  if (action == null) {
@@ -1082,10 +1119,10 @@ function useFetcher(_temp3) {
1082
1119
  router
1083
1120
  } = useDataRouterContext(DataRouterHook.UseFetcher);
1084
1121
  let state = useDataRouterState(DataRouterStateHook.UseFetcher);
1085
- let fetchersContext = React.useContext(FetchersContext);
1122
+ let fetcherData = React.useContext(FetchersContext);
1086
1123
  let route = React.useContext(UNSAFE_RouteContext);
1087
1124
  let routeId = (_route$matches = route.matches[route.matches.length - 1]) == null ? void 0 : _route$matches.route.id;
1088
- !fetchersContext ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "useFetcher must be used inside a FetchersContext") : UNSAFE_invariant(false) : void 0;
1125
+ !fetcherData ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "useFetcher must be used inside a FetchersContext") : UNSAFE_invariant(false) : void 0;
1089
1126
  !route ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "useFetcher must be used inside a RouteContext") : UNSAFE_invariant(false) : void 0;
1090
1127
  !(routeId != null) ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "useFetcher can only be used on routes that contain a unique \"id\"") : UNSAFE_invariant(false) : void 0;
1091
1128
  // Fetcher key handling
@@ -1094,26 +1131,19 @@ function useFetcher(_temp3) {
1094
1131
  setFetcherKey(getUniqueFetcherId());
1095
1132
  }
1096
1133
  // Registration/cleanup
1097
- let {
1098
- fetcherData,
1099
- register,
1100
- unregister
1101
- } = fetchersContext;
1102
1134
  React.useEffect(() => {
1103
- register(fetcherKey);
1135
+ router.getFetcher(fetcherKey);
1104
1136
  return () => {
1105
- // Unregister from ref counting for the data layer
1106
- unregister(fetcherKey);
1107
1137
  // Tell the router we've unmounted - if v7_fetcherPersist is enabled this
1108
1138
  // will not delete immediately but instead queue up a delete after the
1109
1139
  // fetcher returns to an `idle` state
1110
1140
  router.deleteFetcher(fetcherKey);
1111
1141
  };
1112
- }, [router, fetcherKey, register, unregister]);
1142
+ }, [router, fetcherKey]);
1113
1143
  // Fetcher additions
1114
- let load = React.useCallback(href => {
1144
+ let load = React.useCallback((href, opts) => {
1115
1145
  !routeId ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "No routeId available for fetcher.load()") : UNSAFE_invariant(false) : void 0;
1116
- router.fetch(fetcherKey, routeId, href);
1146
+ router.fetch(fetcherKey, routeId, href, opts);
1117
1147
  }, [fetcherKey, routeId, router]);
1118
1148
  let submitImpl = useSubmit();
1119
1149
  let submit = React.useCallback((target, opts) => {
@@ -1312,7 +1342,7 @@ function usePrompt(_ref12) {
1312
1342
  when,
1313
1343
  message
1314
1344
  } = _ref12;
1315
- let blocker = unstable_useBlocker(when);
1345
+ let blocker = useBlocker(when);
1316
1346
  React.useEffect(() => {
1317
1347
  if (blocker.state === "blocked") {
1318
1348
  let proceed = window.confirm(message);