@tanstack/react-router 0.0.1-beta.269 → 0.0.1-beta.270

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.
@@ -909,6 +909,346 @@
909
909
  .replace(/"/g, '\\"'); // Escape double quotes
910
910
  }
911
911
 
912
+ const matchContext = /*#__PURE__*/React__namespace.createContext(undefined);
913
+ function Matches() {
914
+ const router = useRouter();
915
+ const matchId = useRouterState({
916
+ select: s => {
917
+ return getRenderedMatches(s)[0]?.id;
918
+ }
919
+ });
920
+ return /*#__PURE__*/React__namespace.createElement(matchContext.Provider, {
921
+ value: matchId
922
+ }, /*#__PURE__*/React__namespace.createElement(CatchBoundary, {
923
+ getResetKey: () => router.state.resolvedLocation.state?.key,
924
+ errorComponent: ErrorComponent,
925
+ onCatch: () => {
926
+ warning(false, `Error in router! Consider setting an 'errorComponent' in your RootRoute! 👍`);
927
+ }
928
+ }, matchId ? /*#__PURE__*/React__namespace.createElement(Match, {
929
+ matchId: matchId
930
+ }) : null));
931
+ }
932
+ function SafeFragment(props) {
933
+ return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, props.children);
934
+ }
935
+ function Match({
936
+ matchId
937
+ }) {
938
+ const router = useRouter();
939
+ const routeId = useRouterState({
940
+ select: s => getRenderedMatches(s).find(d => d.id === matchId)?.routeId
941
+ });
942
+ invariant(routeId, `Could not find routeId for matchId "${matchId}". Please file an issue!`);
943
+ const route = router.routesById[routeId];
944
+ const PendingComponent = route.options.pendingComponent ?? router.options.defaultPendingComponent;
945
+ const routeErrorComponent = route.options.errorComponent ?? router.options.defaultErrorComponent ?? ErrorComponent;
946
+ const ResolvedSuspenseBoundary = route.options.wrapInSuspense ?? PendingComponent ?? route.options.component?.preload ?? route.options.pendingComponent?.preload ?? route.options.errorComponent?.preload ? React__namespace.Suspense : SafeFragment;
947
+ const ResolvedCatchBoundary = routeErrorComponent ? CatchBoundary : SafeFragment;
948
+ return /*#__PURE__*/React__namespace.createElement(matchContext.Provider, {
949
+ value: matchId
950
+ }, /*#__PURE__*/React__namespace.createElement(ResolvedSuspenseBoundary, {
951
+ fallback: PendingComponent
952
+ }, /*#__PURE__*/React__namespace.createElement(ResolvedCatchBoundary, {
953
+ getResetKey: () => router.state.resolvedLocation.state?.key,
954
+ errorComponent: routeErrorComponent,
955
+ onCatch: () => {
956
+ warning(false, `Error in route match: ${matchId}`);
957
+ }
958
+ }, /*#__PURE__*/React__namespace.createElement(MatchInner, {
959
+ matchId: matchId,
960
+ pendingElement: PendingComponent
961
+ }))));
962
+ }
963
+ function MatchInner({
964
+ matchId,
965
+ pendingElement
966
+ }) {
967
+ const router = useRouter();
968
+ const routeId = useRouterState({
969
+ select: s => getRenderedMatches(s).find(d => d.id === matchId)?.routeId
970
+ });
971
+ const route = router.routesById[routeId];
972
+ const match = useRouterState({
973
+ select: s => pick(getRenderedMatches(s).find(d => d.id === matchId), ['status', 'error', 'showPending', 'loadPromise'])
974
+ });
975
+ if (match.status === 'error') {
976
+ throw match.error;
977
+ }
978
+ if (match.status === 'pending') {
979
+ if (match.showPending) {
980
+ return pendingElement || null;
981
+ }
982
+ throw match.loadPromise;
983
+ }
984
+ if (match.status === 'success') {
985
+ let Comp = route.options.component ?? router.options.defaultComponent;
986
+ if (Comp) {
987
+ return /*#__PURE__*/React__namespace.createElement(Comp, null);
988
+ }
989
+ return /*#__PURE__*/React__namespace.createElement(Outlet, null);
990
+ }
991
+ invariant(false, 'Idle routeMatch status encountered during rendering! You should never see this. File an issue!');
992
+ }
993
+ const Outlet = /*#__PURE__*/React__namespace.memo(function Outlet() {
994
+ const matchId = React__namespace.useContext(matchContext);
995
+ const childMatchId = useRouterState({
996
+ select: s => {
997
+ const matches = getRenderedMatches(s);
998
+ const index = matches.findIndex(d => d.id === matchId);
999
+ return matches[index + 1]?.id;
1000
+ }
1001
+ });
1002
+ if (!childMatchId) {
1003
+ return null;
1004
+ }
1005
+ return /*#__PURE__*/React__namespace.createElement(Match, {
1006
+ matchId: childMatchId
1007
+ });
1008
+ });
1009
+ function useMatchRoute() {
1010
+ const {
1011
+ matchRoute
1012
+ } = useRouter();
1013
+ return React__namespace.useCallback(opts => {
1014
+ const {
1015
+ pending,
1016
+ caseSensitive,
1017
+ ...rest
1018
+ } = opts;
1019
+ return matchRoute(rest, {
1020
+ pending,
1021
+ caseSensitive
1022
+ });
1023
+ }, []);
1024
+ }
1025
+ function MatchRoute(props) {
1026
+ const matchRoute = useMatchRoute();
1027
+ const params = matchRoute(props);
1028
+ if (typeof props.children === 'function') {
1029
+ return props.children(params);
1030
+ }
1031
+ return !!params ? props.children : null;
1032
+ }
1033
+ function getRenderedMatches(state) {
1034
+ return state.pendingMatches?.some(d => d.showPending) ? state.pendingMatches : state.matches;
1035
+ }
1036
+ function useMatch(opts) {
1037
+ const router = useRouter();
1038
+ const nearestMatchId = React__namespace.useContext(matchContext);
1039
+ const nearestMatchRouteId = getRenderedMatches(router.state).find(d => d.id === nearestMatchId)?.routeId;
1040
+ const matchRouteId = (() => {
1041
+ const matches = getRenderedMatches(router.state);
1042
+ const match = opts?.from ? matches.find(d => d.routeId === opts?.from) : matches.find(d => d.id === nearestMatchId);
1043
+ return match.routeId;
1044
+ })();
1045
+ if (opts?.strict ?? true) {
1046
+ invariant(nearestMatchRouteId == matchRouteId, `useMatch("${matchRouteId}") is being called in a component that is meant to render the '${nearestMatchRouteId}' route. Did you mean to 'useMatch("${matchRouteId}", { strict: false })' or 'useRoute("${matchRouteId}")' instead?`);
1047
+ }
1048
+ const matchSelection = useRouterState({
1049
+ select: state => {
1050
+ const match = getRenderedMatches(state).find(d => d.id === nearestMatchId);
1051
+ invariant(match, `Could not find ${opts?.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`);
1052
+ return opts?.select ? opts.select(match) : match;
1053
+ }
1054
+ });
1055
+ return matchSelection;
1056
+ }
1057
+ function useMatches(opts) {
1058
+ return useRouterState({
1059
+ select: state => {
1060
+ let matches = getRenderedMatches(state);
1061
+ return opts?.select ? opts.select(matches) : matches;
1062
+ }
1063
+ });
1064
+ }
1065
+ function useParentMatches(opts) {
1066
+ const contextMatchId = React__namespace.useContext(matchContext);
1067
+ return useMatches({
1068
+ select: matches => {
1069
+ matches = matches.slice(matches.findIndex(d => d.id === contextMatchId));
1070
+ return opts?.select ? opts.select(matches) : matches;
1071
+ }
1072
+ });
1073
+ }
1074
+ function useLoaderData(opts) {
1075
+ return useMatch({
1076
+ ...opts,
1077
+ select: s => {
1078
+ return typeof opts.select === 'function' ? opts.select(s?.loaderData) : s?.loaderData;
1079
+ }
1080
+ });
1081
+ }
1082
+
1083
+ const routerContext = /*#__PURE__*/React__namespace.createContext(null);
1084
+ if (typeof document !== 'undefined') {
1085
+ window.__TSR_ROUTER_CONTEXT__ = routerContext;
1086
+ }
1087
+ function RouterProvider({
1088
+ router,
1089
+ ...rest
1090
+ }) {
1091
+ // Allow the router to update options on the router instance
1092
+ router.update({
1093
+ ...router.options,
1094
+ ...rest,
1095
+ context: {
1096
+ ...router.options.context,
1097
+ ...rest?.context
1098
+ }
1099
+ });
1100
+ const inner = /*#__PURE__*/React__namespace.createElement(routerContext.Provider, {
1101
+ value: router
1102
+ }, /*#__PURE__*/React__namespace.createElement(Matches, null), /*#__PURE__*/React__namespace.createElement(Transitioner, null));
1103
+ if (router.options.Wrap) {
1104
+ return /*#__PURE__*/React__namespace.createElement(router.options.Wrap, null, inner);
1105
+ }
1106
+ return inner;
1107
+ }
1108
+ function Transitioner() {
1109
+ const router = useRouter();
1110
+ const routerState = useRouterState({
1111
+ select: s => pick(s, ['isLoading', 'location', 'resolvedLocation', 'isTransitioning'])
1112
+ });
1113
+ const [isTransitioning, startReactTransition] = React__namespace.useTransition();
1114
+ router.startReactTransition = startReactTransition;
1115
+ React__namespace.useEffect(() => {
1116
+ if (isTransitioning) {
1117
+ router.__store.setState(s => ({
1118
+ ...s,
1119
+ isTransitioning
1120
+ }));
1121
+ }
1122
+ }, [isTransitioning]);
1123
+ const tryLoad = () => {
1124
+ const apply = cb => {
1125
+ if (!routerState.isTransitioning) {
1126
+ startReactTransition(() => cb());
1127
+ } else {
1128
+ cb();
1129
+ }
1130
+ };
1131
+ apply(() => {
1132
+ try {
1133
+ router.load();
1134
+ } catch (err) {
1135
+ console.error(err);
1136
+ }
1137
+ });
1138
+ };
1139
+ useLayoutEffect$1(() => {
1140
+ const unsub = router.history.subscribe(() => {
1141
+ router.latestLocation = router.parseLocation(router.latestLocation);
1142
+ if (routerState.location !== router.latestLocation) {
1143
+ tryLoad();
1144
+ }
1145
+ });
1146
+ const nextLocation = router.buildLocation({
1147
+ search: true,
1148
+ params: true,
1149
+ hash: true,
1150
+ state: true
1151
+ });
1152
+ if (routerState.location.href !== nextLocation.href) {
1153
+ router.commitLocation({
1154
+ ...nextLocation,
1155
+ replace: true
1156
+ });
1157
+ }
1158
+ return () => {
1159
+ unsub();
1160
+ };
1161
+ }, [router.history]);
1162
+ useLayoutEffect$1(() => {
1163
+ if (routerState.isTransitioning && !isTransitioning && !routerState.isLoading && routerState.resolvedLocation !== routerState.location) {
1164
+ router.emit({
1165
+ type: 'onResolved',
1166
+ fromLocation: routerState.resolvedLocation,
1167
+ toLocation: routerState.location,
1168
+ pathChanged: routerState.location.href !== routerState.resolvedLocation?.href
1169
+ });
1170
+ if (document.querySelector) {
1171
+ const el = document.getElementById(routerState.location.hash);
1172
+ if (el) {
1173
+ el.scrollIntoView();
1174
+ }
1175
+ }
1176
+ router.pendingMatches = [];
1177
+ router.__store.setState(s => ({
1178
+ ...s,
1179
+ isTransitioning: false,
1180
+ resolvedLocation: s.location
1181
+ }));
1182
+ }
1183
+ }, [routerState.isTransitioning, isTransitioning, routerState.isLoading, routerState.resolvedLocation, routerState.location]);
1184
+ useLayoutEffect$1(() => {
1185
+ if (!window.__TSR_DEHYDRATED__) {
1186
+ tryLoad();
1187
+ }
1188
+ }, []);
1189
+ return null;
1190
+ }
1191
+ function getRouteMatch(state, id) {
1192
+ return [...(state.pendingMatches ?? []), ...state.matches].find(d => d.id === id);
1193
+ }
1194
+ function useRouterState(opts) {
1195
+ const router = useRouter();
1196
+ return useStore(router.__store, opts?.select);
1197
+ }
1198
+ function useRouter() {
1199
+ const resolvedContext = typeof document !== 'undefined' ? window.__TSR_ROUTER_CONTEXT__ || routerContext : routerContext;
1200
+ const value = React__namespace.useContext(resolvedContext);
1201
+ warning(value, 'useRouter must be used inside a <RouterProvider> component!');
1202
+ return value;
1203
+ }
1204
+
1205
+ function defer(_promise) {
1206
+ const promise = _promise;
1207
+ if (!promise.__deferredState) {
1208
+ promise.__deferredState = {
1209
+ uid: Math.random().toString(36).slice(2),
1210
+ status: 'pending'
1211
+ };
1212
+ const state = promise.__deferredState;
1213
+ promise.then(data => {
1214
+ state.status = 'success';
1215
+ state.data = data;
1216
+ }).catch(error => {
1217
+ state.status = 'error';
1218
+ state.error = error;
1219
+ });
1220
+ }
1221
+ return promise;
1222
+ }
1223
+ function isDehydratedDeferred(obj) {
1224
+ return typeof obj === 'object' && obj !== null && !(obj instanceof Promise) && !obj.then && '__deferredState' in obj;
1225
+ }
1226
+
1227
+ function useAwaited({
1228
+ promise
1229
+ }) {
1230
+ const router = useRouter();
1231
+ let state = promise.__deferredState;
1232
+ const key = `__TSR__DEFERRED__${state.uid}`;
1233
+ if (isDehydratedDeferred(promise)) {
1234
+ state = router.hydrateData(key);
1235
+ promise = Promise.resolve(state.data);
1236
+ promise.__deferredState = state;
1237
+ }
1238
+ if (state.status === 'pending') {
1239
+ throw new Promise(r => setTimeout(r, 1)).then(() => promise);
1240
+ }
1241
+ if (state.status === 'error') {
1242
+ throw state.error;
1243
+ }
1244
+ router.dehydrateData(key, state);
1245
+ return [state.data];
1246
+ }
1247
+ function Await(props) {
1248
+ const awaited = useAwaited(props);
1249
+ return props.children(...awaited);
1250
+ }
1251
+
912
1252
  function joinPaths(paths) {
913
1253
  return cleanPath(paths.filter(Boolean).join('/'));
914
1254
  }
@@ -1084,133 +1424,47 @@
1084
1424
  }
1085
1425
  if (baseSegment.value.charAt(0) !== '$') {
1086
1426
  params[routeSegment.value.substring(1)] = baseSegment.value;
1087
- }
1088
- }
1089
- }
1090
- if (!isLastBaseSegment && isLastRouteSegment) {
1091
- params['**'] = joinPaths(baseSegments.slice(i + 1).map(d => d.value));
1092
- return !!matchLocation.fuzzy && routeSegment?.value !== '/';
1093
- }
1094
- }
1095
- return true;
1096
- })();
1097
- return isMatch ? params : undefined;
1098
- }
1099
-
1100
- function useParams(opts) {
1101
- return useRouterState({
1102
- select: state => {
1103
- const params = last(state.matches)?.params;
1104
- return opts?.select ? opts.select(params) : params;
1105
- }
1106
- });
1107
- }
1108
-
1109
- function useSearch(opts) {
1110
- return useMatch({
1111
- ...opts,
1112
- select: match => {
1113
- return opts?.select ? opts.select(match.search) : match.search;
1114
- }
1115
- });
1116
- }
1117
-
1118
- const rootRouteId = '__root__';
1119
-
1120
- // The parse type here allows a zod schema to be passed directly to the validator
1121
-
1122
- class RouteApi {
1123
- constructor({
1124
- id
1125
- }) {
1126
- this.id = id;
1127
- }
1128
- useMatch = opts => {
1129
- return useMatch({
1130
- ...opts,
1131
- from: this.id
1132
- });
1133
- };
1134
- useRouteContext = opts => {
1135
- return useMatch({
1136
- ...opts,
1137
- from: this.id,
1138
- select: d => opts?.select ? opts.select(d.context) : d.context
1139
- });
1140
- };
1141
- useSearch = opts => {
1142
- return useSearch({
1143
- ...opts,
1144
- from: this.id
1145
- });
1146
- };
1147
- useParams = opts => {
1148
- return useParams({
1149
- ...opts,
1150
- from: this.id
1151
- });
1152
- };
1153
- useLoaderData = opts => {
1154
- return useLoaderData({
1155
- ...opts,
1156
- from: this.id
1157
- });
1158
- };
1427
+ }
1428
+ }
1429
+ }
1430
+ if (!isLastBaseSegment && isLastRouteSegment) {
1431
+ params['**'] = joinPaths(baseSegments.slice(i + 1).map(d => d.value));
1432
+ return !!matchLocation.fuzzy && routeSegment?.value !== '/';
1433
+ }
1434
+ }
1435
+ return true;
1436
+ })();
1437
+ return isMatch ? params : undefined;
1159
1438
  }
1160
- class Route {
1161
- // Set up in this.init()
1162
-
1163
- // customId!: TCustomId
1164
-
1165
- // Optional
1166
1439
 
1167
- constructor(options) {
1168
- this.options = options || {};
1169
- this.isRoot = !options?.getParentRoute;
1170
- invariant(!(options?.id && options?.path), `Route cannot have both an 'id' and a 'path' option.`);
1171
- this.$$typeof = Symbol.for('react.memo');
1172
- }
1173
- init = opts => {
1174
- this.originalIndex = opts.originalIndex;
1175
- const options = this.options;
1176
- const isRoot = !options?.path && !options?.id;
1177
- this.parentRoute = this.options?.getParentRoute?.();
1178
- if (isRoot) {
1179
- this.path = rootRouteId;
1180
- } else {
1181
- invariant(this.parentRoute, `Child Route instances must pass a 'getParentRoute: () => ParentRoute' option that returns a Route instance.`);
1440
+ function useParams(opts) {
1441
+ return useRouterState({
1442
+ select: state => {
1443
+ const params = last(state.matches)?.params;
1444
+ return opts?.select ? opts.select(params) : params;
1182
1445
  }
1183
- let path = isRoot ? rootRouteId : options.path;
1446
+ });
1447
+ }
1184
1448
 
1185
- // If the path is anything other than an index path, trim it up
1186
- if (path && path !== '/') {
1187
- path = trimPath(path);
1449
+ function useSearch(opts) {
1450
+ return useMatch({
1451
+ ...opts,
1452
+ select: match => {
1453
+ return opts?.select ? opts.select(match.search) : match.search;
1188
1454
  }
1189
- const customId = options?.id || path;
1455
+ });
1456
+ }
1190
1457
 
1191
- // Strip the parentId prefix from the first level of children
1192
- let id = isRoot ? rootRouteId : joinPaths([this.parentRoute.id === rootRouteId ? '' : this.parentRoute.id, customId]);
1193
- if (path === rootRouteId) {
1194
- path = '/';
1195
- }
1196
- if (id !== rootRouteId) {
1197
- id = joinPaths(['/', id]);
1198
- }
1199
- const fullPath = id === rootRouteId ? '/' : joinPaths([this.parentRoute.fullPath, path]);
1200
- this.path = path;
1458
+ const rootRouteId = '__root__';
1459
+
1460
+ // The parse type here allows a zod schema to be passed directly to the validator
1461
+
1462
+ class RouteApi {
1463
+ constructor({
1464
+ id
1465
+ }) {
1201
1466
  this.id = id;
1202
- // this.customId = customId as TCustomId
1203
- this.fullPath = fullPath;
1204
- this.to = fullPath;
1205
- };
1206
- addChildren = children => {
1207
- this.children = children;
1208
- return this;
1209
- };
1210
- update = options => {
1211
- Object.assign(this.options, options);
1212
- return this;
1213
- };
1467
+ }
1214
1468
  useMatch = opts => {
1215
1469
  return useMatch({
1216
1470
  ...opts,
@@ -1243,393 +1497,115 @@
1243
1497
  });
1244
1498
  };
1245
1499
  }
1246
- function rootRouteWithContext() {
1247
- return options => {
1248
- return new RootRoute(options);
1249
- };
1250
- }
1251
- class RootRoute extends Route {
1252
- constructor(options) {
1253
- super(options);
1254
- }
1255
- }
1256
- function createRouteMask(opts) {
1257
- return opts;
1258
- }
1259
-
1260
- //
1261
-
1262
- class NotFoundRoute extends Route {
1263
- constructor(options) {
1264
- super({
1265
- ...options,
1266
- id: '404'
1267
- });
1268
- }
1269
- }
1270
-
1271
- const matchContext = /*#__PURE__*/React__namespace.createContext(undefined);
1272
- function Matches() {
1273
- const router = useRouter();
1274
- const matchId = useRouterState({
1275
- select: s => {
1276
- return getRenderedMatches(s)[0]?.id;
1277
- }
1278
- });
1279
- const route = router.routesById[rootRouteId];
1280
- const errorComponent = React__namespace.useCallback(props => {
1281
- return /*#__PURE__*/React__namespace.createElement(ErrorComponent, {
1282
- ...props,
1283
- useMatch: route.useMatch,
1284
- useRouteContext: route.useRouteContext,
1285
- useSearch: route.useSearch,
1286
- useParams: route.useParams
1287
- });
1288
- }, [route]);
1289
- return /*#__PURE__*/React__namespace.createElement(matchContext.Provider, {
1290
- value: matchId
1291
- }, /*#__PURE__*/React__namespace.createElement(CatchBoundary, {
1292
- getResetKey: () => router.state.resolvedLocation.state?.key,
1293
- errorComponent: errorComponent,
1294
- onCatch: () => {
1295
- warning(false, `Error in router! Consider setting an 'errorComponent' in your RootRoute! 👍`);
1296
- }
1297
- }, matchId ? /*#__PURE__*/React__namespace.createElement(Match, {
1298
- matchId: matchId
1299
- }) : null));
1300
- }
1301
- function SafeFragment(props) {
1302
- return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, props.children);
1303
- }
1304
- function Match({
1305
- matchId
1306
- }) {
1307
- const router = useRouter();
1308
- const routeId = useRouterState({
1309
- select: s => getRenderedMatches(s).find(d => d.id === matchId)?.routeId
1310
- });
1311
- invariant(routeId, `Could not find routeId for matchId "${matchId}". Please file an issue!`);
1312
- const route = router.routesById[routeId];
1313
- const PendingComponent = route.options.pendingComponent ?? router.options.defaultPendingComponent;
1314
- const pendingElement = PendingComponent ? /*#__PURE__*/React__namespace.createElement(PendingComponent, {
1315
- useMatch: route.useMatch,
1316
- useRouteContext: route.useRouteContext,
1317
- useSearch: route.useSearch,
1318
- useParams: route.useParams
1319
- }) : undefined;
1320
- const routeErrorComponent = route.options.errorComponent ?? router.options.defaultErrorComponent ?? ErrorComponent;
1321
- const ResolvedSuspenseBoundary = route.options.wrapInSuspense ?? pendingElement ? React__namespace.Suspense : SafeFragment;
1322
- const errorComponent = routeErrorComponent ? React__namespace.useCallback(props => {
1323
- return /*#__PURE__*/React__namespace.createElement(routeErrorComponent, {
1324
- ...props,
1325
- useMatch: route.useMatch,
1326
- useRouteContext: route.useRouteContext,
1327
- useSearch: route.useSearch,
1328
- useParams: route.useParams
1329
- });
1330
- }, [route]) : undefined;
1331
- const ResolvedCatchBoundary = errorComponent ? CatchBoundary : SafeFragment;
1332
- return /*#__PURE__*/React__namespace.createElement(matchContext.Provider, {
1333
- value: matchId
1334
- }, /*#__PURE__*/React__namespace.createElement(ResolvedSuspenseBoundary, {
1335
- fallback: pendingElement
1336
- }, /*#__PURE__*/React__namespace.createElement(ResolvedCatchBoundary, {
1337
- getResetKey: () => router.state.resolvedLocation.state?.key,
1338
- errorComponent: errorComponent,
1339
- onCatch: () => {
1340
- warning(false, `Error in route match: ${matchId}`);
1341
- }
1342
- }, /*#__PURE__*/React__namespace.createElement(MatchInner, {
1343
- matchId: matchId,
1344
- pendingElement: pendingElement
1345
- }))));
1346
- }
1347
- function MatchInner({
1348
- matchId,
1349
- pendingElement
1350
- }) {
1351
- const router = useRouter();
1352
- const routeId = useRouterState({
1353
- select: s => getRenderedMatches(s).find(d => d.id === matchId)?.routeId
1354
- });
1355
- const route = router.routesById[routeId];
1356
- const match = useRouterState({
1357
- select: s => pick(getRenderedMatches(s).find(d => d.id === matchId), ['status', 'error', 'showPending', 'loadPromise'])
1358
- });
1359
- if (match.status === 'error') {
1360
- throw match.error;
1361
- }
1362
- if (match.status === 'pending') {
1363
- if (match.showPending) {
1364
- return pendingElement || null;
1365
- }
1366
- throw match.loadPromise;
1367
- }
1368
- if (match.status === 'success') {
1369
- let comp = route.options.component ?? router.options.defaultComponent;
1370
- if (comp) {
1371
- return /*#__PURE__*/React__namespace.createElement(comp, {
1372
- useMatch: route.useMatch,
1373
- useRouteContext: route.useRouteContext,
1374
- useSearch: route.useSearch,
1375
- useParams: route.useParams,
1376
- useLoaderData: route.useLoaderData
1377
- });
1378
- }
1379
- return /*#__PURE__*/React__namespace.createElement(Outlet, null);
1380
- }
1381
- invariant(false, 'Idle routeMatch status encountered during rendering! You should never see this. File an issue!');
1382
- }
1383
- const Outlet = /*#__PURE__*/React__namespace.memo(function Outlet() {
1384
- const matchId = React__namespace.useContext(matchContext);
1385
- const childMatchId = useRouterState({
1386
- select: s => {
1387
- const matches = getRenderedMatches(s);
1388
- const index = matches.findIndex(d => d.id === matchId);
1389
- return matches[index + 1]?.id;
1390
- }
1391
- });
1392
- if (!childMatchId) {
1393
- return null;
1394
- }
1395
- return /*#__PURE__*/React__namespace.createElement(Match, {
1396
- matchId: childMatchId
1397
- });
1398
- });
1399
- function useMatchRoute() {
1400
- const {
1401
- matchRoute
1402
- } = useRouter();
1403
- return React__namespace.useCallback(opts => {
1404
- const {
1405
- pending,
1406
- caseSensitive,
1407
- ...rest
1408
- } = opts;
1409
- return matchRoute(rest, {
1410
- pending,
1411
- caseSensitive
1412
- });
1413
- }, []);
1414
- }
1415
- function MatchRoute(props) {
1416
- const matchRoute = useMatchRoute();
1417
- const params = matchRoute(props);
1418
- if (typeof props.children === 'function') {
1419
- return props.children(params);
1420
- }
1421
- return !!params ? props.children : null;
1422
- }
1423
- function getRenderedMatches(state) {
1424
- return state.pendingMatches?.some(d => d.showPending) ? state.pendingMatches : state.matches;
1425
- }
1426
- function useMatch(opts) {
1427
- const router = useRouter();
1428
- const nearestMatchId = React__namespace.useContext(matchContext);
1429
- const nearestMatchRouteId = getRenderedMatches(router.state).find(d => d.id === nearestMatchId)?.routeId;
1430
- const matchRouteId = (() => {
1431
- const matches = getRenderedMatches(router.state);
1432
- const match = opts?.from ? matches.find(d => d.routeId === opts?.from) : matches.find(d => d.id === nearestMatchId);
1433
- return match.routeId;
1434
- })();
1435
- if (opts?.strict ?? true) {
1436
- invariant(nearestMatchRouteId == matchRouteId, `useMatch("${matchRouteId}") is being called in a component that is meant to render the '${nearestMatchRouteId}' route. Did you mean to 'useMatch("${matchRouteId}", { strict: false })' or 'useRoute("${matchRouteId}")' instead?`);
1437
- }
1438
- const matchSelection = useRouterState({
1439
- select: state => {
1440
- const match = getRenderedMatches(state).find(d => d.id === nearestMatchId);
1441
- invariant(match, `Could not find ${opts?.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`);
1442
- return opts?.select ? opts.select(match) : match;
1443
- }
1444
- });
1445
- return matchSelection;
1446
- }
1447
- function useMatches(opts) {
1448
- const contextMatchId = React__namespace.useContext(matchContext);
1449
- return useRouterState({
1450
- select: state => {
1451
- let matches = getRenderedMatches(state);
1452
- matches = matches.slice(matches.findIndex(d => d.id === contextMatchId));
1453
- return opts?.select ? opts.select(matches) : matches;
1454
- }
1455
- });
1456
- }
1457
- function useLoaderData(opts) {
1458
- return useMatch({
1459
- ...opts,
1460
- select: s => {
1461
- return typeof opts.select === 'function' ? opts.select(s?.loaderData) : s?.loaderData;
1500
+ class Route {
1501
+ // Set up in this.init()
1502
+
1503
+ // customId!: TCustomId
1504
+
1505
+ // Optional
1506
+
1507
+ constructor(options) {
1508
+ this.options = options || {};
1509
+ this.isRoot = !options?.getParentRoute;
1510
+ invariant(!(options?.id && options?.path), `Route cannot have both an 'id' and a 'path' option.`);
1511
+ this.$$typeof = Symbol.for('react.memo');
1512
+ }
1513
+ init = opts => {
1514
+ this.originalIndex = opts.originalIndex;
1515
+ const options = this.options;
1516
+ const isRoot = !options?.path && !options?.id;
1517
+ this.parentRoute = this.options?.getParentRoute?.();
1518
+ if (isRoot) {
1519
+ this.path = rootRouteId;
1520
+ } else {
1521
+ invariant(this.parentRoute, `Child Route instances must pass a 'getParentRoute: () => ParentRoute' option that returns a Route instance.`);
1462
1522
  }
1463
- });
1464
- }
1523
+ let path = isRoot ? rootRouteId : options.path;
1465
1524
 
1466
- const routerContext = /*#__PURE__*/React__namespace.createContext(null);
1467
- if (typeof document !== 'undefined') {
1468
- window.__TSR_ROUTER_CONTEXT__ = routerContext;
1469
- }
1470
- function RouterProvider({
1471
- router,
1472
- ...rest
1473
- }) {
1474
- // Allow the router to update options on the router instance
1475
- router.update({
1476
- ...router.options,
1477
- ...rest,
1478
- context: {
1479
- ...router.options.context,
1480
- ...rest?.context
1525
+ // If the path is anything other than an index path, trim it up
1526
+ if (path && path !== '/') {
1527
+ path = trimPath(path);
1481
1528
  }
1482
- });
1483
- const inner = /*#__PURE__*/React__namespace.createElement(routerContext.Provider, {
1484
- value: router
1485
- }, /*#__PURE__*/React__namespace.createElement(Matches, null), /*#__PURE__*/React__namespace.createElement(Transitioner, null));
1486
- if (router.options.Wrap) {
1487
- return /*#__PURE__*/React__namespace.createElement(router.options.Wrap, null, inner);
1488
- }
1489
- return inner;
1490
- }
1491
- function Transitioner() {
1492
- const router = useRouter();
1493
- const routerState = useRouterState({
1494
- select: s => pick(s, ['isLoading', 'location', 'resolvedLocation', 'isTransitioning'])
1495
- });
1496
- const [isTransitioning, startReactTransition] = React__namespace.useTransition();
1497
- router.startReactTransition = startReactTransition;
1498
- React__namespace.useEffect(() => {
1499
- if (isTransitioning) {
1500
- router.__store.setState(s => ({
1501
- ...s,
1502
- isTransitioning
1503
- }));
1529
+ const customId = options?.id || path;
1530
+
1531
+ // Strip the parentId prefix from the first level of children
1532
+ let id = isRoot ? rootRouteId : joinPaths([this.parentRoute.id === rootRouteId ? '' : this.parentRoute.id, customId]);
1533
+ if (path === rootRouteId) {
1534
+ path = '/';
1504
1535
  }
1505
- }, [isTransitioning]);
1506
- const tryLoad = () => {
1507
- const apply = cb => {
1508
- if (!routerState.isTransitioning) {
1509
- startReactTransition(() => cb());
1510
- } else {
1511
- cb();
1512
- }
1513
- };
1514
- apply(() => {
1515
- try {
1516
- router.load();
1517
- } catch (err) {
1518
- console.error(err);
1519
- }
1536
+ if (id !== rootRouteId) {
1537
+ id = joinPaths(['/', id]);
1538
+ }
1539
+ const fullPath = id === rootRouteId ? '/' : joinPaths([this.parentRoute.fullPath, path]);
1540
+ this.path = path;
1541
+ this.id = id;
1542
+ // this.customId = customId as TCustomId
1543
+ this.fullPath = fullPath;
1544
+ this.to = fullPath;
1545
+ };
1546
+ addChildren = children => {
1547
+ this.children = children;
1548
+ return this;
1549
+ };
1550
+ update = options => {
1551
+ Object.assign(this.options, options);
1552
+ return this;
1553
+ };
1554
+ useMatch = opts => {
1555
+ return useMatch({
1556
+ ...opts,
1557
+ from: this.id
1520
1558
  });
1521
1559
  };
1522
- useLayoutEffect$1(() => {
1523
- const unsub = router.history.subscribe(() => {
1524
- router.latestLocation = router.parseLocation(router.latestLocation);
1525
- if (routerState.location !== router.latestLocation) {
1526
- tryLoad();
1527
- }
1560
+ useRouteContext = opts => {
1561
+ return useMatch({
1562
+ ...opts,
1563
+ from: this.id,
1564
+ select: d => opts?.select ? opts.select(d.context) : d.context
1528
1565
  });
1529
- const nextLocation = router.buildLocation({
1530
- search: true,
1531
- params: true,
1532
- hash: true,
1533
- state: true
1566
+ };
1567
+ useSearch = opts => {
1568
+ return useSearch({
1569
+ ...opts,
1570
+ from: this.id
1534
1571
  });
1535
- if (routerState.location.href !== nextLocation.href) {
1536
- router.commitLocation({
1537
- ...nextLocation,
1538
- replace: true
1539
- });
1540
- }
1541
- return () => {
1542
- unsub();
1543
- };
1544
- }, [router.history]);
1545
- useLayoutEffect$1(() => {
1546
- if (routerState.isTransitioning && !isTransitioning && !routerState.isLoading && routerState.resolvedLocation !== routerState.location) {
1547
- router.emit({
1548
- type: 'onResolved',
1549
- fromLocation: routerState.resolvedLocation,
1550
- toLocation: routerState.location,
1551
- pathChanged: routerState.location.href !== routerState.resolvedLocation?.href
1552
- });
1553
- if (document.querySelector) {
1554
- const el = document.getElementById(routerState.location.hash);
1555
- if (el) {
1556
- el.scrollIntoView();
1557
- }
1558
- }
1559
- router.pendingMatches = [];
1560
- router.__store.setState(s => ({
1561
- ...s,
1562
- isTransitioning: false,
1563
- resolvedLocation: s.location
1564
- }));
1565
- }
1566
- }, [routerState.isTransitioning, isTransitioning, routerState.isLoading, routerState.resolvedLocation, routerState.location]);
1567
- useLayoutEffect$1(() => {
1568
- if (!window.__TSR_DEHYDRATED__) {
1569
- tryLoad();
1570
- }
1571
- }, []);
1572
- return null;
1573
- }
1574
- function getRouteMatch(state, id) {
1575
- return [...(state.pendingMatches ?? []), ...state.matches].find(d => d.id === id);
1576
- }
1577
- function useRouterState(opts) {
1578
- const router = useRouter();
1579
- return useStore(router.__store, opts?.select);
1572
+ };
1573
+ useParams = opts => {
1574
+ return useParams({
1575
+ ...opts,
1576
+ from: this.id
1577
+ });
1578
+ };
1579
+ useLoaderData = opts => {
1580
+ return useLoaderData({
1581
+ ...opts,
1582
+ from: this.id
1583
+ });
1584
+ };
1580
1585
  }
1581
- function useRouter() {
1582
- const resolvedContext = typeof document !== 'undefined' ? window.__TSR_ROUTER_CONTEXT__ || routerContext : routerContext;
1583
- const value = React__namespace.useContext(resolvedContext);
1584
- warning(value, 'useRouter must be used inside a <RouterProvider> component!');
1585
- return value;
1586
+ function rootRouteWithContext() {
1587
+ return options => {
1588
+ return new RootRoute(options);
1589
+ };
1586
1590
  }
1587
-
1588
- function defer(_promise) {
1589
- const promise = _promise;
1590
- if (!promise.__deferredState) {
1591
- promise.__deferredState = {
1592
- uid: Math.random().toString(36).slice(2),
1593
- status: 'pending'
1594
- };
1595
- const state = promise.__deferredState;
1596
- promise.then(data => {
1597
- state.status = 'success';
1598
- state.data = data;
1599
- }).catch(error => {
1600
- state.status = 'error';
1601
- state.error = error;
1602
- });
1591
+ class RootRoute extends Route {
1592
+ constructor(options) {
1593
+ super(options);
1603
1594
  }
1604
- return promise;
1605
1595
  }
1606
- function isDehydratedDeferred(obj) {
1607
- return typeof obj === 'object' && obj !== null && !(obj instanceof Promise) && !obj.then && '__deferredState' in obj;
1596
+ function createRouteMask(opts) {
1597
+ return opts;
1608
1598
  }
1609
1599
 
1610
- function useAwaited({
1611
- promise
1612
- }) {
1613
- const router = useRouter();
1614
- let state = promise.__deferredState;
1615
- const key = `__TSR__DEFERRED__${state.uid}`;
1616
- if (isDehydratedDeferred(promise)) {
1617
- state = router.hydrateData(key);
1618
- promise = Promise.resolve(state.data);
1619
- promise.__deferredState = state;
1620
- }
1621
- if (state.status === 'pending') {
1622
- throw new Promise(r => setTimeout(r, 1)).then(() => promise);
1623
- }
1624
- if (state.status === 'error') {
1625
- throw state.error;
1600
+ //
1601
+
1602
+ class NotFoundRoute extends Route {
1603
+ constructor(options) {
1604
+ super({
1605
+ ...options,
1606
+ id: '404'
1607
+ });
1626
1608
  }
1627
- router.dehydrateData(key, state);
1628
- return [state.data];
1629
- }
1630
- function Await(props) {
1631
- const awaited = useAwaited(props);
1632
- return props.children(...awaited);
1633
1609
  }
1634
1610
 
1635
1611
  class FileRoute {
@@ -2310,7 +2286,6 @@
2310
2286
  status: hasLoaders ? 'pending' : 'success',
2311
2287
  showPending: false,
2312
2288
  isFetching: false,
2313
- invalid: false,
2314
2289
  error: undefined,
2315
2290
  paramsError: parseErrors[index],
2316
2291
  loadPromise: Promise.resolve(),
@@ -2629,7 +2604,6 @@
2629
2604
  matches[index] = match = {
2630
2605
  ...match,
2631
2606
  fetchedAt: Date.now(),
2632
- invalid: false,
2633
2607
  showPending: false
2634
2608
  };
2635
2609
  const pendingMs = route.options.pendingMs ?? this.options.defaultPendingMs;
@@ -2832,7 +2806,7 @@
2832
2806
 
2833
2807
  //
2834
2808
  ;
2835
- [[exitingMatchIds, 'onLeave'], [enteringMatchIds, 'onEnter'], [stayingMatchIds, 'onTransition']].forEach(([matches, hook]) => {
2809
+ [[exitingMatchIds, 'onLeave'], [enteringMatchIds, 'onEnter'], [stayingMatchIds, 'onStay']].forEach(([matches, hook]) => {
2836
2810
  matches.forEach(match => {
2837
2811
  this.looseRoutesById[match.routeId].options[hook]?.(match);
2838
2812
  });
@@ -2922,7 +2896,7 @@
2922
2896
  dehydrate = () => {
2923
2897
  return {
2924
2898
  state: {
2925
- dehydratedMatches: this.state.matches.map(d => pick(d, ['fetchedAt', 'invalid', 'id', 'status', 'updatedAt', 'loaderData']))
2899
+ dehydratedMatches: this.state.matches.map(d => pick(d, ['fetchedAt', 'id', 'status', 'updatedAt', 'loaderData']))
2926
2900
  }
2927
2901
  };
2928
2902
  };
@@ -3186,9 +3160,21 @@
3186
3160
  });
3187
3161
  }, []);
3188
3162
  }
3189
- function typedNavigate(navigate) {
3190
- return navigate;
3191
- } //
3163
+
3164
+ // NOTE: I don't know of anyone using this. It's undocumented, so let's wait until someone needs it
3165
+ // export function typedNavigate<
3166
+ // TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
3167
+ // TDefaultFrom extends RoutePaths<TRouteTree> = '/',
3168
+ // >(navigate: (opts: NavigateOptions<any>) => Promise<void>) {
3169
+ // return navigate as <
3170
+ // TFrom extends RoutePaths<TRouteTree> = TDefaultFrom,
3171
+ // TTo extends string = '',
3172
+ // TMaskFrom extends RoutePaths<TRouteTree> = '/',
3173
+ // TMaskTo extends string = '',
3174
+ // >(
3175
+ // opts?: NavigateOptions<TRouteTree, TFrom, TTo, TMaskFrom, TMaskTo>,
3176
+ // ) => Promise<void>
3177
+ // } //
3192
3178
 
3193
3179
  function Navigate(props) {
3194
3180
  const {
@@ -3272,7 +3258,6 @@
3272
3258
  exports.trimPath = trimPath;
3273
3259
  exports.trimPathLeft = trimPathLeft;
3274
3260
  exports.trimPathRight = trimPathRight;
3275
- exports.typedNavigate = typedNavigate;
3276
3261
  exports.useAwaited = useAwaited;
3277
3262
  exports.useBlocker = useBlocker;
3278
3263
  exports.useElementScrollRestoration = useElementScrollRestoration;
@@ -3284,6 +3269,7 @@
3284
3269
  exports.useMatches = useMatches;
3285
3270
  exports.useNavigate = useNavigate;
3286
3271
  exports.useParams = useParams;
3272
+ exports.useParentMatches = useParentMatches;
3287
3273
  exports.useRouteContext = useRouteContext;
3288
3274
  exports.useRouter = useRouter;
3289
3275
  exports.useRouterState = useRouterState;