@tanstack/react-router 0.0.1-beta.69 → 0.0.1-beta.70
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/build/cjs/index.js +26 -20
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.js +21 -15
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +81 -51
- package/build/types/index.d.ts +3 -3
- package/build/umd/index.development.js +281 -244
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +4 -4
- package/build/umd/index.production.js.map +1 -1
- package/package.json +2 -2
- package/src/index.tsx +34 -44
|
@@ -59,6 +59,24 @@
|
|
|
59
59
|
throw new Error(value);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
function warning(condition, message) {
|
|
63
|
+
{
|
|
64
|
+
if (condition) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
var text = "Warning: " + message;
|
|
69
|
+
|
|
70
|
+
if (typeof console !== 'undefined') {
|
|
71
|
+
console.warn(text);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
throw Error(text);
|
|
76
|
+
} catch (x) {}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
62
80
|
/**
|
|
63
81
|
* store
|
|
64
82
|
*
|
|
@@ -261,15 +279,6 @@
|
|
|
261
279
|
function last(arr) {
|
|
262
280
|
return arr[arr.length - 1];
|
|
263
281
|
}
|
|
264
|
-
function warning(cond, message) {
|
|
265
|
-
if (cond) {
|
|
266
|
-
if (typeof console !== 'undefined') console.warn(message);
|
|
267
|
-
try {
|
|
268
|
-
throw new Error(message);
|
|
269
|
-
} catch {}
|
|
270
|
-
}
|
|
271
|
-
return true;
|
|
272
|
-
}
|
|
273
282
|
function isFunction(d) {
|
|
274
283
|
return typeof d === 'function';
|
|
275
284
|
}
|
|
@@ -481,6 +490,9 @@
|
|
|
481
490
|
const baseSegments = parsePathname(from);
|
|
482
491
|
const to = `${matchLocation.to ?? '$'}`;
|
|
483
492
|
const routeSegments = parsePathname(to);
|
|
493
|
+
if (last(baseSegments)?.value === '/') {
|
|
494
|
+
baseSegments.pop();
|
|
495
|
+
}
|
|
484
496
|
const params = {};
|
|
485
497
|
let isMatch = (() => {
|
|
486
498
|
for (let i = 0; i < Math.max(baseSegments.length, routeSegments.length); i++) {
|
|
@@ -686,211 +698,6 @@
|
|
|
686
698
|
// const config = rootRoute.addChildren([aRoute.addChildren([bRoute])])
|
|
687
699
|
// // ^?
|
|
688
700
|
|
|
689
|
-
const componentTypes = ['component', 'errorComponent', 'pendingComponent'];
|
|
690
|
-
class RouteMatch {
|
|
691
|
-
abortController = new AbortController();
|
|
692
|
-
onLoaderDataListeners = new Set();
|
|
693
|
-
constructor(router, route, opts) {
|
|
694
|
-
Object.assign(this, {
|
|
695
|
-
route,
|
|
696
|
-
router,
|
|
697
|
-
id: opts.id,
|
|
698
|
-
pathname: opts.pathname,
|
|
699
|
-
params: opts.params,
|
|
700
|
-
store: new Store({
|
|
701
|
-
updatedAt: 0,
|
|
702
|
-
routeSearch: {},
|
|
703
|
-
search: {},
|
|
704
|
-
status: 'idle'
|
|
705
|
-
}, {
|
|
706
|
-
onUpdate: next => {
|
|
707
|
-
this.state = next;
|
|
708
|
-
}
|
|
709
|
-
})
|
|
710
|
-
});
|
|
711
|
-
this.state = this.store.state;
|
|
712
|
-
componentTypes.map(async type => {
|
|
713
|
-
const component = this.route.options[type];
|
|
714
|
-
if (typeof this[type] !== 'function') {
|
|
715
|
-
this[type] = component;
|
|
716
|
-
}
|
|
717
|
-
});
|
|
718
|
-
if (this.state.status === 'idle' && !this.#hasLoaders()) {
|
|
719
|
-
this.store.setState(s => ({
|
|
720
|
-
...s,
|
|
721
|
-
status: 'success'
|
|
722
|
-
}));
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
#hasLoaders = () => {
|
|
726
|
-
return !!(this.route.options.onLoad || componentTypes.some(d => this.route.options[d]?.preload));
|
|
727
|
-
};
|
|
728
|
-
__commit = () => {
|
|
729
|
-
const {
|
|
730
|
-
routeSearch,
|
|
731
|
-
search,
|
|
732
|
-
context,
|
|
733
|
-
routeContext
|
|
734
|
-
} = this.#resolveInfo({
|
|
735
|
-
location: this.router.state.currentLocation
|
|
736
|
-
});
|
|
737
|
-
this.context = context;
|
|
738
|
-
this.routeContext = routeContext;
|
|
739
|
-
this.store.setState(s => ({
|
|
740
|
-
...s,
|
|
741
|
-
routeSearch: replaceEqualDeep(s.routeSearch, routeSearch),
|
|
742
|
-
search: replaceEqualDeep(s.search, search)
|
|
743
|
-
}));
|
|
744
|
-
};
|
|
745
|
-
cancel = () => {
|
|
746
|
-
this.abortController?.abort();
|
|
747
|
-
};
|
|
748
|
-
#resolveSearchInfo = opts => {
|
|
749
|
-
// Validate the search params and stabilize them
|
|
750
|
-
const parentSearchInfo = this.parentMatch ? this.parentMatch.#resolveSearchInfo(opts) : {
|
|
751
|
-
search: opts.location.search,
|
|
752
|
-
routeSearch: opts.location.search
|
|
753
|
-
};
|
|
754
|
-
try {
|
|
755
|
-
const validator = typeof this.route.options.validateSearch === 'object' ? this.route.options.validateSearch.parse : this.route.options.validateSearch;
|
|
756
|
-
const routeSearch = validator?.(parentSearchInfo.search) ?? {};
|
|
757
|
-
const search = {
|
|
758
|
-
...parentSearchInfo.search,
|
|
759
|
-
...routeSearch
|
|
760
|
-
};
|
|
761
|
-
return {
|
|
762
|
-
routeSearch,
|
|
763
|
-
search
|
|
764
|
-
};
|
|
765
|
-
} catch (err) {
|
|
766
|
-
this.route.options.onValidateSearchError?.(err);
|
|
767
|
-
const error = new Error('Invalid search params found', {
|
|
768
|
-
cause: err
|
|
769
|
-
});
|
|
770
|
-
error.code = 'INVALID_SEARCH_PARAMS';
|
|
771
|
-
throw error;
|
|
772
|
-
}
|
|
773
|
-
};
|
|
774
|
-
#resolveInfo = opts => {
|
|
775
|
-
const {
|
|
776
|
-
search,
|
|
777
|
-
routeSearch
|
|
778
|
-
} = this.#resolveSearchInfo(opts);
|
|
779
|
-
const routeContext = this.route.options.getContext?.({
|
|
780
|
-
parentContext: this.parentMatch?.routeContext ?? {},
|
|
781
|
-
context: this.parentMatch?.context ?? this.router?.options.context ?? {},
|
|
782
|
-
params: this.params,
|
|
783
|
-
search
|
|
784
|
-
}) || {};
|
|
785
|
-
const context = {
|
|
786
|
-
...(this.parentMatch?.context ?? this.router?.options.context),
|
|
787
|
-
...routeContext
|
|
788
|
-
};
|
|
789
|
-
return {
|
|
790
|
-
routeSearch,
|
|
791
|
-
search,
|
|
792
|
-
context,
|
|
793
|
-
routeContext
|
|
794
|
-
};
|
|
795
|
-
};
|
|
796
|
-
__load = async opts => {
|
|
797
|
-
this.parentMatch = opts.parentMatch;
|
|
798
|
-
let info;
|
|
799
|
-
try {
|
|
800
|
-
info = this.#resolveInfo(opts);
|
|
801
|
-
} catch (err) {
|
|
802
|
-
this.route.options.onError?.(err);
|
|
803
|
-
this.store.setState(s => ({
|
|
804
|
-
...s,
|
|
805
|
-
status: 'error',
|
|
806
|
-
error: err
|
|
807
|
-
}));
|
|
808
|
-
|
|
809
|
-
// Do not proceed with loading the route
|
|
810
|
-
return;
|
|
811
|
-
}
|
|
812
|
-
const {
|
|
813
|
-
routeSearch,
|
|
814
|
-
search,
|
|
815
|
-
context,
|
|
816
|
-
routeContext
|
|
817
|
-
} = info;
|
|
818
|
-
|
|
819
|
-
// If the match is invalid, errored or idle, trigger it to load
|
|
820
|
-
if (this.state.status === 'pending') {
|
|
821
|
-
return;
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
// TODO: Should load promises be tracked based on location?
|
|
825
|
-
this.__loadPromise = Promise.resolve().then(async () => {
|
|
826
|
-
const loadId = '' + Date.now() + Math.random();
|
|
827
|
-
this.#latestId = loadId;
|
|
828
|
-
const checkLatest = () => {
|
|
829
|
-
return loadId !== this.#latestId ? this.__loadPromise : undefined;
|
|
830
|
-
};
|
|
831
|
-
let latestPromise;
|
|
832
|
-
|
|
833
|
-
// If the match was in an error state, set it
|
|
834
|
-
// to a loading state again. Otherwise, keep it
|
|
835
|
-
// as loading or resolved
|
|
836
|
-
if (this.state.status === 'idle') {
|
|
837
|
-
this.store.setState(s => ({
|
|
838
|
-
...s,
|
|
839
|
-
status: 'pending'
|
|
840
|
-
}));
|
|
841
|
-
}
|
|
842
|
-
const componentsPromise = (async () => {
|
|
843
|
-
// then run all component and data loaders in parallel
|
|
844
|
-
// For each component type, potentially load it asynchronously
|
|
845
|
-
|
|
846
|
-
await Promise.all(componentTypes.map(async type => {
|
|
847
|
-
const component = this.route.options[type];
|
|
848
|
-
if (this[type]?.preload) {
|
|
849
|
-
this[type] = await this.router.options.loadComponent(component);
|
|
850
|
-
}
|
|
851
|
-
}));
|
|
852
|
-
})();
|
|
853
|
-
const dataPromise = Promise.resolve().then(() => {
|
|
854
|
-
if (this.route.options.onLoad) {
|
|
855
|
-
return this.route.options.onLoad({
|
|
856
|
-
params: this.params,
|
|
857
|
-
routeSearch,
|
|
858
|
-
search,
|
|
859
|
-
signal: this.abortController.signal,
|
|
860
|
-
preload: !!opts?.preload,
|
|
861
|
-
routeContext: routeContext,
|
|
862
|
-
context: context
|
|
863
|
-
});
|
|
864
|
-
}
|
|
865
|
-
return;
|
|
866
|
-
});
|
|
867
|
-
try {
|
|
868
|
-
await Promise.all([componentsPromise, dataPromise]);
|
|
869
|
-
if (latestPromise = checkLatest()) return await latestPromise;
|
|
870
|
-
this.store.setState(s => ({
|
|
871
|
-
...s,
|
|
872
|
-
error: undefined,
|
|
873
|
-
status: 'success',
|
|
874
|
-
updatedAt: Date.now()
|
|
875
|
-
}));
|
|
876
|
-
} catch (err) {
|
|
877
|
-
this.route.options.onLoadError?.(err);
|
|
878
|
-
this.route.options.onError?.(err);
|
|
879
|
-
this.store.setState(s => ({
|
|
880
|
-
...s,
|
|
881
|
-
error: err,
|
|
882
|
-
status: 'error',
|
|
883
|
-
updatedAt: Date.now()
|
|
884
|
-
}));
|
|
885
|
-
} finally {
|
|
886
|
-
delete this.__loadPromise;
|
|
887
|
-
}
|
|
888
|
-
});
|
|
889
|
-
return this.__loadPromise;
|
|
890
|
-
};
|
|
891
|
-
#latestId = '';
|
|
892
|
-
}
|
|
893
|
-
|
|
894
701
|
const defaultParseSearch = parseSearchWith(JSON.parse);
|
|
895
702
|
const defaultStringifySearch = stringifySearchWith(JSON.stringify);
|
|
896
703
|
function parseSearchWith(parser) {
|
|
@@ -991,9 +798,9 @@
|
|
|
991
798
|
mount = () => {
|
|
992
799
|
// Mount only does anything on the client
|
|
993
800
|
if (!isServer) {
|
|
994
|
-
// If the router matches are empty,
|
|
801
|
+
// If the router matches are empty, start loading the matches
|
|
995
802
|
if (!this.state.currentMatches.length) {
|
|
996
|
-
this.
|
|
803
|
+
this.safeLoad();
|
|
997
804
|
}
|
|
998
805
|
const visibilityChangeEvent = 'visibilitychange';
|
|
999
806
|
const focusEvent = 'focus';
|
|
@@ -1031,7 +838,7 @@
|
|
|
1031
838
|
currentLocation: parsedLocation
|
|
1032
839
|
}));
|
|
1033
840
|
this.#unsubHistory = this.history.listen(() => {
|
|
1034
|
-
this.
|
|
841
|
+
this.safeLoad({
|
|
1035
842
|
next: this.#parseLocation(this.state.latestLocation)
|
|
1036
843
|
});
|
|
1037
844
|
});
|
|
@@ -1063,6 +870,12 @@
|
|
|
1063
870
|
match.cancel();
|
|
1064
871
|
});
|
|
1065
872
|
};
|
|
873
|
+
safeLoad = opts => {
|
|
874
|
+
this.load(opts).catch(err => {
|
|
875
|
+
console.warn(err);
|
|
876
|
+
invariant(false, 'Encountered an error during router.load()! ☝️.');
|
|
877
|
+
});
|
|
878
|
+
};
|
|
1066
879
|
load = async opts => {
|
|
1067
880
|
let now = Date.now();
|
|
1068
881
|
const startedAt = now;
|
|
@@ -1093,14 +906,10 @@
|
|
|
1093
906
|
});
|
|
1094
907
|
|
|
1095
908
|
// Load the matches
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
} catch (err) {
|
|
1101
|
-
console.warn(err);
|
|
1102
|
-
invariant(false, 'Matches failed to load due to error above ☝️. Navigation cancelled!');
|
|
1103
|
-
}
|
|
909
|
+
await this.loadMatches(matches, this.state.pendingLocation
|
|
910
|
+
// opts
|
|
911
|
+
);
|
|
912
|
+
|
|
1104
913
|
if (this.startedLoadingAt !== startedAt) {
|
|
1105
914
|
// Ignore side-effects of outdated side-effects
|
|
1106
915
|
return this.navigationPromise;
|
|
@@ -1529,7 +1338,7 @@
|
|
|
1529
1338
|
};
|
|
1530
1339
|
};
|
|
1531
1340
|
#onFocus = () => {
|
|
1532
|
-
this.
|
|
1341
|
+
this.safeLoad();
|
|
1533
1342
|
};
|
|
1534
1343
|
#buildLocation = (dest = {}) => {
|
|
1535
1344
|
dest.fromCurrent = dest.fromCurrent ?? dest.to === '';
|
|
@@ -1592,9 +1401,6 @@
|
|
|
1592
1401
|
id,
|
|
1593
1402
|
...next.state
|
|
1594
1403
|
});
|
|
1595
|
-
|
|
1596
|
-
// this.load(this.#parseLocation(this.state.latestLocation))
|
|
1597
|
-
|
|
1598
1404
|
return this.navigationPromise = new Promise(resolve => {
|
|
1599
1405
|
const previousNavigationResolve = this.resolveNavigation;
|
|
1600
1406
|
this.resolveNavigation = () => {
|
|
@@ -1619,6 +1425,229 @@
|
|
|
1619
1425
|
function isCtrlEvent(e) {
|
|
1620
1426
|
return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
|
|
1621
1427
|
}
|
|
1428
|
+
function redirect(opts) {
|
|
1429
|
+
opts.isRedirect = true;
|
|
1430
|
+
return opts;
|
|
1431
|
+
}
|
|
1432
|
+
function isRedirect(obj) {
|
|
1433
|
+
return !!obj?.isRedirect;
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
const componentTypes = ['component', 'errorComponent', 'pendingComponent'];
|
|
1437
|
+
class RouteMatch {
|
|
1438
|
+
abortController = new AbortController();
|
|
1439
|
+
onLoaderDataListeners = new Set();
|
|
1440
|
+
constructor(router, route, opts) {
|
|
1441
|
+
Object.assign(this, {
|
|
1442
|
+
route,
|
|
1443
|
+
router,
|
|
1444
|
+
id: opts.id,
|
|
1445
|
+
pathname: opts.pathname,
|
|
1446
|
+
params: opts.params,
|
|
1447
|
+
store: new Store({
|
|
1448
|
+
updatedAt: 0,
|
|
1449
|
+
routeSearch: {},
|
|
1450
|
+
search: {},
|
|
1451
|
+
status: 'idle'
|
|
1452
|
+
}, {
|
|
1453
|
+
onUpdate: next => {
|
|
1454
|
+
this.state = next;
|
|
1455
|
+
}
|
|
1456
|
+
})
|
|
1457
|
+
});
|
|
1458
|
+
this.state = this.store.state;
|
|
1459
|
+
componentTypes.map(async type => {
|
|
1460
|
+
const component = this.route.options[type];
|
|
1461
|
+
if (typeof this[type] !== 'function') {
|
|
1462
|
+
this[type] = component;
|
|
1463
|
+
}
|
|
1464
|
+
});
|
|
1465
|
+
if (this.state.status === 'idle' && !this.#hasLoaders()) {
|
|
1466
|
+
this.store.setState(s => ({
|
|
1467
|
+
...s,
|
|
1468
|
+
status: 'success'
|
|
1469
|
+
}));
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
#hasLoaders = () => {
|
|
1473
|
+
return !!(this.route.options.onLoad || componentTypes.some(d => this.route.options[d]?.preload));
|
|
1474
|
+
};
|
|
1475
|
+
__commit = () => {
|
|
1476
|
+
const {
|
|
1477
|
+
routeSearch,
|
|
1478
|
+
search,
|
|
1479
|
+
context,
|
|
1480
|
+
routeContext
|
|
1481
|
+
} = this.#resolveInfo({
|
|
1482
|
+
location: this.router.state.currentLocation
|
|
1483
|
+
});
|
|
1484
|
+
this.context = context;
|
|
1485
|
+
this.routeContext = routeContext;
|
|
1486
|
+
this.store.setState(s => ({
|
|
1487
|
+
...s,
|
|
1488
|
+
routeSearch: replaceEqualDeep(s.routeSearch, routeSearch),
|
|
1489
|
+
search: replaceEqualDeep(s.search, search)
|
|
1490
|
+
}));
|
|
1491
|
+
};
|
|
1492
|
+
cancel = () => {
|
|
1493
|
+
this.abortController?.abort();
|
|
1494
|
+
};
|
|
1495
|
+
#resolveSearchInfo = opts => {
|
|
1496
|
+
// Validate the search params and stabilize them
|
|
1497
|
+
const parentSearchInfo = this.parentMatch ? this.parentMatch.#resolveSearchInfo(opts) : {
|
|
1498
|
+
search: opts.location.search,
|
|
1499
|
+
routeSearch: opts.location.search
|
|
1500
|
+
};
|
|
1501
|
+
try {
|
|
1502
|
+
const validator = typeof this.route.options.validateSearch === 'object' ? this.route.options.validateSearch.parse : this.route.options.validateSearch;
|
|
1503
|
+
const routeSearch = validator?.(parentSearchInfo.search) ?? {};
|
|
1504
|
+
const search = {
|
|
1505
|
+
...parentSearchInfo.search,
|
|
1506
|
+
...routeSearch
|
|
1507
|
+
};
|
|
1508
|
+
return {
|
|
1509
|
+
routeSearch,
|
|
1510
|
+
search
|
|
1511
|
+
};
|
|
1512
|
+
} catch (err) {
|
|
1513
|
+
if (isRedirect(err)) {
|
|
1514
|
+
throw err;
|
|
1515
|
+
}
|
|
1516
|
+
this.route.options.onValidateSearchError?.(err);
|
|
1517
|
+
const error = new Error('Invalid search params found', {
|
|
1518
|
+
cause: err
|
|
1519
|
+
});
|
|
1520
|
+
error.code = 'INVALID_SEARCH_PARAMS';
|
|
1521
|
+
throw error;
|
|
1522
|
+
}
|
|
1523
|
+
};
|
|
1524
|
+
#resolveInfo = opts => {
|
|
1525
|
+
const {
|
|
1526
|
+
search,
|
|
1527
|
+
routeSearch
|
|
1528
|
+
} = this.#resolveSearchInfo(opts);
|
|
1529
|
+
const routeContext = this.route.options.getContext?.({
|
|
1530
|
+
parentContext: this.parentMatch?.routeContext ?? {},
|
|
1531
|
+
context: this.parentMatch?.context ?? this.router?.options.context ?? {},
|
|
1532
|
+
params: this.params,
|
|
1533
|
+
search
|
|
1534
|
+
}) || {};
|
|
1535
|
+
const context = {
|
|
1536
|
+
...(this.parentMatch?.context ?? this.router?.options.context),
|
|
1537
|
+
...routeContext
|
|
1538
|
+
};
|
|
1539
|
+
return {
|
|
1540
|
+
routeSearch,
|
|
1541
|
+
search,
|
|
1542
|
+
context,
|
|
1543
|
+
routeContext
|
|
1544
|
+
};
|
|
1545
|
+
};
|
|
1546
|
+
__load = async opts => {
|
|
1547
|
+
this.parentMatch = opts.parentMatch;
|
|
1548
|
+
let info;
|
|
1549
|
+
try {
|
|
1550
|
+
info = this.#resolveInfo(opts);
|
|
1551
|
+
} catch (err) {
|
|
1552
|
+
if (isRedirect(err)) {
|
|
1553
|
+
this.router.navigate(err);
|
|
1554
|
+
return;
|
|
1555
|
+
}
|
|
1556
|
+
this.route.options.onError?.(err);
|
|
1557
|
+
this.store.setState(s => ({
|
|
1558
|
+
...s,
|
|
1559
|
+
status: 'error',
|
|
1560
|
+
error: err
|
|
1561
|
+
}));
|
|
1562
|
+
|
|
1563
|
+
// Do not proceed with loading the route
|
|
1564
|
+
return;
|
|
1565
|
+
}
|
|
1566
|
+
const {
|
|
1567
|
+
routeSearch,
|
|
1568
|
+
search,
|
|
1569
|
+
context,
|
|
1570
|
+
routeContext
|
|
1571
|
+
} = info;
|
|
1572
|
+
|
|
1573
|
+
// If the match is invalid, errored or idle, trigger it to load
|
|
1574
|
+
if (this.state.status === 'pending') {
|
|
1575
|
+
return;
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
// TODO: Should load promises be tracked based on location?
|
|
1579
|
+
this.__loadPromise = Promise.resolve().then(async () => {
|
|
1580
|
+
const loadId = '' + Date.now() + Math.random();
|
|
1581
|
+
this.#latestId = loadId;
|
|
1582
|
+
const checkLatest = () => {
|
|
1583
|
+
return loadId !== this.#latestId ? this.__loadPromise : undefined;
|
|
1584
|
+
};
|
|
1585
|
+
let latestPromise;
|
|
1586
|
+
|
|
1587
|
+
// If the match was in an error state, set it
|
|
1588
|
+
// to a loading state again. Otherwise, keep it
|
|
1589
|
+
// as loading or resolved
|
|
1590
|
+
if (this.state.status === 'idle') {
|
|
1591
|
+
this.store.setState(s => ({
|
|
1592
|
+
...s,
|
|
1593
|
+
status: 'pending'
|
|
1594
|
+
}));
|
|
1595
|
+
}
|
|
1596
|
+
const componentsPromise = (async () => {
|
|
1597
|
+
// then run all component and data loaders in parallel
|
|
1598
|
+
// For each component type, potentially load it asynchronously
|
|
1599
|
+
|
|
1600
|
+
await Promise.all(componentTypes.map(async type => {
|
|
1601
|
+
const component = this.route.options[type];
|
|
1602
|
+
if (this[type]?.preload) {
|
|
1603
|
+
this[type] = await this.router.options.loadComponent(component);
|
|
1604
|
+
}
|
|
1605
|
+
}));
|
|
1606
|
+
})();
|
|
1607
|
+
const dataPromise = Promise.resolve().then(() => {
|
|
1608
|
+
if (this.route.options.onLoad) {
|
|
1609
|
+
return this.route.options.onLoad({
|
|
1610
|
+
params: this.params,
|
|
1611
|
+
routeSearch,
|
|
1612
|
+
search,
|
|
1613
|
+
signal: this.abortController.signal,
|
|
1614
|
+
preload: !!opts?.preload,
|
|
1615
|
+
routeContext: routeContext,
|
|
1616
|
+
context: context
|
|
1617
|
+
});
|
|
1618
|
+
}
|
|
1619
|
+
return;
|
|
1620
|
+
});
|
|
1621
|
+
try {
|
|
1622
|
+
await Promise.all([componentsPromise, dataPromise]);
|
|
1623
|
+
if (latestPromise = checkLatest()) return await latestPromise;
|
|
1624
|
+
this.store.setState(s => ({
|
|
1625
|
+
...s,
|
|
1626
|
+
error: undefined,
|
|
1627
|
+
status: 'success',
|
|
1628
|
+
updatedAt: Date.now()
|
|
1629
|
+
}));
|
|
1630
|
+
} catch (err) {
|
|
1631
|
+
if (isRedirect(err)) {
|
|
1632
|
+
this.router.navigate(err);
|
|
1633
|
+
return;
|
|
1634
|
+
}
|
|
1635
|
+
this.route.options.onLoadError?.(err);
|
|
1636
|
+
this.route.options.onError?.(err);
|
|
1637
|
+
this.store.setState(s => ({
|
|
1638
|
+
...s,
|
|
1639
|
+
error: err,
|
|
1640
|
+
status: 'error',
|
|
1641
|
+
updatedAt: Date.now()
|
|
1642
|
+
}));
|
|
1643
|
+
} finally {
|
|
1644
|
+
delete this.__loadPromise;
|
|
1645
|
+
}
|
|
1646
|
+
});
|
|
1647
|
+
return this.__loadPromise;
|
|
1648
|
+
};
|
|
1649
|
+
#latestId = '';
|
|
1650
|
+
}
|
|
1622
1651
|
|
|
1623
1652
|
/**
|
|
1624
1653
|
* react-store
|
|
@@ -1826,12 +1855,17 @@
|
|
|
1826
1855
|
router.update(rest);
|
|
1827
1856
|
const currentMatches = useStore(router.store, s => s.currentMatches);
|
|
1828
1857
|
React__namespace.useEffect(router.mount, [router]);
|
|
1829
|
-
return /*#__PURE__*/React__namespace.createElement(
|
|
1858
|
+
return /*#__PURE__*/React__namespace.createElement(routerContext.Provider, {
|
|
1830
1859
|
value: {
|
|
1831
1860
|
router: router
|
|
1832
1861
|
}
|
|
1833
1862
|
}, /*#__PURE__*/React__namespace.createElement(matchesContext.Provider, {
|
|
1834
1863
|
value: [undefined, ...currentMatches]
|
|
1864
|
+
}, /*#__PURE__*/React__namespace.createElement(CatchBoundary, {
|
|
1865
|
+
errorComponent: ErrorComponent,
|
|
1866
|
+
onCatch: () => {
|
|
1867
|
+
warning(false, `Error in router! Consider setting an 'errorComponent' in your RootRoute! 👍`);
|
|
1868
|
+
}
|
|
1835
1869
|
}, /*#__PURE__*/React__namespace.createElement(Outlet, null))));
|
|
1836
1870
|
}
|
|
1837
1871
|
function useRouterContext() {
|
|
@@ -1944,23 +1978,24 @@
|
|
|
1944
1978
|
}, []);
|
|
1945
1979
|
const PendingComponent = match.pendingComponent ?? router.options.defaultPendingComponent ?? defaultPending;
|
|
1946
1980
|
const errorComponent = match.errorComponent ?? router.options.defaultErrorComponent;
|
|
1981
|
+
const ResolvedSuspenseBoundary = match.route.options.wrapInSuspense ?? true ? React__namespace.Suspense : SafeFragment;
|
|
1982
|
+
const ResolvedCatchBoundary = errorComponent ? CatchBoundary : SafeFragment;
|
|
1947
1983
|
return /*#__PURE__*/React__namespace.createElement(matchesContext.Provider, {
|
|
1948
1984
|
value: matches
|
|
1949
|
-
},
|
|
1985
|
+
}, /*#__PURE__*/React__namespace.createElement(ResolvedSuspenseBoundary, {
|
|
1950
1986
|
fallback: /*#__PURE__*/React__namespace.createElement(PendingComponent, null)
|
|
1951
|
-
}, /*#__PURE__*/React__namespace.createElement(
|
|
1952
|
-
key: match.route.id,
|
|
1953
|
-
errorComponent: errorComponent,
|
|
1954
|
-
match: match
|
|
1955
|
-
}, /*#__PURE__*/React__namespace.createElement(Inner, {
|
|
1956
|
-
match: match
|
|
1957
|
-
}))) : /*#__PURE__*/React__namespace.createElement(CatchBoundary, {
|
|
1987
|
+
}, /*#__PURE__*/React__namespace.createElement(ResolvedCatchBoundary, {
|
|
1958
1988
|
key: match.route.id,
|
|
1959
1989
|
errorComponent: errorComponent,
|
|
1960
|
-
|
|
1990
|
+
onCatch: () => {
|
|
1991
|
+
warning(false, `Error in route match: ${match.id}`);
|
|
1992
|
+
}
|
|
1961
1993
|
}, /*#__PURE__*/React__namespace.createElement(Inner, {
|
|
1962
1994
|
match: match
|
|
1963
|
-
})));
|
|
1995
|
+
}))));
|
|
1996
|
+
}
|
|
1997
|
+
function SafeFragment(props) {
|
|
1998
|
+
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, props.children);
|
|
1964
1999
|
}
|
|
1965
2000
|
|
|
1966
2001
|
// This is the messiest thing ever... I'm either seriously tired (likely) or
|
|
@@ -1973,7 +2008,7 @@
|
|
|
1973
2008
|
info: undefined
|
|
1974
2009
|
};
|
|
1975
2010
|
componentDidCatch(error, info) {
|
|
1976
|
-
|
|
2011
|
+
this.props.onCatch(error, info);
|
|
1977
2012
|
console.error(error);
|
|
1978
2013
|
this.setState({
|
|
1979
2014
|
error,
|
|
@@ -1990,7 +2025,7 @@
|
|
|
1990
2025
|
function CatchBoundaryInner(props) {
|
|
1991
2026
|
const [activeErrorState, setActiveErrorState] = React__namespace.useState(props.errorState);
|
|
1992
2027
|
const router = useRouterContext();
|
|
1993
|
-
const errorComponent = props.errorComponent ??
|
|
2028
|
+
const errorComponent = props.errorComponent ?? ErrorComponent;
|
|
1994
2029
|
const prevKeyRef = React__namespace.useRef('');
|
|
1995
2030
|
React__namespace.useEffect(() => {
|
|
1996
2031
|
if (activeErrorState) {
|
|
@@ -2011,7 +2046,7 @@
|
|
|
2011
2046
|
}
|
|
2012
2047
|
return props.children;
|
|
2013
2048
|
}
|
|
2014
|
-
function
|
|
2049
|
+
function ErrorComponent({
|
|
2015
2050
|
error
|
|
2016
2051
|
}) {
|
|
2017
2052
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
@@ -2065,7 +2100,7 @@
|
|
|
2065
2100
|
// return (children ?? null) as ReactNode
|
|
2066
2101
|
// }
|
|
2067
2102
|
|
|
2068
|
-
exports.
|
|
2103
|
+
exports.ErrorComponent = ErrorComponent;
|
|
2069
2104
|
exports.Link = Link;
|
|
2070
2105
|
exports.MatchRoute = MatchRoute;
|
|
2071
2106
|
exports.Navigate = Navigate;
|
|
@@ -2089,6 +2124,7 @@
|
|
|
2089
2124
|
exports.interpolatePath = interpolatePath;
|
|
2090
2125
|
exports.invariant = invariant;
|
|
2091
2126
|
exports.isPlainObject = isPlainObject;
|
|
2127
|
+
exports.isRedirect = isRedirect;
|
|
2092
2128
|
exports.joinPaths = joinPaths;
|
|
2093
2129
|
exports.last = last;
|
|
2094
2130
|
exports.lazy = lazy;
|
|
@@ -2099,6 +2135,7 @@
|
|
|
2099
2135
|
exports.parseSearchWith = parseSearchWith;
|
|
2100
2136
|
exports.partialDeepEqual = partialDeepEqual;
|
|
2101
2137
|
exports.pick = pick;
|
|
2138
|
+
exports.redirect = redirect;
|
|
2102
2139
|
exports.replaceEqualDeep = replaceEqualDeep;
|
|
2103
2140
|
exports.resolvePath = resolvePath;
|
|
2104
2141
|
exports.rootRouteId = rootRouteId;
|