@ereo/client 0.1.22 → 0.1.24

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/index.js CHANGED
@@ -248,14 +248,111 @@ function cleanupIslands() {
248
248
  islandRegistry.cleanupAll();
249
249
  }
250
250
 
251
+ // src/view-transition.ts
252
+ import { createContext, useContext } from "react";
253
+ function isViewTransitionSupported() {
254
+ return typeof document !== "undefined" && "startViewTransition" in document;
255
+ }
256
+ function startViewTransition(callback, options) {
257
+ if (!isViewTransitionSupported()) {
258
+ const result = callback();
259
+ if (result && typeof result.then === "function") {
260
+ result.catch(() => {});
261
+ }
262
+ return null;
263
+ }
264
+ if (options?.className) {
265
+ document.documentElement.classList.add(options.className);
266
+ }
267
+ const transition = document.startViewTransition(callback);
268
+ if (options?.className) {
269
+ const className = options.className;
270
+ transition.finished.then(() => {
271
+ document.documentElement.classList.remove(className);
272
+ }).catch(() => {
273
+ document.documentElement.classList.remove(className);
274
+ });
275
+ }
276
+ return transition;
277
+ }
278
+ var ViewTransitionContext = createContext({
279
+ isTransitioning: false,
280
+ currentTransition: null
281
+ });
282
+ function useViewTransitionState() {
283
+ const context = useContext(ViewTransitionContext);
284
+ return {
285
+ isTransitioning: context.isTransitioning,
286
+ currentTransition: context.currentTransition
287
+ };
288
+ }
289
+ var viewTransitionsEnabled = false;
290
+ var globalTransitionOptions;
291
+ function enableViewTransitions(options) {
292
+ viewTransitionsEnabled = true;
293
+ globalTransitionOptions = options;
294
+ }
295
+ function disableViewTransitions() {
296
+ viewTransitionsEnabled = false;
297
+ globalTransitionOptions = undefined;
298
+ }
299
+ function areViewTransitionsEnabled() {
300
+ return viewTransitionsEnabled;
301
+ }
302
+ function resetViewTransitions() {
303
+ viewTransitionsEnabled = false;
304
+ globalTransitionOptions = undefined;
305
+ }
306
+
251
307
  // src/navigation.ts
252
308
  class ClientRouter {
253
309
  listeners = new Set;
254
310
  currentState;
311
+ blockers = new Set;
312
+ blockerListeners = new Set;
313
+ pendingNavigation = null;
255
314
  constructor() {
256
315
  this.currentState = this.getStateFromLocation();
257
316
  this.setupPopState();
258
317
  }
318
+ addBlocker(fn) {
319
+ this.blockers.add(fn);
320
+ return () => this.blockers.delete(fn);
321
+ }
322
+ isBlocked() {
323
+ for (const fn of this.blockers) {
324
+ if (fn())
325
+ return true;
326
+ }
327
+ return false;
328
+ }
329
+ subscribeBlocker(listener) {
330
+ this.blockerListeners.add(listener);
331
+ return () => this.blockerListeners.delete(listener);
332
+ }
333
+ notifyBlockers() {
334
+ for (const listener of this.blockerListeners) {
335
+ listener();
336
+ }
337
+ }
338
+ proceedNavigation() {
339
+ const pending = this.pendingNavigation;
340
+ this.pendingNavigation = null;
341
+ const savedBlockers = new Set(this.blockers);
342
+ this.blockers.clear();
343
+ this.notifyBlockers();
344
+ if (pending) {
345
+ this.navigate(pending.to, pending.options).then(() => {
346
+ for (const fn of savedBlockers) {
347
+ this.blockers.add(fn);
348
+ }
349
+ });
350
+ }
351
+ }
352
+ resetNavigation() {
353
+ this.pendingNavigation = null;
354
+ this.notifyBlockers();
355
+ }
259
356
  getStateFromLocation() {
260
357
  if (typeof window === "undefined") {
261
358
  return { pathname: "/", search: "", hash: "" };
@@ -271,6 +368,16 @@ class ClientRouter {
271
368
  if (typeof window === "undefined")
272
369
  return;
273
370
  window.addEventListener("popstate", (event) => {
371
+ if (this.isBlocked()) {
372
+ const current = this.currentState;
373
+ window.history.pushState(current.state, "", current.pathname + current.search + current.hash);
374
+ this.pendingNavigation = {
375
+ to: window.location.pathname + window.location.search + window.location.hash,
376
+ options: {}
377
+ };
378
+ this.notifyBlockers();
379
+ return;
380
+ }
274
381
  const from = this.currentState;
275
382
  this.currentState = this.getStateFromLocation();
276
383
  this.notify({
@@ -283,25 +390,39 @@ class ClientRouter {
283
390
  async navigate(to, options = {}) {
284
391
  if (typeof window === "undefined")
285
392
  return;
286
- const url = new URL(to, window.location.origin);
287
- const from = this.currentState;
288
- const newState = {
289
- pathname: url.pathname,
290
- search: url.search,
291
- hash: url.hash,
292
- state: options.state
393
+ if (this.isBlocked()) {
394
+ this.pendingNavigation = { to, options };
395
+ this.notifyBlockers();
396
+ return;
397
+ }
398
+ const useTransition = options.viewTransition === true ? areViewTransitionsEnabled() || options.viewTransition : options.viewTransition ? true : areViewTransitionsEnabled();
399
+ const transitionOptions = typeof options.viewTransition === "object" ? options.viewTransition : undefined;
400
+ const doNavigate = () => {
401
+ const url = new URL(to, window.location.origin);
402
+ const from = this.currentState;
403
+ const newState = {
404
+ pathname: url.pathname,
405
+ search: url.search,
406
+ hash: url.hash,
407
+ state: options.state
408
+ };
409
+ if (options.replace) {
410
+ window.history.replaceState(options.state, "", to);
411
+ } else {
412
+ window.history.pushState(options.state, "", to);
413
+ }
414
+ this.currentState = newState;
415
+ this.notify({
416
+ type: options.replace ? "replace" : "push",
417
+ from,
418
+ to: newState
419
+ });
293
420
  };
294
- if (options.replace) {
295
- window.history.replaceState(options.state, "", to);
421
+ if (useTransition) {
422
+ startViewTransition(doNavigate, transitionOptions);
296
423
  } else {
297
- window.history.pushState(options.state, "", to);
424
+ doNavigate();
298
425
  }
299
- this.currentState = newState;
300
- this.notify({
301
- type: options.replace ? "replace" : "push",
302
- from,
303
- to: newState
304
- });
305
426
  }
306
427
  back() {
307
428
  if (typeof window !== "undefined") {
@@ -543,63 +664,149 @@ function isPrefetched(url) {
543
664
  }
544
665
  // src/hooks.ts
545
666
  import {
546
- createContext,
547
- useContext,
548
- useState,
549
- useCallback,
667
+ createContext as createContext3,
668
+ useContext as useContext3,
669
+ useState as useState3,
670
+ useCallback as useCallback2,
671
+ useMemo as useMemo2,
672
+ createElement as createElement2
673
+ } from "react";
674
+
675
+ // src/matches.ts
676
+ import {
677
+ createContext as createContext2,
678
+ useContext as useContext2,
679
+ useState as useState2,
550
680
  useMemo,
551
681
  createElement
552
682
  } from "react";
553
- var LoaderDataContext = createContext(null);
554
- var ActionDataContext = createContext(null);
555
- var NavigationContext = createContext(null);
556
- var ErrorContext = createContext(null);
683
+ var MatchesContext = createContext2(null);
684
+ function useMatches() {
685
+ const context = useContext2(MatchesContext);
686
+ if (context === null) {
687
+ throw new Error("useMatches must be used within an EreoProvider. " + "Make sure your component is wrapped with <EreoProvider>.");
688
+ }
689
+ return context.matches;
690
+ }
691
+ function MatchesProvider({
692
+ children,
693
+ initialMatches = []
694
+ }) {
695
+ const [matches, setMatches] = useState2(initialMatches);
696
+ const value = useMemo(() => ({ matches, setMatches }), [matches]);
697
+ return createElement(MatchesContext.Provider, { value }, children);
698
+ }
699
+
700
+ // src/hooks.ts
701
+ var LoaderDataContext = createContext3(null);
702
+ var ActionDataContext = createContext3(null);
703
+ var NavigationContext = createContext3(null);
704
+ var ErrorContext = createContext3(null);
705
+ var ParamsContext = createContext3(null);
706
+ var LocationContext = createContext3(null);
557
707
  function useLoaderData() {
558
- const context = useContext(LoaderDataContext);
708
+ const context = useContext3(LoaderDataContext);
559
709
  if (context === null) {
560
710
  throw new Error("useLoaderData must be used within an EreoProvider. " + "Make sure your component is wrapped with <EreoProvider>.");
561
711
  }
562
712
  return context.data;
563
713
  }
714
+ function useRouteLoaderData(routeId) {
715
+ const context = useContext3(MatchesContext);
716
+ if (context === null) {
717
+ return;
718
+ }
719
+ const match = context.matches.find((m) => m.id === routeId);
720
+ return match?.data;
721
+ }
564
722
  function useActionData() {
565
- const context = useContext(ActionDataContext);
723
+ const context = useContext3(ActionDataContext);
566
724
  if (context === null) {
567
725
  return;
568
726
  }
569
727
  return context.data;
570
728
  }
571
729
  function useNavigation() {
572
- const context = useContext(NavigationContext);
730
+ const context = useContext3(NavigationContext);
573
731
  if (context === null) {
574
732
  throw new Error("useNavigation must be used within an EreoProvider. " + "Make sure your component is wrapped with <EreoProvider>.");
575
733
  }
576
734
  return context.state;
577
735
  }
578
736
  function useError() {
579
- const context = useContext(ErrorContext);
737
+ const context = useContext3(ErrorContext);
580
738
  if (context === null) {
581
739
  throw new Error("useError must be used within an EreoProvider. " + "Make sure your component is wrapped with <EreoProvider>.");
582
740
  }
583
741
  return context.error;
584
742
  }
743
+ function useParams() {
744
+ const context = useContext3(ParamsContext);
745
+ if (context === null) {
746
+ throw new Error("useParams must be used within an EreoProvider. " + "Make sure your component is wrapped with <EreoProvider>.");
747
+ }
748
+ return context.params;
749
+ }
750
+ function useSearchParams() {
751
+ const locationCtx = useContext3(LocationContext);
752
+ if (locationCtx === null) {
753
+ throw new Error("useSearchParams must be used within an EreoProvider. " + "Make sure your component is wrapped with <EreoProvider>.");
754
+ }
755
+ const searchParams = useMemo2(() => new URLSearchParams(locationCtx.location.search), [locationCtx.location.search]);
756
+ const setSearchParams = useCallback2((nextParams, options) => {
757
+ let resolved;
758
+ if (typeof nextParams === "function") {
759
+ const result = nextParams(searchParams);
760
+ resolved = result instanceof URLSearchParams ? result : new URLSearchParams(result);
761
+ } else if (nextParams instanceof URLSearchParams) {
762
+ resolved = nextParams;
763
+ } else {
764
+ resolved = new URLSearchParams(nextParams);
765
+ }
766
+ const newSearch = resolved.toString();
767
+ const newLocation = {
768
+ ...locationCtx.location,
769
+ search: newSearch ? `?${newSearch}` : "",
770
+ key: Math.random().toString(36).slice(2, 10)
771
+ };
772
+ locationCtx.setLocation(newLocation);
773
+ if (typeof window !== "undefined") {
774
+ const url = new URL(window.location.href);
775
+ url.search = newLocation.search;
776
+ if (options?.replace) {
777
+ window.history.replaceState(locationCtx.location.state, "", url.toString());
778
+ } else {
779
+ window.history.pushState(locationCtx.location.state, "", url.toString());
780
+ }
781
+ }
782
+ }, [searchParams, locationCtx]);
783
+ return [searchParams, setSearchParams];
784
+ }
785
+ function useLocation() {
786
+ const context = useContext3(LocationContext);
787
+ if (context === null) {
788
+ throw new Error("useLocation must be used within an EreoProvider. " + "Make sure your component is wrapped with <EreoProvider>.");
789
+ }
790
+ return context.location;
791
+ }
585
792
  function LoaderDataProvider({
586
793
  children,
587
794
  initialData
588
795
  }) {
589
- const [data, setData] = useState(initialData);
590
- const value = useMemo(() => ({ data, setData }), [data]);
591
- return createElement(LoaderDataContext.Provider, { value }, children);
796
+ const [data, setData] = useState3(initialData);
797
+ const value = useMemo2(() => ({ data, setData }), [data]);
798
+ return createElement2(LoaderDataContext.Provider, { value }, children);
592
799
  }
593
800
  function ActionDataProvider({
594
801
  children,
595
802
  initialData
596
803
  }) {
597
- const [data, setData] = useState(initialData);
598
- const clearData = useCallback(() => {
804
+ const [data, setData] = useState3(initialData);
805
+ const clearData = useCallback2(() => {
599
806
  setData(undefined);
600
807
  }, []);
601
- const value = useMemo(() => ({ data, setData, clearData }), [data, clearData]);
602
- return createElement(ActionDataContext.Provider, { value }, children);
808
+ const value = useMemo2(() => ({ data, setData, clearData }), [data, clearData]);
809
+ return createElement2(ActionDataContext.Provider, { value }, children);
603
810
  }
604
811
  var defaultNavigationState = {
605
812
  status: "idle"
@@ -608,14 +815,14 @@ function NavigationProvider({
608
815
  children,
609
816
  initialState = defaultNavigationState
610
817
  }) {
611
- const [state, setState] = useState(initialState);
612
- const startLoading = useCallback((location) => {
818
+ const [state, setState] = useState3(initialState);
819
+ const startLoading = useCallback2((location) => {
613
820
  setState({
614
821
  status: "loading",
615
822
  location
616
823
  });
617
824
  }, []);
618
- const startSubmitting = useCallback((options) => {
825
+ const startSubmitting = useCallback2((options) => {
619
826
  setState({
620
827
  status: "submitting",
621
828
  location: options.location,
@@ -624,61 +831,87 @@ function NavigationProvider({
624
831
  formAction: options.formAction
625
832
  });
626
833
  }, []);
627
- const complete = useCallback(() => {
834
+ const complete = useCallback2(() => {
628
835
  setState({ status: "idle" });
629
836
  }, []);
630
- const value = useMemo(() => ({
837
+ const value = useMemo2(() => ({
631
838
  state,
632
839
  setState,
633
840
  startLoading,
634
841
  startSubmitting,
635
842
  complete
636
843
  }), [state, startLoading, startSubmitting, complete]);
637
- return createElement(NavigationContext.Provider, { value }, children);
844
+ return createElement2(NavigationContext.Provider, { value }, children);
638
845
  }
639
846
  function ErrorProvider({
640
847
  children,
641
848
  initialError
642
849
  }) {
643
- const [error, setError] = useState(initialError);
644
- const clearError = useCallback(() => {
850
+ const [error, setError] = useState3(initialError);
851
+ const clearError = useCallback2(() => {
645
852
  setError(undefined);
646
853
  }, []);
647
- const value = useMemo(() => ({ error, setError, clearError }), [error, clearError]);
648
- return createElement(ErrorContext.Provider, { value }, children);
854
+ const value = useMemo2(() => ({ error, setError, clearError }), [error, clearError]);
855
+ return createElement2(ErrorContext.Provider, { value }, children);
856
+ }
857
+ function ParamsProvider({
858
+ children,
859
+ initialParams = {}
860
+ }) {
861
+ const [params, setParams] = useState3(initialParams);
862
+ const value = useMemo2(() => ({ params, setParams }), [params]);
863
+ return createElement2(ParamsContext.Provider, { value }, children);
864
+ }
865
+ var defaultLocation = {
866
+ pathname: "/",
867
+ search: "",
868
+ hash: "",
869
+ state: null,
870
+ key: "default"
871
+ };
872
+ function LocationProvider({
873
+ children,
874
+ initialLocation = defaultLocation
875
+ }) {
876
+ const [location, setLocation] = useState3(initialLocation);
877
+ const value = useMemo2(() => ({ location, setLocation }), [location]);
878
+ return createElement2(LocationContext.Provider, { value }, children);
649
879
  }
650
880
  function EreoProvider({
651
881
  children,
652
882
  loaderData,
653
883
  actionData,
654
884
  navigationState,
655
- error
885
+ error,
886
+ params,
887
+ location,
888
+ matches
656
889
  }) {
657
- return createElement(ErrorProvider, { initialError: error, children: createElement(NavigationProvider, { initialState: navigationState, children: createElement(ActionDataProvider, { initialData: actionData, children: createElement(LoaderDataProvider, { initialData: loaderData, children }) }) }) });
890
+ return createElement2(MatchesProvider, { initialMatches: matches, children: createElement2(LocationProvider, { initialLocation: location, children: createElement2(ParamsProvider, { initialParams: params, children: createElement2(ErrorProvider, { initialError: error, children: createElement2(NavigationProvider, { initialState: navigationState, children: createElement2(ActionDataProvider, { initialData: actionData, children: createElement2(LoaderDataProvider, { initialData: loaderData, children }) }) }) }) }) }) });
658
891
  }
659
892
  function useLoaderDataContext() {
660
- const context = useContext(LoaderDataContext);
893
+ const context = useContext3(LoaderDataContext);
661
894
  if (context === null) {
662
895
  throw new Error("useLoaderDataContext must be used within an EreoProvider");
663
896
  }
664
897
  return context;
665
898
  }
666
899
  function useActionDataContext() {
667
- const context = useContext(ActionDataContext);
900
+ const context = useContext3(ActionDataContext);
668
901
  if (context === null) {
669
902
  throw new Error("useActionDataContext must be used within an EreoProvider");
670
903
  }
671
904
  return context;
672
905
  }
673
906
  function useNavigationContext() {
674
- const context = useContext(NavigationContext);
907
+ const context = useContext3(NavigationContext);
675
908
  if (context === null) {
676
909
  throw new Error("useNavigationContext must be used within an EreoProvider");
677
910
  }
678
911
  return context;
679
912
  }
680
913
  function useErrorContext() {
681
- const context = useContext(ErrorContext);
914
+ const context = useContext3(ErrorContext);
682
915
  if (context === null) {
683
916
  throw new Error("useErrorContext must be used within an EreoProvider");
684
917
  }
@@ -720,6 +953,7 @@ var Link = React.forwardRef(function Link2({
720
953
  preventScrollReset = false,
721
954
  state,
722
955
  reloadDocument = false,
956
+ viewTransition,
723
957
  onClick,
724
958
  onMouseEnter,
725
959
  onFocus,
@@ -751,11 +985,11 @@ var Link = React.forwardRef(function Link2({
751
985
  return;
752
986
  }
753
987
  event.preventDefault();
754
- navigate(destination, { replace, state });
988
+ navigate(destination, { replace, state, viewTransition });
755
989
  if (!preventScrollReset && typeof window !== "undefined") {
756
990
  window.scrollTo(0, 0);
757
991
  }
758
- }, [onClick, destination, replace, state, isExternal, reloadDocument, preventScrollReset]);
992
+ }, [onClick, destination, replace, state, isExternal, reloadDocument, preventScrollReset, viewTransition]);
759
993
  const handleMouseEnter = React.useCallback((event) => {
760
994
  onMouseEnter?.(event);
761
995
  if (prefetchStrategy === "intent") {
@@ -1278,18 +1512,52 @@ async function preloadRoute(path, options) {
1278
1512
  } catch {}
1279
1513
  }
1280
1514
  // src/form.ts
1281
- import { createElement as createElement2, useCallback as useCallback4, useRef as useRef3, useState as useState4, useEffect as useEffect3, useContext as useContext2, createContext as createContext2 } from "react";
1282
- var FormContext = createContext2(null);
1515
+ import { createElement as createElement3, useCallback as useCallback5, useRef as useRef3, useState as useState6, useEffect as useEffect4, useContext as useContext4, createContext as createContext4 } from "react";
1516
+ var FormContext = createContext4(null);
1283
1517
  function FormProvider({
1284
1518
  children,
1285
1519
  initialActionData
1286
1520
  }) {
1287
- const [actionData, setActionData] = useState4(initialActionData);
1288
- const [state, setState] = useState4("idle");
1289
- return createElement2(FormContext.Provider, { value: { actionData, state, setActionData, setState } }, children);
1521
+ const [actionData, setActionData] = useState6(initialActionData);
1522
+ const [state, setState] = useState6("idle");
1523
+ return createElement3(FormContext.Provider, { value: { actionData, state, setActionData, setState } }, children);
1290
1524
  }
1291
1525
  function useFormContext() {
1292
- return useContext2(FormContext);
1526
+ return useContext4(FormContext);
1527
+ }
1528
+ var fetcherRegistry = new Map;
1529
+ var fetcherListeners = new Set;
1530
+ var fetcherIdCounter = 0;
1531
+ function generateFetcherId() {
1532
+ return `__fetcher_${++fetcherIdCounter}`;
1533
+ }
1534
+ function registerFetcher(id, state) {
1535
+ fetcherRegistry.set(id, state);
1536
+ notifyFetcherListeners();
1537
+ }
1538
+ function updateFetcherInRegistry(id, state) {
1539
+ if (fetcherRegistry.has(id)) {
1540
+ fetcherRegistry.set(id, state);
1541
+ notifyFetcherListeners();
1542
+ }
1543
+ }
1544
+ function unregisterFetcher(id) {
1545
+ fetcherRegistry.delete(id);
1546
+ notifyFetcherListeners();
1547
+ }
1548
+ function notifyFetcherListeners() {
1549
+ for (const listener of fetcherListeners) {
1550
+ listener();
1551
+ }
1552
+ }
1553
+ function subscribeFetcherRegistry(listener) {
1554
+ fetcherListeners.add(listener);
1555
+ return () => {
1556
+ fetcherListeners.delete(listener);
1557
+ };
1558
+ }
1559
+ function getFetcherRegistrySnapshot() {
1560
+ return Array.from(fetcherRegistry.values());
1293
1561
  }
1294
1562
  function Form({
1295
1563
  method = "post",
@@ -1307,7 +1575,7 @@ function Form({
1307
1575
  const formRef = useRef3(null);
1308
1576
  const formContext = useFormContext();
1309
1577
  const resolvedAction = action ?? (typeof window !== "undefined" ? window.location.pathname : "");
1310
- const handleSubmit = useCallback4(async (event) => {
1578
+ const handleSubmit = useCallback5(async (event) => {
1311
1579
  if (onSubmit) {
1312
1580
  onSubmit(event);
1313
1581
  if (event.defaultPrevented) {
@@ -1410,14 +1678,14 @@ function Form({
1410
1678
  }
1411
1679
  }, [method, resolvedAction, onSubmitStart, onSubmitEnd, replace, preventScrollReset, encType, fetcherKey, formContext, onSubmit]);
1412
1680
  const formMethod = method.toLowerCase() === "get" ? "get" : "post";
1413
- return createElement2("form", {
1681
+ return createElement3("form", {
1414
1682
  ref: formRef,
1415
1683
  method: formMethod,
1416
1684
  action: resolvedAction,
1417
1685
  encType,
1418
1686
  onSubmit: handleSubmit,
1419
1687
  ...props
1420
- }, method !== "get" && method !== "post" ? createElement2("input", {
1688
+ }, method !== "get" && method !== "post" ? createElement3("input", {
1421
1689
  type: "hidden",
1422
1690
  name: "_method",
1423
1691
  value: method.toUpperCase()
@@ -1425,7 +1693,7 @@ function Form({
1425
1693
  }
1426
1694
  function useSubmit() {
1427
1695
  const formContext = useFormContext();
1428
- const submit = useCallback4(async (target, options = {}) => {
1696
+ const submit = useCallback5(async (target, options = {}) => {
1429
1697
  const {
1430
1698
  method = "post",
1431
1699
  action,
@@ -1532,25 +1800,39 @@ function useSubmit() {
1532
1800
  return submit;
1533
1801
  }
1534
1802
  function useFetcher(key) {
1535
- const [state, setStateInternal] = useState4("idle");
1536
- const [data, setData] = useState4(undefined);
1537
- const [error, setError] = useState4(undefined);
1538
- const [formData, setFormData] = useState4(undefined);
1539
- const [formMethod, setFormMethod] = useState4(undefined);
1540
- const [formAction, setFormAction] = useState4(undefined);
1803
+ const [state, setStateInternal] = useState6("idle");
1804
+ const [data, setData] = useState6(undefined);
1805
+ const [error, setError] = useState6(undefined);
1806
+ const [formData, setFormData] = useState6(undefined);
1807
+ const [formMethod, setFormMethod] = useState6(undefined);
1808
+ const [formAction, setFormAction] = useState6(undefined);
1809
+ const fetcherIdRef = useRef3(key || generateFetcherId());
1541
1810
  const mountedRef = useRef3(true);
1542
- useEffect3(() => {
1811
+ useEffect4(() => {
1543
1812
  mountedRef.current = true;
1813
+ const id = fetcherIdRef.current;
1814
+ registerFetcher(id, { state: "idle" });
1544
1815
  return () => {
1545
1816
  mountedRef.current = false;
1817
+ unregisterFetcher(id);
1546
1818
  };
1547
1819
  }, []);
1548
- const safeSetState = useCallback4((newState) => {
1820
+ useEffect4(() => {
1821
+ updateFetcherInRegistry(fetcherIdRef.current, {
1822
+ state,
1823
+ data,
1824
+ error,
1825
+ formData,
1826
+ formMethod,
1827
+ formAction
1828
+ });
1829
+ }, [state, data, error, formData, formMethod, formAction]);
1830
+ const safeSetState = useCallback5((newState) => {
1549
1831
  if (mountedRef.current) {
1550
1832
  setStateInternal(newState);
1551
1833
  }
1552
1834
  }, []);
1553
- const reset = useCallback4(() => {
1835
+ const reset = useCallback5(() => {
1554
1836
  if (mountedRef.current) {
1555
1837
  setStateInternal("idle");
1556
1838
  setData(undefined);
@@ -1560,7 +1842,7 @@ function useFetcher(key) {
1560
1842
  setFormAction(undefined);
1561
1843
  }
1562
1844
  }, []);
1563
- const submit = useCallback4(async (target, options = {}) => {
1845
+ const submit = useCallback5(async (target, options = {}) => {
1564
1846
  const {
1565
1847
  method = "post",
1566
1848
  action,
@@ -1648,7 +1930,7 @@ function useFetcher(key) {
1648
1930
  }
1649
1931
  }
1650
1932
  }, [safeSetState]);
1651
- const load = useCallback4(async (href) => {
1933
+ const load = useCallback5(async (href) => {
1652
1934
  if (typeof window === "undefined") {
1653
1935
  return;
1654
1936
  }
@@ -1674,7 +1956,7 @@ function useFetcher(key) {
1674
1956
  }
1675
1957
  }
1676
1958
  }, [safeSetState]);
1677
- const FetcherForm = useCallback4((formProps) => {
1959
+ const FetcherForm = useCallback5((formProps) => {
1678
1960
  return Form({
1679
1961
  ...formProps,
1680
1962
  fetcherKey: key || "fetcher",
@@ -1718,14 +2000,14 @@ function useActionData2() {
1718
2000
  return context?.actionData;
1719
2001
  }
1720
2002
  function useNavigation2() {
1721
- const [navigationState, setNavigationState] = useState4(() => {
2003
+ const [navigationState, setNavigationState] = useState6(() => {
1722
2004
  if (typeof window === "undefined") {
1723
2005
  return { pathname: "/", search: "", hash: "" };
1724
2006
  }
1725
2007
  return router.getState();
1726
2008
  });
1727
2009
  const formContext = useFormContext();
1728
- useEffect3(() => {
2010
+ useEffect4(() => {
1729
2011
  return router.subscribe((event) => {
1730
2012
  setNavigationState(event.to);
1731
2013
  });
@@ -1735,6 +2017,15 @@ function useNavigation2() {
1735
2017
  state: formContext?.state || "idle"
1736
2018
  };
1737
2019
  }
2020
+ function useFetchers() {
2021
+ const [fetchers, setFetchers] = useState6(() => getFetcherRegistrySnapshot());
2022
+ useEffect4(() => {
2023
+ return subscribeFetcherRegistry(() => {
2024
+ setFetchers(getFetcherRegistrySnapshot());
2025
+ });
2026
+ }, []);
2027
+ return fetchers;
2028
+ }
1738
2029
  function serializeFormData(formData) {
1739
2030
  const params = new URLSearchParams;
1740
2031
  formData.forEach((value, key) => {
@@ -1781,10 +2072,168 @@ function objectToFormData(obj) {
1781
2072
  }
1782
2073
  return formData;
1783
2074
  }
2075
+ // src/revalidation.ts
2076
+ import {
2077
+ useState as useState7,
2078
+ useCallback as useCallback6,
2079
+ useContext as useContext5
2080
+ } from "react";
2081
+ function getRoutesToRevalidate(routes, nextParams, context) {
2082
+ const routeIds = [];
2083
+ for (const route of routes) {
2084
+ const shouldRevalidateFn = route.module?.shouldRevalidate;
2085
+ if (!shouldRevalidateFn) {
2086
+ if (route.module?.loader) {
2087
+ routeIds.push(route.id);
2088
+ }
2089
+ continue;
2090
+ }
2091
+ if (!route.module?.loader) {
2092
+ continue;
2093
+ }
2094
+ const args = {
2095
+ currentUrl: context.currentUrl,
2096
+ nextUrl: context.nextUrl,
2097
+ currentParams: route.params,
2098
+ nextParams,
2099
+ formMethod: context.formMethod,
2100
+ formAction: context.formAction,
2101
+ formData: context.formData,
2102
+ actionResult: context.actionResult,
2103
+ defaultShouldRevalidate: true
2104
+ };
2105
+ try {
2106
+ if (shouldRevalidateFn(args)) {
2107
+ routeIds.push(route.id);
2108
+ }
2109
+ } catch (error) {
2110
+ console.error(`shouldRevalidate threw for route "${route.id}", defaulting to revalidate:`, error);
2111
+ routeIds.push(route.id);
2112
+ }
2113
+ }
2114
+ return routeIds;
2115
+ }
2116
+ function checkShouldRevalidate(shouldRevalidateFn, args) {
2117
+ if (!shouldRevalidateFn) {
2118
+ return args.defaultShouldRevalidate;
2119
+ }
2120
+ try {
2121
+ return shouldRevalidateFn(args);
2122
+ } catch {
2123
+ return args.defaultShouldRevalidate;
2124
+ }
2125
+ }
2126
+ function useRevalidator() {
2127
+ const [state, setState] = useState7("idle");
2128
+ const loaderCtx = useContext5(LoaderDataContext);
2129
+ const matchesCtx = useContext5(MatchesContext);
2130
+ const revalidate = useCallback6(async () => {
2131
+ if (typeof window === "undefined")
2132
+ return;
2133
+ setState("loading");
2134
+ try {
2135
+ const response = await fetch(window.location.href, {
2136
+ headers: { Accept: "application/json" }
2137
+ });
2138
+ if (!response.ok) {
2139
+ throw new Error(`Revalidation failed: ${response.status}`);
2140
+ }
2141
+ const result = await response.json();
2142
+ if (loaderCtx) {
2143
+ loaderCtx.setData(result.data);
2144
+ }
2145
+ if (matchesCtx && result.matches) {
2146
+ matchesCtx.setMatches(result.matches);
2147
+ }
2148
+ } catch (error) {
2149
+ console.error("Revalidation error:", error);
2150
+ } finally {
2151
+ setState("idle");
2152
+ }
2153
+ }, [loaderCtx, matchesCtx]);
2154
+ return { state, revalidate };
2155
+ }
2156
+ // src/use-navigation-type.ts
2157
+ import { useState as useState8, useEffect as useEffect5 } from "react";
2158
+ function useNavigationType() {
2159
+ const [type, setType] = useState8("push");
2160
+ useEffect5(() => {
2161
+ return router.subscribe((event) => {
2162
+ setType(event.type);
2163
+ });
2164
+ }, []);
2165
+ return type;
2166
+ }
2167
+ // src/use-before-unload.ts
2168
+ import { useRef as useRef4, useEffect as useEffect6 } from "react";
2169
+ function useBeforeUnload(callback, options) {
2170
+ const callbackRef = useRef4(callback);
2171
+ callbackRef.current = callback;
2172
+ useEffect6(() => {
2173
+ if (typeof window === "undefined")
2174
+ return;
2175
+ const handler = (event) => {
2176
+ callbackRef.current(event);
2177
+ };
2178
+ const capture = options?.capture ?? false;
2179
+ window.addEventListener("beforeunload", handler, { capture });
2180
+ return () => {
2181
+ window.removeEventListener("beforeunload", handler, { capture });
2182
+ };
2183
+ }, [options?.capture]);
2184
+ }
2185
+ // src/blocker.ts
2186
+ import { useState as useState9, useEffect as useEffect7, useCallback as useCallback8, useRef as useRef5 } from "react";
2187
+ function useBlocker(shouldBlock) {
2188
+ const [state, setState] = useState9("unblocked");
2189
+ const shouldBlockRef = useRef5(shouldBlock);
2190
+ shouldBlockRef.current = shouldBlock;
2191
+ useEffect7(() => {
2192
+ if (typeof window === "undefined")
2193
+ return;
2194
+ const blockerFn = () => {
2195
+ const block = typeof shouldBlockRef.current === "function" ? shouldBlockRef.current() : shouldBlockRef.current;
2196
+ return block;
2197
+ };
2198
+ const removeBlocker = router.addBlocker(blockerFn);
2199
+ const removeListener = router.subscribeBlocker(() => {
2200
+ if (router.pendingNavigation) {
2201
+ setState("blocked");
2202
+ } else {
2203
+ setState("unblocked");
2204
+ }
2205
+ });
2206
+ return () => {
2207
+ removeBlocker();
2208
+ removeListener();
2209
+ };
2210
+ }, []);
2211
+ useEffect7(() => {
2212
+ if (typeof window === "undefined")
2213
+ return;
2214
+ const handleBeforeUnload = (e) => {
2215
+ const block = typeof shouldBlockRef.current === "function" ? shouldBlockRef.current() : shouldBlockRef.current;
2216
+ if (block) {
2217
+ e.preventDefault();
2218
+ }
2219
+ };
2220
+ window.addEventListener("beforeunload", handleBeforeUnload);
2221
+ return () => window.removeEventListener("beforeunload", handleBeforeUnload);
2222
+ }, []);
2223
+ const proceed = useCallback8(() => {
2224
+ setState("proceeding");
2225
+ router.proceedNavigation();
2226
+ }, []);
2227
+ const reset = useCallback8(() => {
2228
+ setState("unblocked");
2229
+ router.resetNavigation();
2230
+ }, []);
2231
+ return { state, proceed, reset };
2232
+ }
1784
2233
  // src/error-boundary.tsx
1785
2234
  import React3, {
1786
2235
  Component,
1787
- useContext as useContext3
2236
+ useContext as useContext6
1788
2237
  } from "react";
1789
2238
  class ErrorBoundary extends Component {
1790
2239
  constructor(props) {
@@ -1843,7 +2292,7 @@ class ErrorBoundary extends Component {
1843
2292
  }
1844
2293
  }
1845
2294
  function useErrorBoundary() {
1846
- const context = useContext3(ErrorContext);
2295
+ const context = useContext6(ErrorContext);
1847
2296
  if (!context) {
1848
2297
  throw new Error("useErrorBoundary must be used within an EreoProvider or ErrorProvider. " + "Make sure your component is wrapped with the appropriate provider.");
1849
2298
  }
@@ -1854,7 +2303,7 @@ function useErrorBoundary() {
1854
2303
  };
1855
2304
  }
1856
2305
  function useRouteError() {
1857
- const context = useContext3(ErrorContext);
2306
+ const context = useContext6(ErrorContext);
1858
2307
  return context?.error;
1859
2308
  }
1860
2309
 
@@ -1985,6 +2434,235 @@ class RouteError extends Error {
1985
2434
  };
1986
2435
  }
1987
2436
  }
2437
+ // src/outlet.ts
2438
+ import {
2439
+ createContext as createContext5,
2440
+ useContext as useContext7,
2441
+ createElement as createElement4
2442
+ } from "react";
2443
+ var OutletElementContext = createContext5(null);
2444
+ var OutletDataContext = createContext5(null);
2445
+ function Outlet({ context } = {}) {
2446
+ const elementCtx = useContext7(OutletElementContext);
2447
+ if (elementCtx === null) {
2448
+ return null;
2449
+ }
2450
+ const child = elementCtx.element;
2451
+ if (context !== undefined) {
2452
+ return createElement4(OutletDataContext.Provider, { value: { data: context } }, child);
2453
+ }
2454
+ return child;
2455
+ }
2456
+ function useOutletContext() {
2457
+ const context = useContext7(OutletDataContext);
2458
+ if (context === null) {
2459
+ throw new Error("useOutletContext must be used within a route rendered by an <Outlet> " + "that has a context prop. Make sure the parent layout passes context " + "via <Outlet context={...} />.");
2460
+ }
2461
+ return context.data;
2462
+ }
2463
+ function OutletProvider({
2464
+ children,
2465
+ element,
2466
+ context
2467
+ }) {
2468
+ const elementValue = { element };
2469
+ let tree = createElement4(OutletElementContext.Provider, { value: elementValue }, children);
2470
+ if (context !== undefined) {
2471
+ tree = createElement4(OutletDataContext.Provider, { value: { data: context } }, tree);
2472
+ }
2473
+ return tree;
2474
+ }
2475
+ // src/route-links.ts
2476
+ var EREO_LINK_ATTR = "data-ereo-link";
2477
+ var activeLinks = [];
2478
+ function renderLinkTags(links) {
2479
+ return links.map((link) => {
2480
+ const attrs = Object.entries(link).filter(([, v]) => v !== undefined).map(([k, v]) => `${k}="${escapeAttr(String(v))}"`).join(" ");
2481
+ return `<link ${attrs} ${EREO_LINK_ATTR}>`;
2482
+ }).join(`
2483
+ `);
2484
+ }
2485
+ function updateRouteLinks(links) {
2486
+ if (typeof document === "undefined")
2487
+ return;
2488
+ removeRouteLinks();
2489
+ const head = document.head;
2490
+ const newLinks = [];
2491
+ for (const descriptor of links) {
2492
+ const link = document.createElement("link");
2493
+ for (const [key, value] of Object.entries(descriptor)) {
2494
+ if (value !== undefined) {
2495
+ link.setAttribute(key, String(value));
2496
+ }
2497
+ }
2498
+ link.setAttribute(EREO_LINK_ATTR, "");
2499
+ head.appendChild(link);
2500
+ newLinks.push(link);
2501
+ }
2502
+ activeLinks = newLinks;
2503
+ }
2504
+ function removeRouteLinks() {
2505
+ if (typeof document === "undefined")
2506
+ return;
2507
+ for (const link of activeLinks) {
2508
+ link.parentNode?.removeChild(link);
2509
+ }
2510
+ activeLinks = [];
2511
+ }
2512
+ function getActiveLinksCount() {
2513
+ return activeLinks.length;
2514
+ }
2515
+ function escapeAttr(s) {
2516
+ return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;");
2517
+ }
2518
+ // src/client-data.ts
2519
+ async function executeClientLoader(clientLoader, pathname, params, request) {
2520
+ const req = request ?? new Request(typeof window !== "undefined" ? window.location.href : `http://localhost${pathname}`);
2521
+ const serverLoader = async () => {
2522
+ return fetchLoaderData(pathname, params);
2523
+ };
2524
+ const args = {
2525
+ params,
2526
+ request: req,
2527
+ serverLoader
2528
+ };
2529
+ return clientLoader(args);
2530
+ }
2531
+ async function executeClientAction(clientAction, pathname, params, request) {
2532
+ const serverAction = async () => {
2533
+ const formData = await request.clone().formData().catch(() => {
2534
+ return;
2535
+ });
2536
+ return submitAction(pathname, formData ?? new FormData);
2537
+ };
2538
+ const args = {
2539
+ params,
2540
+ request,
2541
+ serverAction
2542
+ };
2543
+ return clientAction(args);
2544
+ }
2545
+ function shouldHydrateClientLoader(clientLoader) {
2546
+ if (!clientLoader)
2547
+ return false;
2548
+ return clientLoader.hydrate === true;
2549
+ }
2550
+ function getHydrateFallback(module) {
2551
+ if (!module)
2552
+ return;
2553
+ if (!shouldHydrateClientLoader(module.clientLoader))
2554
+ return;
2555
+ return module.HydrateFallback;
2556
+ }
2557
+ // src/lazy-route.ts
2558
+ var lazyRoutes = new Map;
2559
+ var moduleCache = new Map;
2560
+ var loadingPromises = new Map;
2561
+ function registerLazyRoute(id, path, loader) {
2562
+ lazyRoutes.set(id, {
2563
+ id,
2564
+ path,
2565
+ loader,
2566
+ loaded: false
2567
+ });
2568
+ }
2569
+ function registerLazyRoutes(routes) {
2570
+ for (const [id, { path, loader }] of Object.entries(routes)) {
2571
+ registerLazyRoute(id, path, loader);
2572
+ }
2573
+ }
2574
+ async function loadLazyRoute(id) {
2575
+ const cached = moduleCache.get(id);
2576
+ if (cached)
2577
+ return cached;
2578
+ const inflight = loadingPromises.get(id);
2579
+ if (inflight)
2580
+ return inflight;
2581
+ const route = lazyRoutes.get(id);
2582
+ if (!route) {
2583
+ throw new Error(`Lazy route "${id}" is not registered. ` + "Make sure to call registerLazyRoute() before loading.");
2584
+ }
2585
+ const promise = route.loader().then((module) => {
2586
+ moduleCache.set(id, module);
2587
+ route.loaded = true;
2588
+ route.module = module;
2589
+ loadingPromises.delete(id);
2590
+ return module;
2591
+ }).catch((error) => {
2592
+ loadingPromises.delete(id);
2593
+ throw error;
2594
+ });
2595
+ loadingPromises.set(id, promise);
2596
+ return promise;
2597
+ }
2598
+ async function preloadLazyRoute(id) {
2599
+ if (moduleCache.has(id))
2600
+ return;
2601
+ await loadLazyRoute(id);
2602
+ }
2603
+ function isRouteLoaded(id) {
2604
+ return moduleCache.has(id);
2605
+ }
2606
+ function getLoadedModule(id) {
2607
+ return moduleCache.get(id);
2608
+ }
2609
+ function getLazyRouteIds() {
2610
+ return Array.from(lazyRoutes.keys());
2611
+ }
2612
+ function clearLazyRouteCache() {
2613
+ moduleCache.clear();
2614
+ loadingPromises.clear();
2615
+ for (const route of lazyRoutes.values()) {
2616
+ route.loaded = false;
2617
+ route.module = undefined;
2618
+ }
2619
+ }
2620
+ function resetLazyRoutes() {
2621
+ lazyRoutes.clear();
2622
+ moduleCache.clear();
2623
+ loadingPromises.clear();
2624
+ }
2625
+ var manifest = null;
2626
+ function setRouteManifest(m) {
2627
+ manifest = m;
2628
+ }
2629
+ function getRouteManifestEntry(id) {
2630
+ return manifest?.[id];
2631
+ }
2632
+ function preloadRouteAssets(id) {
2633
+ if (typeof document === "undefined")
2634
+ return;
2635
+ if (!manifest)
2636
+ return;
2637
+ const entry = manifest[id];
2638
+ if (!entry)
2639
+ return;
2640
+ const head = document.head;
2641
+ const existing = new Set(Array.from(head.querySelectorAll('link[rel="modulepreload"], link[rel="preload"]')).map((el) => el.getAttribute("href")));
2642
+ if (!existing.has(entry.js)) {
2643
+ const link = document.createElement("link");
2644
+ link.rel = "modulepreload";
2645
+ link.href = entry.js;
2646
+ head.appendChild(link);
2647
+ }
2648
+ for (const css of entry.css || []) {
2649
+ if (!existing.has(css)) {
2650
+ const link = document.createElement("link");
2651
+ link.rel = "preload";
2652
+ link.href = css;
2653
+ link.as = "style";
2654
+ head.appendChild(link);
2655
+ }
2656
+ }
2657
+ for (const imp of entry.imports || []) {
2658
+ if (!existing.has(imp)) {
2659
+ const link = document.createElement("link");
2660
+ link.rel = "modulepreload";
2661
+ link.href = imp;
2662
+ head.appendChild(link);
2663
+ }
2664
+ }
2665
+ }
1988
2666
  // src/await.tsx
1989
2667
  import { jsxDEV as jsxDEV3, Fragment } from "react/jsx-dev-runtime";
1990
2668
  var promiseCache = new WeakMap;
@@ -2054,6 +2732,98 @@ function isDeferredData(value) {
2054
2732
  async function resolveAwait(deferred) {
2055
2733
  return deferred.promise;
2056
2734
  }
2735
+ // src/scroll-restoration.ts
2736
+ import { useEffect as useEffect8, useRef as useRef6, createElement as createElement5 } from "react";
2737
+ var memoryStore = new Map;
2738
+ function getScrollPosition(key, storageKey) {
2739
+ if (typeof sessionStorage !== "undefined") {
2740
+ try {
2741
+ const stored = sessionStorage.getItem(`${storageKey}:${key}`);
2742
+ if (stored)
2743
+ return JSON.parse(stored);
2744
+ } catch {}
2745
+ }
2746
+ return memoryStore.get(key);
2747
+ }
2748
+ function saveScrollPosition(key, position, storageKey) {
2749
+ if (typeof sessionStorage !== "undefined") {
2750
+ try {
2751
+ sessionStorage.setItem(`${storageKey}:${key}`, JSON.stringify(position));
2752
+ return;
2753
+ } catch {}
2754
+ }
2755
+ memoryStore.set(key, position);
2756
+ }
2757
+ function clearScrollPositions() {
2758
+ memoryStore.clear();
2759
+ }
2760
+ function ScrollRestoration({
2761
+ getKey,
2762
+ nonce,
2763
+ storageKey = "ereo-scroll"
2764
+ } = {}) {
2765
+ const isSetup = useRef6(false);
2766
+ useEffect8(() => {
2767
+ if (typeof window === "undefined")
2768
+ return;
2769
+ if (isSetup.current)
2770
+ return;
2771
+ isSetup.current = true;
2772
+ if ("scrollRestoration" in history) {
2773
+ history.scrollRestoration = "manual";
2774
+ }
2775
+ const keyFn = getKey ?? ((pathname) => pathname);
2776
+ const unsubscribe = router.subscribe((event) => {
2777
+ const fromKey = keyFn(event.from.pathname);
2778
+ saveScrollPosition(fromKey, { x: window.scrollX, y: window.scrollY }, storageKey);
2779
+ if (event.type === "pop") {
2780
+ const toKey = keyFn(event.to.pathname);
2781
+ const saved = getScrollPosition(toKey, storageKey);
2782
+ if (saved) {
2783
+ requestAnimationFrame(() => {
2784
+ window.scrollTo(saved.x, saved.y);
2785
+ });
2786
+ }
2787
+ } else {
2788
+ if (event.to.hash) {
2789
+ requestAnimationFrame(() => {
2790
+ const target = document.getElementById(event.to.hash.slice(1));
2791
+ if (target) {
2792
+ target.scrollIntoView();
2793
+ } else {
2794
+ window.scrollTo(0, 0);
2795
+ }
2796
+ });
2797
+ } else {
2798
+ window.scrollTo(0, 0);
2799
+ }
2800
+ }
2801
+ });
2802
+ const handleBeforeUnload = () => {
2803
+ const currentKey = keyFn(window.location.pathname);
2804
+ saveScrollPosition(currentKey, { x: window.scrollX, y: window.scrollY }, storageKey);
2805
+ };
2806
+ window.addEventListener("beforeunload", handleBeforeUnload);
2807
+ return () => {
2808
+ unsubscribe();
2809
+ window.removeEventListener("beforeunload", handleBeforeUnload);
2810
+ if ("scrollRestoration" in history) {
2811
+ history.scrollRestoration = "auto";
2812
+ }
2813
+ isSetup.current = false;
2814
+ };
2815
+ }, [getKey, storageKey]);
2816
+ if (nonce !== undefined) {
2817
+ return createElement5("script", {
2818
+ nonce,
2819
+ suppressHydrationWarning: true,
2820
+ dangerouslySetInnerHTML: {
2821
+ __html: `if("scrollRestoration" in history)history.scrollRestoration="manual";`
2822
+ }
2823
+ });
2824
+ }
2825
+ return null;
2826
+ }
2057
2827
 
2058
2828
  // src/index.ts
2059
2829
  function initClient() {
@@ -2063,11 +2833,20 @@ function initClient() {
2063
2833
  }
2064
2834
  export {
2065
2835
  withErrorBoundary,
2836
+ useViewTransitionState,
2066
2837
  useTypedNavigate,
2067
2838
  useSubmit,
2839
+ useSearchParams,
2840
+ useRouteLoaderData,
2068
2841
  useRouteError,
2842
+ useRevalidator,
2843
+ useParams,
2844
+ useOutletContext,
2845
+ useNavigationType,
2069
2846
  useNavigationContext,
2070
2847
  useNavigation,
2848
+ useMatches,
2849
+ useLocation,
2071
2850
  useLoaderDataContext,
2072
2851
  useLoaderData,
2073
2852
  useIsRouteActive,
@@ -2075,30 +2854,45 @@ export {
2075
2854
  useNavigation2 as useFormNavigation,
2076
2855
  useFormContext,
2077
2856
  useActionData2 as useFormActionData,
2857
+ useFetchers,
2078
2858
  useFetcher,
2079
2859
  useErrorContext,
2080
2860
  useErrorBoundary,
2081
2861
  useError,
2862
+ useBlocker,
2863
+ useBeforeUnload,
2082
2864
  useActionDataContext,
2083
2865
  useActionData,
2866
+ updateRouteLinks,
2084
2867
  typedRedirect,
2085
2868
  typedNavigate,
2086
2869
  goForward2 as typedGoForward,
2087
2870
  goBack2 as typedGoBack,
2088
2871
  submitAction,
2089
2872
  stripHydrationProps,
2873
+ startViewTransition,
2874
+ shouldHydrateClientLoader,
2090
2875
  shouldHydrate,
2091
2876
  setupScrollRestoration,
2092
2877
  setupLinkPrefetch,
2093
2878
  setupAutoPrefetch,
2879
+ setRouteManifest,
2094
2880
  serializeFormData,
2095
2881
  router,
2096
2882
  resolveAwait,
2883
+ resetViewTransitions,
2884
+ resetLazyRoutes,
2097
2885
  resetIslandCounter,
2886
+ renderLinkTags,
2887
+ removeRouteLinks,
2888
+ registerLazyRoutes,
2889
+ registerLazyRoute,
2098
2890
  registerIslandComponents,
2099
2891
  registerIslandComponent,
2100
2892
  redirect,
2893
+ preloadRouteAssets,
2101
2894
  preloadRoute,
2895
+ preloadLazyRoute,
2102
2896
  prefetchAll,
2103
2897
  prefetch,
2104
2898
  parseTypedSearchParams,
@@ -2108,7 +2902,10 @@ export {
2108
2902
  onNavigate,
2109
2903
  objectToFormData,
2110
2904
  navigate,
2905
+ loadLazyRoute,
2111
2906
  islandRegistry,
2907
+ isViewTransitionSupported,
2908
+ isRouteLoaded,
2112
2909
  isRouteErrorResponse,
2113
2910
  isPrefetching,
2114
2911
  isPrefetched,
@@ -2119,27 +2916,53 @@ export {
2119
2916
  goForward,
2120
2917
  goBack,
2121
2918
  go,
2919
+ getRoutesToRevalidate,
2920
+ getRouteManifestEntry,
2122
2921
  getPrefetchedData,
2123
2922
  getNavigationState,
2923
+ getLoadedModule,
2924
+ getLazyRouteIds,
2124
2925
  getIslandCount,
2125
2926
  getIslandComponent,
2927
+ getHydrateFallback,
2928
+ getActiveLinksCount,
2126
2929
  generateIslandId,
2127
2930
  formDataToObject,
2128
2931
  fetchLoaderData,
2932
+ executeClientLoader,
2933
+ executeClientAction,
2934
+ enableViewTransitions,
2935
+ disableViewTransitions,
2129
2936
  createRouteErrorResponse,
2130
2937
  createIsland,
2131
2938
  createHydrationTrigger,
2939
+ clearScrollPositions,
2132
2940
  clearPrefetchCache,
2941
+ clearLazyRouteCache,
2133
2942
  cleanupIslands,
2943
+ checkShouldRevalidate,
2134
2944
  buildUrl,
2135
2945
  buildTypedUrl,
2946
+ areViewTransitionsEnabled,
2947
+ ViewTransitionContext,
2136
2948
  TypedNavLink,
2137
2949
  TypedLink,
2950
+ ScrollRestoration,
2138
2951
  RouteErrorBoundary,
2139
2952
  RouteError,
2953
+ ParamsProvider,
2954
+ ParamsContext,
2955
+ OutletProvider,
2956
+ OutletElementContext,
2957
+ OutletDataContext,
2958
+ Outlet,
2140
2959
  NavigationProvider,
2141
2960
  NavigationContext,
2142
2961
  NavLink,
2962
+ MatchesProvider,
2963
+ MatchesContext,
2964
+ LocationProvider,
2965
+ LocationContext,
2143
2966
  LoaderDataProvider,
2144
2967
  LoaderDataContext,
2145
2968
  Link,