@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/blocker.d.ts +55 -0
- package/dist/blocker.d.ts.map +1 -0
- package/dist/client-data.d.ts +43 -0
- package/dist/client-data.d.ts.map +1 -0
- package/dist/form.d.ts +6 -1
- package/dist/form.d.ts.map +1 -1
- package/dist/hooks.d.ts +153 -1
- package/dist/hooks.d.ts.map +1 -1
- package/dist/index.d.ts +24 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +903 -80
- package/dist/lazy-route.d.ts +137 -0
- package/dist/lazy-route.d.ts.map +1 -0
- package/dist/link.d.ts +3 -0
- package/dist/link.d.ts.map +1 -1
- package/dist/matches.d.ts +93 -0
- package/dist/matches.d.ts.map +1 -0
- package/dist/navigation.d.ts +45 -0
- package/dist/navigation.d.ts.map +1 -1
- package/dist/outlet.d.ts +150 -0
- package/dist/outlet.d.ts.map +1 -0
- package/dist/revalidation.d.ts +85 -0
- package/dist/revalidation.d.ts.map +1 -0
- package/dist/route-links.d.ts +30 -0
- package/dist/route-links.d.ts.map +1 -0
- package/dist/scroll-restoration.d.ts +64 -0
- package/dist/scroll-restoration.d.ts.map +1 -0
- package/dist/use-before-unload.d.ts +25 -0
- package/dist/use-before-unload.d.ts.map +1 -0
- package/dist/use-navigation-type.d.ts +18 -0
- package/dist/use-navigation-type.d.ts.map +1 -0
- package/dist/view-transition.d.ts +136 -0
- package/dist/view-transition.d.ts.map +1 -0
- package/package.json +2 -2
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
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
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 (
|
|
295
|
-
|
|
421
|
+
if (useTransition) {
|
|
422
|
+
startViewTransition(doNavigate, transitionOptions);
|
|
296
423
|
} else {
|
|
297
|
-
|
|
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
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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] =
|
|
590
|
-
const value =
|
|
591
|
-
return
|
|
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] =
|
|
598
|
-
const clearData =
|
|
804
|
+
const [data, setData] = useState3(initialData);
|
|
805
|
+
const clearData = useCallback2(() => {
|
|
599
806
|
setData(undefined);
|
|
600
807
|
}, []);
|
|
601
|
-
const value =
|
|
602
|
-
return
|
|
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] =
|
|
612
|
-
const startLoading =
|
|
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 =
|
|
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 =
|
|
834
|
+
const complete = useCallback2(() => {
|
|
628
835
|
setState({ status: "idle" });
|
|
629
836
|
}, []);
|
|
630
|
-
const value =
|
|
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
|
|
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] =
|
|
644
|
-
const clearError =
|
|
850
|
+
const [error, setError] = useState3(initialError);
|
|
851
|
+
const clearError = useCallback2(() => {
|
|
645
852
|
setError(undefined);
|
|
646
853
|
}, []);
|
|
647
|
-
const value =
|
|
648
|
-
return
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
1282
|
-
var FormContext =
|
|
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] =
|
|
1288
|
-
const [state, setState] =
|
|
1289
|
-
return
|
|
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
|
|
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 =
|
|
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
|
|
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" ?
|
|
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 =
|
|
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] =
|
|
1536
|
-
const [data, setData] =
|
|
1537
|
-
const [error, setError] =
|
|
1538
|
-
const [formData, setFormData] =
|
|
1539
|
-
const [formMethod, setFormMethod] =
|
|
1540
|
-
const [formAction, setFormAction] =
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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] =
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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, "&").replace(/"/g, """).replace(/</g, "<");
|
|
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,
|