@tanstack/react-router 0.0.1-beta.222 → 0.0.1-beta.224

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.
@@ -1106,274 +1106,34 @@
1106
1106
  return typeof opts.select === 'function' ? opts.select(match?.loaderData) : match?.loaderData;
1107
1107
  }
1108
1108
 
1109
- // Detect if we're in the DOM
1110
-
1111
- function redirect(opts) {
1112
- opts.isRedirect = true;
1113
- return opts;
1114
- }
1115
- function isRedirect(obj) {
1116
- return !!obj?.isRedirect;
1117
- }
1118
-
1119
- // @ts-nocheck
1120
-
1121
- // qss has been slightly modified and inlined here for our use cases (and compression's sake). We've included it as a hard dependency for MIT license attribution.
1122
-
1123
- function encode(obj, pfx) {
1124
- var k,
1125
- i,
1126
- tmp,
1127
- str = '';
1128
- for (k in obj) {
1129
- if ((tmp = obj[k]) !== void 0) {
1130
- if (Array.isArray(tmp)) {
1131
- for (i = 0; i < tmp.length; i++) {
1132
- str && (str += '&');
1133
- str += encodeURIComponent(k) + '=' + encodeURIComponent(tmp[i]);
1134
- }
1135
- } else {
1136
- str && (str += '&');
1137
- str += encodeURIComponent(k) + '=' + encodeURIComponent(tmp);
1138
- }
1139
- }
1140
- }
1141
- return (pfx || '') + str;
1142
- }
1143
- function toValue(mix) {
1144
- if (!mix) return '';
1145
- var str = decodeURIComponent(mix);
1146
- if (str === 'false') return false;
1147
- if (str === 'true') return true;
1148
- return +str * 0 === 0 && +str + '' === str ? +str : str;
1149
- }
1150
- function decode(str) {
1151
- var tmp,
1152
- k,
1153
- out = {},
1154
- arr = str.split('&');
1155
- while (tmp = arr.shift()) {
1156
- tmp = tmp.split('=');
1157
- k = tmp.shift();
1158
- if (out[k] !== void 0) {
1159
- out[k] = [].concat(out[k], toValue(tmp.shift()));
1160
- } else {
1161
- out[k] = toValue(tmp.shift());
1162
- }
1163
- }
1164
- return out;
1165
- }
1166
-
1167
- const defaultParseSearch = parseSearchWith(JSON.parse);
1168
- const defaultStringifySearch = stringifySearchWith(JSON.stringify, JSON.parse);
1169
- function parseSearchWith(parser) {
1170
- return searchStr => {
1171
- if (searchStr.substring(0, 1) === '?') {
1172
- searchStr = searchStr.substring(1);
1173
- }
1174
- let query = decode(searchStr);
1175
-
1176
- // Try to parse any query params that might be json
1177
- for (let key in query) {
1178
- const value = query[key];
1179
- if (typeof value === 'string') {
1180
- try {
1181
- query[key] = parser(value);
1182
- } catch (err) {
1183
- //
1184
- }
1185
- }
1186
- }
1187
- return query;
1188
- };
1189
- }
1190
- function stringifySearchWith(stringify, parser) {
1191
- function stringifyValue(val) {
1192
- if (typeof val === 'object' && val !== null) {
1193
- try {
1194
- return stringify(val);
1195
- } catch (err) {
1196
- // silent
1197
- }
1198
- } else if (typeof val === 'string' && typeof parser === 'function') {
1199
- try {
1200
- // Check if it's a valid parseable string.
1201
- // If it is, then stringify it again.
1202
- parser(val);
1203
- return stringify(val);
1204
- } catch (err) {
1205
- // silent
1206
- }
1207
- }
1208
- return val;
1209
- }
1210
- return search => {
1211
- search = {
1212
- ...search
1213
- };
1214
- if (search) {
1215
- Object.keys(search).forEach(key => {
1216
- const val = search[key];
1217
- if (typeof val === 'undefined' || val === undefined) {
1218
- delete search[key];
1219
- } else {
1220
- search[key] = stringifyValue(val);
1221
- }
1222
- });
1223
- }
1224
- const searchStr = encode(search).toString();
1225
- return searchStr ? `?${searchStr}` : '';
1226
- };
1227
- }
1228
-
1229
- //
1230
-
1231
- //
1232
-
1233
- const componentTypes = ['component', 'errorComponent', 'pendingComponent'];
1234
- class Router {
1235
- // dehydratedData?: TDehydrated
1236
- // resetNextScroll = false
1237
- // tempLocationKey = `${Math.round(Math.random() * 10000000)}`
1238
- constructor(options) {
1239
- this.options = {
1240
- defaultPreloadDelay: 50,
1241
- context: undefined,
1242
- ...options,
1243
- stringifySearch: options?.stringifySearch ?? defaultStringifySearch,
1244
- parseSearch: options?.parseSearch ?? defaultParseSearch
1245
- };
1246
- this.routeTree = this.options.routeTree;
1247
- }
1248
- subscribers = new Set();
1249
- subscribe = (eventType, fn) => {
1250
- const listener = {
1251
- eventType,
1252
- fn
1253
- };
1254
- this.subscribers.add(listener);
1255
- return () => {
1256
- this.subscribers.delete(listener);
1257
- };
1258
- };
1259
- emit = routerEvent => {
1260
- this.subscribers.forEach(listener => {
1261
- if (listener.eventType === routerEvent.type) {
1262
- listener.fn(routerEvent);
1263
- }
1264
- });
1265
- };
1266
-
1267
- // dehydrate = (): DehydratedRouter => {
1268
- // return {
1269
- // state: {
1270
- // dehydratedMatches: state.matches.map((d) =>
1271
- // pick(d, ['fetchedAt', 'invalid', 'id', 'status', 'updatedAt']),
1272
- // ),
1273
- // },
1274
- // }
1275
- // }
1276
-
1277
- // hydrate = async (__do_not_use_server_ctx?: HydrationCtx) => {
1278
- // let _ctx = __do_not_use_server_ctx
1279
- // // Client hydrates from window
1280
- // if (typeof document !== 'undefined') {
1281
- // _ctx = window.__TSR_DEHYDRATED__
1282
- // }
1283
-
1284
- // invariant(
1285
- // _ctx,
1286
- // 'Expected to find a __TSR_DEHYDRATED__ property on window... but we did not. Did you forget to render <DehydrateRouter /> in your app?',
1287
- // )
1288
-
1289
- // const ctx = _ctx
1290
- // this.dehydratedData = ctx.payload as any
1291
- // this.options.hydrate?.(ctx.payload as any)
1292
- // const dehydratedState = ctx.router.state
1293
-
1294
- // let matches = this.matchRoutes(
1295
- // state.location.pathname,
1296
- // state.location.search,
1297
- // ).map((match) => {
1298
- // const dehydratedMatch = dehydratedState.dehydratedMatches.find(
1299
- // (d) => d.id === match.id,
1300
- // )
1301
-
1302
- // invariant(
1303
- // dehydratedMatch,
1304
- // `Could not find a client-side match for dehydrated match with id: ${match.id}!`,
1305
- // )
1306
-
1307
- // if (dehydratedMatch) {
1308
- // return {
1309
- // ...match,
1310
- // ...dehydratedMatch,
1311
- // }
1312
- // }
1313
- // return match
1314
- // })
1315
-
1316
- // this.setState((s) => {
1317
- // return {
1318
- // ...s,
1319
- // matches: dehydratedState.dehydratedMatches as any,
1320
- // }
1321
- // })
1322
- // }
1323
-
1324
- // resolveMatchPromise = (matchId: string, key: string, value: any) => {
1325
- // state.matches
1326
- // .find((d) => d.id === matchId)
1327
- // ?.__promisesByKey[key]?.resolve(value)
1328
- // }
1329
-
1330
- // setRouteMatch = (
1331
- // id: string,
1332
- // pending: boolean,
1333
- // updater: NonNullableUpdater<RouteMatch<TRouteTree>>,
1334
- // ) => {
1335
- // const key = pending ? 'pendingMatches' : 'matches'
1336
-
1337
- // this.setState((prev) => {
1338
- // return {
1339
- // ...prev,
1340
- // [key]: prev[key].map((d) => {
1341
- // if (d.id === id) {
1342
- // return functionalUpdate(updater, d)
1343
- // }
1344
-
1345
- // return d
1346
- // }),
1347
- // }
1348
- // })
1349
- // }
1350
-
1351
- // setPendingRouteMatch = (
1352
- // id: string,
1353
- // updater: NonNullableUpdater<RouteMatch<TRouteTree>>,
1354
- // ) => {
1355
- // this.setRouteMatch(id, true, updater)
1356
- // }
1357
- }
1358
-
1359
- // A function that takes an import() argument which is a function and returns a new function that will
1360
- // proxy arguments from the caller to the imported function, retaining all type
1361
- // information along the way
1362
- function lazyFn(fn, key) {
1363
- return async (...args) => {
1364
- const imported = await fn();
1365
- return imported[key || 'default'](...args);
1366
- };
1367
- }
1368
-
1109
+ // export type RouterContext<
1110
+ // TRouteTree extends AnyRoute,
1111
+ // // TDehydrated extends Record<string, any>,
1112
+ // > = {
1113
+ // buildLink: BuildLinkFn<TRouteTree>
1114
+ // state: RouterState<TRouteTree>
1115
+ // navigate: NavigateFn<TRouteTree>
1116
+ // matchRoute: MatchRouteFn<TRouteTree>
1117
+ // routeTree: TRouteTree
1118
+ // routesById: RoutesById<TRouteTree>
1119
+ // options: RouterOptions<TRouteTree>
1120
+ // history: RouterHistory
1121
+ // load: LoadFn
1122
+ // buildLocation: BuildLocationFn<TRouteTree>
1123
+ // subscribe: Router<TRouteTree>['subscribe']
1124
+ // resetNextScrollRef: React.MutableRefObject<boolean>
1125
+ // injectedHtmlRef: React.MutableRefObject<InjectedHtmlEntry[]>
1126
+ // injectHtml: (entry: InjectedHtmlEntry) => void
1127
+ // dehydrateData: <T>(
1128
+ // key: any,
1129
+ // getData: T | (() => Promise<T> | T),
1130
+ // ) => () => void
1131
+ // hydrateData: <T>(key: any) => T | undefined
1132
+ // }
1369
1133
  const routerContext = /*#__PURE__*/React__namespace.createContext(null);
1370
1134
  if (typeof document !== 'undefined') {
1371
1135
  window.__TSR_ROUTER_CONTEXT__ = routerContext;
1372
1136
  }
1373
- const preloadWarning = 'Error preloading route! ☝️';
1374
- function isCtrlEvent(e) {
1375
- return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
1376
- }
1377
1137
  class SearchParamError extends Error {}
1378
1138
  class PathParamError extends Error {}
1379
1139
  function getInitialRouterState(location) {
@@ -1390,66 +1150,55 @@
1390
1150
  router,
1391
1151
  ...rest
1392
1152
  }) {
1393
- const options = {
1153
+ // Allow the router to update options on the router instance
1154
+ router.updateOptions({
1394
1155
  ...router.options,
1395
1156
  ...rest,
1396
1157
  context: {
1397
1158
  ...router.options.context,
1398
1159
  ...rest?.context
1399
1160
  }
1400
- };
1401
- const history = React__namespace.useState(() => options.history ?? createBrowserHistory())[0];
1402
- const tempLocationKeyRef = React__namespace.useRef(`${Math.round(Math.random() * 10000000)}`);
1403
- const resetNextScrollRef = React__namespace.useRef(true);
1404
- const navigateTimeoutRef = React__namespace.useRef(null);
1405
- const latestLoadPromiseRef = React__namespace.useRef(Promise.resolve());
1406
- const checkLatest = promise => {
1407
- return latestLoadPromiseRef.current !== promise ? latestLoadPromiseRef.current : undefined;
1408
- };
1409
- const parseLocation = useStableCallback(previousLocation => {
1410
- const parse = ({
1411
- pathname,
1412
- search,
1413
- hash,
1414
- state
1415
- }) => {
1416
- const parsedSearch = options.parseSearch(search);
1417
- return {
1418
- pathname: pathname,
1419
- searchStr: search,
1420
- search: replaceEqualDeep(previousLocation?.search, parsedSearch),
1421
- hash: hash.split('#').reverse()[0] ?? '',
1422
- href: `${pathname}${search}${hash}`,
1423
- state: replaceEqualDeep(previousLocation?.state, state)
1424
- };
1425
- };
1426
- const location = parse(history.location);
1427
- let {
1428
- __tempLocation,
1429
- __tempKey
1430
- } = location.state;
1431
- if (__tempLocation && (!__tempKey || __tempKey === tempLocationKeyRef.current)) {
1432
- // Sync up the location keys
1433
- const parsedTempLocation = parse(__tempLocation);
1434
- parsedTempLocation.state.key = location.state.key;
1435
- delete parsedTempLocation.state.__tempLocation;
1436
- return {
1437
- ...parsedTempLocation,
1438
- maskedLocation: location
1439
- };
1440
- }
1441
- return location;
1442
1161
  });
1443
- const latestLocationRef = React__namespace.useRef(parseLocation());
1444
- const [preState, setState] = React__namespace.useState(() => getInitialRouterState(latestLocationRef.current));
1162
+ const [preState, setState] = React__namespace.useState(() => router.state);
1445
1163
  const [isTransitioning, startReactTransition] = React__namespace.useTransition();
1446
- const pendingMatchesRef = React__namespace.useRef([]);
1447
1164
  const state = React__namespace.useMemo(() => ({
1448
1165
  ...preState,
1449
1166
  status: isTransitioning ? 'pending' : 'idle',
1450
- location: isTransitioning ? latestLocationRef.current : preState.location,
1451
- pendingMatches: pendingMatchesRef.current
1167
+ location: isTransitioning ? router.latestLocation : preState.location,
1168
+ pendingMatches: router.pendingMatches
1452
1169
  }), [preState, isTransitioning]);
1170
+ router.setState = setState;
1171
+ router.state = state;
1172
+ router.startReactTransition = startReactTransition;
1173
+ React__namespace.useLayoutEffect(() => {
1174
+ const unsub = router.history.subscribe(() => {
1175
+ router.latestLocation = router.parseLocation(router.latestLocation);
1176
+ if (state.location !== router.latestLocation) {
1177
+ startReactTransition(() => {
1178
+ try {
1179
+ router.load();
1180
+ } catch (err) {
1181
+ console.error(err);
1182
+ }
1183
+ });
1184
+ }
1185
+ });
1186
+ const nextLocation = router.buildLocation({
1187
+ search: true,
1188
+ params: true,
1189
+ hash: true,
1190
+ state: true
1191
+ });
1192
+ if (state.location.href !== nextLocation.href) {
1193
+ router.commitLocation({
1194
+ ...nextLocation,
1195
+ replace: true
1196
+ });
1197
+ }
1198
+ return () => {
1199
+ unsub();
1200
+ };
1201
+ }, [history]);
1453
1202
  React__namespace.useLayoutEffect(() => {
1454
1203
  if (!isTransitioning && state.resolvedLocation !== state.location) {
1455
1204
  router.emit({
@@ -1458,135 +1207,592 @@
1458
1207
  toLocation: state.location,
1459
1208
  pathChanged: state.location.href !== state.resolvedLocation?.href
1460
1209
  });
1461
- pendingMatchesRef.current = [];
1210
+ router.pendingMatches = [];
1462
1211
  setState(s => ({
1463
1212
  ...s,
1464
1213
  resolvedLocation: s.location
1465
1214
  }));
1466
1215
  }
1467
1216
  });
1468
- const basepath = `/${trimPath(options.basepath ?? '') ?? ''}`;
1469
- const resolvePathWithBase = useStableCallback((from, path) => {
1470
- return resolvePath(basepath, from, cleanPath(path));
1471
- });
1472
- const [routesById, routesByPath] = React__namespace.useMemo(() => {
1473
- const routesById = {};
1474
- const routesByPath = {};
1475
- const recurseRoutes = routes => {
1476
- routes.forEach((route, i) => {
1477
- route.init({
1478
- originalIndex: i
1479
- });
1480
- const existingRoute = routesById[route.id];
1481
- invariant(!existingRoute, `Duplicate routes found with id: ${String(route.id)}`);
1482
- routesById[route.id] = route;
1483
- if (!route.isRoot && route.path) {
1484
- const trimmedFullPath = trimPathRight(route.fullPath);
1485
- if (!routesByPath[trimmedFullPath] || route.fullPath.endsWith('/')) {
1486
- routesByPath[trimmedFullPath] = route;
1487
- }
1488
- }
1489
- const children = route.children;
1490
- if (children?.length) {
1491
- recurseRoutes(children);
1492
- }
1493
- });
1494
- };
1495
- recurseRoutes([router.routeTree]);
1496
- return [routesById, routesByPath];
1497
- }, []);
1498
- const looseRoutesById = routesById;
1499
- const flatRoutes = React__namespace.useMemo(() => Object.values(routesByPath).map((d, i) => {
1500
- const trimmed = trimPath(d.fullPath);
1501
- const parsed = parsePathname(trimmed);
1502
- while (parsed.length > 1 && parsed[0]?.value === '/') {
1503
- parsed.shift();
1504
- }
1505
- const score = parsed.map(d => {
1506
- if (d.type === 'param') {
1507
- return 0.5;
1508
- }
1509
- if (d.type === 'wildcard') {
1510
- return 0.25;
1217
+ React__namespace.useLayoutEffect(() => {
1218
+ startReactTransition(() => {
1219
+ try {
1220
+ router.load();
1221
+ } catch (err) {
1222
+ console.error(err);
1511
1223
  }
1512
- return 1;
1513
1224
  });
1514
- return {
1515
- child: d,
1516
- trimmed,
1517
- parsed,
1518
- index: i,
1519
- score
1225
+ }, []);
1226
+ return /*#__PURE__*/React__namespace.createElement(routerContext.Provider, {
1227
+ value: router
1228
+ }, /*#__PURE__*/React__namespace.createElement(Matches, null));
1229
+ }
1230
+ function getRouteMatch(state, id) {
1231
+ return [...state.pendingMatches, ...state.matches].find(d => d.id === id);
1232
+ }
1233
+ function useRouterState(opts) {
1234
+ const {
1235
+ state
1236
+ } = useRouter();
1237
+ // return useStore(router.__store, opts?.select as any)
1238
+ return opts?.select ? opts.select(state) : state;
1239
+ }
1240
+ function useRouter() {
1241
+ const resolvedContext = window.__TSR_ROUTER_CONTEXT__ || routerContext;
1242
+ const value = React__namespace.useContext(resolvedContext);
1243
+ warning(value, 'useRouter must be used inside a <RouterProvider> component!');
1244
+ return value;
1245
+ }
1246
+
1247
+ function defer(_promise) {
1248
+ const promise = _promise;
1249
+ if (!promise.__deferredState) {
1250
+ promise.__deferredState = {
1251
+ uid: Math.random().toString(36).slice(2),
1252
+ status: 'pending'
1520
1253
  };
1521
- }).sort((a, b) => {
1522
- let isIndex = a.trimmed === '/' ? 1 : b.trimmed === '/' ? -1 : 0;
1523
- if (isIndex !== 0) return isIndex;
1524
- const length = Math.min(a.score.length, b.score.length);
1525
-
1526
- // Sort by length of score
1527
- if (a.score.length !== b.score.length) {
1528
- return b.score.length - a.score.length;
1529
- }
1254
+ const state = promise.__deferredState;
1255
+ promise.then(data => {
1256
+ state.status = 'success';
1257
+ state.data = data;
1258
+ }).catch(error => {
1259
+ state.status = 'error';
1260
+ state.error = error;
1261
+ });
1262
+ }
1263
+ return promise;
1264
+ }
1265
+ function isDehydratedDeferred(obj) {
1266
+ return typeof obj === 'object' && obj !== null && !(obj instanceof Promise) && !obj.then && '__deferredState' in obj;
1267
+ }
1530
1268
 
1531
- // Sort by min available score
1532
- for (let i = 0; i < length; i++) {
1533
- if (a.score[i] !== b.score[i]) {
1534
- return b.score[i] - a.score[i];
1535
- }
1536
- }
1269
+ function useAwaited({
1270
+ promise
1271
+ }) {
1272
+ const router = useRouter();
1273
+ let state = promise.__deferredState;
1274
+ const key = `__TSR__DEFERRED__${state.uid}`;
1275
+ if (isDehydratedDeferred(promise)) {
1276
+ state = router.hydrateData(key);
1277
+ promise = Promise.resolve(state.data);
1278
+ promise.__deferredState = state;
1279
+ }
1280
+ if (state.status === 'pending') {
1281
+ throw promise;
1282
+ }
1283
+ if (state.status === 'error') {
1284
+ throw state.error;
1285
+ }
1286
+ router.dehydrateData(key, state);
1287
+ return [state.data];
1288
+ }
1289
+ function Await(props) {
1290
+ const awaited = useAwaited(props);
1291
+ return props.children(...awaited);
1292
+ }
1537
1293
 
1538
- // Sort by min available parsed value
1539
- for (let i = 0; i < length; i++) {
1540
- if (a.parsed[i].value !== b.parsed[i].value) {
1541
- return a.parsed[i].value > b.parsed[i].value ? 1 : -1;
1542
- }
1543
- }
1294
+ class FileRoute {
1295
+ constructor(path) {
1296
+ this.path = path;
1297
+ }
1298
+ createRoute = options => {
1299
+ const route = new Route(options);
1300
+ route.isRoot = false;
1301
+ return route;
1302
+ };
1303
+ }
1544
1304
 
1545
- // Sort by length of trimmed full path
1546
- if (a.trimmed !== b.trimmed) {
1547
- return a.trimmed > b.trimmed ? 1 : -1;
1305
+ function lazyRouteComponent(importer, exportName) {
1306
+ let loadPromise;
1307
+ const load = () => {
1308
+ if (!loadPromise) {
1309
+ loadPromise = importer();
1548
1310
  }
1311
+ return loadPromise;
1312
+ };
1313
+ const lazyComp = /*#__PURE__*/React__namespace.lazy(async () => {
1314
+ const moduleExports = await load();
1315
+ const comp = moduleExports[exportName ?? 'default'];
1316
+ return {
1317
+ default: comp
1318
+ };
1319
+ });
1320
+ lazyComp.preload = load;
1321
+ return lazyComp;
1322
+ }
1549
1323
 
1550
- // Sort by original index
1551
- return a.index - b.index;
1552
- }).map((d, i) => {
1553
- d.child.rank = i;
1554
- return d.child;
1555
- }), [routesByPath]);
1556
- const matchRoutes = useStableCallback((pathname, locationSearch, opts) => {
1557
- let routeParams = {};
1558
- let foundRoute = flatRoutes.find(route => {
1559
- const matchedParams = matchPathname(basepath, trimPathRight(pathname), {
1560
- to: route.fullPath,
1561
- caseSensitive: route.options.caseSensitive ?? options.caseSensitive,
1562
- fuzzy: false
1563
- });
1564
- if (matchedParams) {
1565
- routeParams = matchedParams;
1566
- return true;
1324
+ function _extends() {
1325
+ _extends = Object.assign ? Object.assign.bind() : function (target) {
1326
+ for (var i = 1; i < arguments.length; i++) {
1327
+ var source = arguments[i];
1328
+ for (var key in source) {
1329
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
1330
+ target[key] = source[key];
1331
+ }
1567
1332
  }
1568
- return false;
1569
- });
1570
- let routeCursor = foundRoute || routesById['__root__'];
1571
- let matchedRoutes = [routeCursor];
1572
- // let includingLayouts = true
1573
- while (routeCursor?.parentRoute) {
1574
- routeCursor = routeCursor.parentRoute;
1575
- if (routeCursor) matchedRoutes.unshift(routeCursor);
1576
1333
  }
1334
+ return target;
1335
+ };
1336
+ return _extends.apply(this, arguments);
1337
+ }
1577
1338
 
1578
- // Existing matches are matches that are already loaded along with
1579
- // pending matches that are still loading
1339
+ function useLinkProps(options) {
1340
+ const {
1341
+ buildLink
1342
+ } = useRouter();
1343
+ const match = useMatch({
1344
+ strict: false
1345
+ });
1346
+ const {
1347
+ // custom props
1348
+ type,
1349
+ children,
1350
+ target,
1351
+ activeProps = () => ({
1352
+ className: 'active'
1353
+ }),
1354
+ inactiveProps = () => ({}),
1355
+ activeOptions,
1356
+ disabled,
1357
+ hash,
1358
+ search,
1359
+ params,
1360
+ to,
1361
+ state,
1362
+ mask,
1363
+ preload,
1364
+ preloadDelay,
1365
+ replace,
1366
+ startTransition,
1367
+ resetScroll,
1368
+ // element props
1369
+ style,
1370
+ className,
1371
+ onClick,
1372
+ onFocus,
1373
+ onMouseEnter,
1374
+ onMouseLeave,
1375
+ onTouchStart,
1376
+ ...rest
1377
+ } = options;
1378
+ const linkInfo = buildLink({
1379
+ from: options.to ? match.pathname : undefined,
1380
+ ...options
1381
+ });
1382
+ if (linkInfo.type === 'external') {
1383
+ const {
1384
+ href
1385
+ } = linkInfo;
1386
+ return {
1387
+ href
1388
+ };
1389
+ }
1390
+ const {
1391
+ handleClick,
1392
+ handleFocus,
1393
+ handleEnter,
1394
+ handleLeave,
1395
+ handleTouchStart,
1396
+ isActive,
1397
+ next
1398
+ } = linkInfo;
1399
+ const composeHandlers = handlers => e => {
1400
+ if (e.persist) e.persist();
1401
+ handlers.filter(Boolean).forEach(handler => {
1402
+ if (e.defaultPrevented) return;
1403
+ handler(e);
1404
+ });
1405
+ };
1580
1406
 
1581
- const parseErrors = matchedRoutes.map(route => {
1582
- let parsedParamsError;
1583
- if (route.options.parseParams) {
1584
- try {
1585
- const parsedParams = route.options.parseParams(routeParams);
1586
- // Add the parsed params to the accumulated params bag
1587
- Object.assign(routeParams, parsedParams);
1588
- } catch (err) {
1589
- parsedParamsError = new PathParamError(err.message, {
1407
+ // Get the active props
1408
+ const resolvedActiveProps = isActive ? functionalUpdate(activeProps, {}) ?? {} : {};
1409
+
1410
+ // Get the inactive props
1411
+ const resolvedInactiveProps = isActive ? {} : functionalUpdate(inactiveProps, {}) ?? {};
1412
+ return {
1413
+ ...resolvedActiveProps,
1414
+ ...resolvedInactiveProps,
1415
+ ...rest,
1416
+ href: disabled ? undefined : next.maskedLocation ? next.maskedLocation.href : next.href,
1417
+ onClick: composeHandlers([onClick, handleClick]),
1418
+ onFocus: composeHandlers([onFocus, handleFocus]),
1419
+ onMouseEnter: composeHandlers([onMouseEnter, handleEnter]),
1420
+ onMouseLeave: composeHandlers([onMouseLeave, handleLeave]),
1421
+ onTouchStart: composeHandlers([onTouchStart, handleTouchStart]),
1422
+ target,
1423
+ style: {
1424
+ ...style,
1425
+ ...resolvedActiveProps.style,
1426
+ ...resolvedInactiveProps.style
1427
+ },
1428
+ className: [className, resolvedActiveProps.className, resolvedInactiveProps.className].filter(Boolean).join(' ') || undefined,
1429
+ ...(disabled ? {
1430
+ role: 'link',
1431
+ 'aria-disabled': true
1432
+ } : undefined),
1433
+ ['data-status']: isActive ? 'active' : undefined
1434
+ };
1435
+ }
1436
+ const Link = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
1437
+ const linkProps = useLinkProps(props);
1438
+ return /*#__PURE__*/React__namespace.createElement("a", _extends({
1439
+ ref: ref
1440
+ }, linkProps, {
1441
+ children: typeof props.children === 'function' ? props.children({
1442
+ isActive: linkProps['data-status'] === 'active'
1443
+ }) : props.children
1444
+ }));
1445
+ });
1446
+
1447
+ // @ts-nocheck
1448
+
1449
+ // qss has been slightly modified and inlined here for our use cases (and compression's sake). We've included it as a hard dependency for MIT license attribution.
1450
+
1451
+ function encode(obj, pfx) {
1452
+ var k,
1453
+ i,
1454
+ tmp,
1455
+ str = '';
1456
+ for (k in obj) {
1457
+ if ((tmp = obj[k]) !== void 0) {
1458
+ if (Array.isArray(tmp)) {
1459
+ for (i = 0; i < tmp.length; i++) {
1460
+ str && (str += '&');
1461
+ str += encodeURIComponent(k) + '=' + encodeURIComponent(tmp[i]);
1462
+ }
1463
+ } else {
1464
+ str && (str += '&');
1465
+ str += encodeURIComponent(k) + '=' + encodeURIComponent(tmp);
1466
+ }
1467
+ }
1468
+ }
1469
+ return (pfx || '') + str;
1470
+ }
1471
+ function toValue(mix) {
1472
+ if (!mix) return '';
1473
+ var str = decodeURIComponent(mix);
1474
+ if (str === 'false') return false;
1475
+ if (str === 'true') return true;
1476
+ return +str * 0 === 0 && +str + '' === str ? +str : str;
1477
+ }
1478
+ function decode(str) {
1479
+ var tmp,
1480
+ k,
1481
+ out = {},
1482
+ arr = str.split('&');
1483
+ while (tmp = arr.shift()) {
1484
+ tmp = tmp.split('=');
1485
+ k = tmp.shift();
1486
+ if (out[k] !== void 0) {
1487
+ out[k] = [].concat(out[k], toValue(tmp.shift()));
1488
+ } else {
1489
+ out[k] = toValue(tmp.shift());
1490
+ }
1491
+ }
1492
+ return out;
1493
+ }
1494
+
1495
+ // Detect if we're in the DOM
1496
+
1497
+ function redirect(opts) {
1498
+ opts.isRedirect = true;
1499
+ return opts;
1500
+ }
1501
+ function isRedirect(obj) {
1502
+ return !!obj?.isRedirect;
1503
+ }
1504
+
1505
+ const defaultParseSearch = parseSearchWith(JSON.parse);
1506
+ const defaultStringifySearch = stringifySearchWith(JSON.stringify, JSON.parse);
1507
+ function parseSearchWith(parser) {
1508
+ return searchStr => {
1509
+ if (searchStr.substring(0, 1) === '?') {
1510
+ searchStr = searchStr.substring(1);
1511
+ }
1512
+ let query = decode(searchStr);
1513
+
1514
+ // Try to parse any query params that might be json
1515
+ for (let key in query) {
1516
+ const value = query[key];
1517
+ if (typeof value === 'string') {
1518
+ try {
1519
+ query[key] = parser(value);
1520
+ } catch (err) {
1521
+ //
1522
+ }
1523
+ }
1524
+ }
1525
+ return query;
1526
+ };
1527
+ }
1528
+ function stringifySearchWith(stringify, parser) {
1529
+ function stringifyValue(val) {
1530
+ if (typeof val === 'object' && val !== null) {
1531
+ try {
1532
+ return stringify(val);
1533
+ } catch (err) {
1534
+ // silent
1535
+ }
1536
+ } else if (typeof val === 'string' && typeof parser === 'function') {
1537
+ try {
1538
+ // Check if it's a valid parseable string.
1539
+ // If it is, then stringify it again.
1540
+ parser(val);
1541
+ return stringify(val);
1542
+ } catch (err) {
1543
+ // silent
1544
+ }
1545
+ }
1546
+ return val;
1547
+ }
1548
+ return search => {
1549
+ search = {
1550
+ ...search
1551
+ };
1552
+ if (search) {
1553
+ Object.keys(search).forEach(key => {
1554
+ const val = search[key];
1555
+ if (typeof val === 'undefined' || val === undefined) {
1556
+ delete search[key];
1557
+ } else {
1558
+ search[key] = stringifyValue(val);
1559
+ }
1560
+ });
1561
+ }
1562
+ const searchStr = encode(search).toString();
1563
+ return searchStr ? `?${searchStr}` : '';
1564
+ };
1565
+ }
1566
+
1567
+ //
1568
+
1569
+ const componentTypes = ['component', 'errorComponent', 'pendingComponent'];
1570
+ const preloadWarning = 'Error preloading route! ☝️';
1571
+ class Router {
1572
+ // Option-independent properties
1573
+ tempLocationKey = `${Math.round(Math.random() * 10000000)}`;
1574
+ resetNextScroll = true;
1575
+ navigateTimeout = null;
1576
+ latestLoadPromise = Promise.resolve();
1577
+ subscribers = new Set();
1578
+ pendingMatches = [];
1579
+ injectedHtml = [];
1580
+
1581
+ // Must build in constructor
1582
+
1583
+ constructor(options) {
1584
+ this.updateOptions({
1585
+ defaultPreloadDelay: 50,
1586
+ context: undefined,
1587
+ ...options,
1588
+ stringifySearch: options?.stringifySearch ?? defaultStringifySearch,
1589
+ parseSearch: options?.parseSearch ?? defaultParseSearch
1590
+ });
1591
+ }
1592
+ startReactTransition = () => {
1593
+ warning(false, 'startReactTransition implementation is missing. If you see this, please file an issue.');
1594
+ };
1595
+ setState = () => {
1596
+ warning(false, 'setState implementation is missing. If you see this, please file an issue.');
1597
+ };
1598
+ updateOptions = newOptions => {
1599
+ this.options;
1600
+ this.options = {
1601
+ ...this.options,
1602
+ ...newOptions
1603
+ };
1604
+ this.basepath = `/${trimPath(newOptions.basepath ?? '') ?? ''}`;
1605
+ if (!this.history || this.options.history && this.options.history !== this.history) {
1606
+ this.history = this.options.history ?? createBrowserHistory();
1607
+ this.latestLocation = this.parseLocation();
1608
+ }
1609
+ if (this.options.routeTree !== this.routeTree) {
1610
+ this.routeTree = this.options.routeTree;
1611
+ this.buildRouteTree();
1612
+ }
1613
+ if (!this.state) {
1614
+ this.state = getInitialRouterState(this.latestLocation);
1615
+ }
1616
+ };
1617
+ buildRouteTree = () => {
1618
+ this.routesById = {};
1619
+ this.routesByPath = {};
1620
+ const recurseRoutes = childRoutes => {
1621
+ childRoutes.forEach((childRoute, i) => {
1622
+ // if (typeof childRoute === 'function') {
1623
+ // childRoute = (childRoute as any)()
1624
+ // }
1625
+ childRoute.init({
1626
+ originalIndex: i
1627
+ });
1628
+ const existingRoute = this.routesById[childRoute.id];
1629
+ invariant(!existingRoute, `Duplicate routes found with id: ${String(childRoute.id)}`);
1630
+ this.routesById[childRoute.id] = childRoute;
1631
+ if (!childRoute.isRoot && childRoute.path) {
1632
+ const trimmedFullPath = trimPathRight(childRoute.fullPath);
1633
+ if (!this.routesByPath[trimmedFullPath] || childRoute.fullPath.endsWith('/')) {
1634
+ this.routesByPath[trimmedFullPath] = childRoute;
1635
+ }
1636
+ }
1637
+ const children = childRoute.children;
1638
+ if (children?.length) {
1639
+ recurseRoutes(children);
1640
+ }
1641
+ });
1642
+ };
1643
+ recurseRoutes([this.routeTree]);
1644
+ this.flatRoutes = Object.values(this.routesByPath).map((d, i) => {
1645
+ const trimmed = trimPath(d.fullPath);
1646
+ const parsed = parsePathname(trimmed);
1647
+ while (parsed.length > 1 && parsed[0]?.value === '/') {
1648
+ parsed.shift();
1649
+ }
1650
+ const score = parsed.map(d => {
1651
+ if (d.type === 'param') {
1652
+ return 0.5;
1653
+ }
1654
+ if (d.type === 'wildcard') {
1655
+ return 0.25;
1656
+ }
1657
+ return 1;
1658
+ });
1659
+ return {
1660
+ child: d,
1661
+ trimmed,
1662
+ parsed,
1663
+ index: i,
1664
+ score
1665
+ };
1666
+ }).sort((a, b) => {
1667
+ let isIndex = a.trimmed === '/' ? 1 : b.trimmed === '/' ? -1 : 0;
1668
+ if (isIndex !== 0) return isIndex;
1669
+ const length = Math.min(a.score.length, b.score.length);
1670
+
1671
+ // Sort by length of score
1672
+ if (a.score.length !== b.score.length) {
1673
+ return b.score.length - a.score.length;
1674
+ }
1675
+
1676
+ // Sort by min available score
1677
+ for (let i = 0; i < length; i++) {
1678
+ if (a.score[i] !== b.score[i]) {
1679
+ return b.score[i] - a.score[i];
1680
+ }
1681
+ }
1682
+
1683
+ // Sort by min available parsed value
1684
+ for (let i = 0; i < length; i++) {
1685
+ if (a.parsed[i].value !== b.parsed[i].value) {
1686
+ return a.parsed[i].value > b.parsed[i].value ? 1 : -1;
1687
+ }
1688
+ }
1689
+
1690
+ // Sort by length of trimmed full path
1691
+ if (a.trimmed !== b.trimmed) {
1692
+ return a.trimmed > b.trimmed ? 1 : -1;
1693
+ }
1694
+
1695
+ // Sort by original index
1696
+ return a.index - b.index;
1697
+ }).map((d, i) => {
1698
+ d.child.rank = i;
1699
+ return d.child;
1700
+ });
1701
+ };
1702
+ subscribe = (eventType, fn) => {
1703
+ const listener = {
1704
+ eventType,
1705
+ fn
1706
+ };
1707
+ this.subscribers.add(listener);
1708
+ return () => {
1709
+ this.subscribers.delete(listener);
1710
+ };
1711
+ };
1712
+ emit = routerEvent => {
1713
+ this.subscribers.forEach(listener => {
1714
+ if (listener.eventType === routerEvent.type) {
1715
+ listener.fn(routerEvent);
1716
+ }
1717
+ });
1718
+ };
1719
+ checkLatest = promise => {
1720
+ return this.latestLoadPromise !== promise ? this.latestLoadPromise : undefined;
1721
+ };
1722
+ parseLocation = previousLocation => {
1723
+ const parse = ({
1724
+ pathname,
1725
+ search,
1726
+ hash,
1727
+ state
1728
+ }) => {
1729
+ const parsedSearch = this.options.parseSearch(search);
1730
+ return {
1731
+ pathname: pathname,
1732
+ searchStr: search,
1733
+ search: replaceEqualDeep(previousLocation?.search, parsedSearch),
1734
+ hash: hash.split('#').reverse()[0] ?? '',
1735
+ href: `${pathname}${search}${hash}`,
1736
+ state: replaceEqualDeep(previousLocation?.state, state)
1737
+ };
1738
+ };
1739
+ const location = parse(this.history.location);
1740
+ let {
1741
+ __tempLocation,
1742
+ __tempKey
1743
+ } = location.state;
1744
+ if (__tempLocation && (!__tempKey || __tempKey === this.tempLocationKey)) {
1745
+ // Sync up the location keys
1746
+ const parsedTempLocation = parse(__tempLocation);
1747
+ parsedTempLocation.state.key = location.state.key;
1748
+ delete parsedTempLocation.state.__tempLocation;
1749
+ return {
1750
+ ...parsedTempLocation,
1751
+ maskedLocation: location
1752
+ };
1753
+ }
1754
+ return location;
1755
+ };
1756
+ resolvePathWithBase = (from, path) => {
1757
+ return resolvePath(this.basepath, from, cleanPath(path));
1758
+ };
1759
+ get looseRoutesById() {
1760
+ return this.routesById;
1761
+ }
1762
+ matchRoutes = (pathname, locationSearch, opts) => {
1763
+ let routeParams = {};
1764
+ let foundRoute = this.flatRoutes.find(route => {
1765
+ const matchedParams = matchPathname(this.basepath, trimPathRight(pathname), {
1766
+ to: route.fullPath,
1767
+ caseSensitive: route.options.caseSensitive ?? this.options.caseSensitive,
1768
+ fuzzy: false
1769
+ });
1770
+ if (matchedParams) {
1771
+ routeParams = matchedParams;
1772
+ return true;
1773
+ }
1774
+ return false;
1775
+ });
1776
+ let routeCursor = foundRoute || this.routesById['__root__'];
1777
+ let matchedRoutes = [routeCursor];
1778
+ // let includingLayouts = true
1779
+ while (routeCursor?.parentRoute) {
1780
+ routeCursor = routeCursor.parentRoute;
1781
+ if (routeCursor) matchedRoutes.unshift(routeCursor);
1782
+ }
1783
+
1784
+ // Existing matches are matches that are already loaded along with
1785
+ // pending matches that are still loading
1786
+
1787
+ const parseErrors = matchedRoutes.map(route => {
1788
+ let parsedParamsError;
1789
+ if (route.options.parseParams) {
1790
+ try {
1791
+ const parsedParams = route.options.parseParams(routeParams);
1792
+ // Add the parsed params to the accumulated params bag
1793
+ Object.assign(routeParams, parsedParams);
1794
+ } catch (err) {
1795
+ parsedParamsError = new PathParamError(err.message, {
1590
1796
  cause: err
1591
1797
  });
1592
1798
  if (opts?.throwOnError) {
@@ -1604,10 +1810,12 @@
1604
1810
  // Waste not, want not. If we already have a match for this route,
1605
1811
  // reuse it. This is important for layout routes, which might stick
1606
1812
  // around between navigation actions that only change leaf routes.
1607
- const existingMatch = getRouteMatch(state, matchId);
1813
+ const existingMatch = getRouteMatch(this.state, matchId);
1814
+ const cause = this.state.matches.find(d => d.id === matchId) ? 'stay' : 'enter';
1608
1815
  if (existingMatch) {
1609
1816
  return {
1610
- ...existingMatch
1817
+ ...existingMatch,
1818
+ cause
1611
1819
  };
1612
1820
  }
1613
1821
 
@@ -1617,7 +1825,7 @@
1617
1825
  id: matchId,
1618
1826
  routeId: route.id,
1619
1827
  params: routeParams,
1620
- pathname: joinPaths([basepath, interpolatedPath]),
1828
+ pathname: joinPaths([this.basepath, interpolatedPath]),
1621
1829
  updatedAt: Date.now(),
1622
1830
  routeSearch: {},
1623
1831
  search: {},
@@ -1631,7 +1839,8 @@
1631
1839
  context: undefined,
1632
1840
  abortController: new AbortController(),
1633
1841
  shouldReloadDeps: undefined,
1634
- fetchedAt: 0
1842
+ fetchedAt: 0,
1843
+ cause
1635
1844
  };
1636
1845
  return routeMatch;
1637
1846
  });
@@ -1641,7 +1850,7 @@
1641
1850
  // so that we can use the parent match's search params and context
1642
1851
  matches.forEach((match, i) => {
1643
1852
  const parentMatch = matches[i - 1];
1644
- const route = looseRoutesById[match.routeId];
1853
+ const route = this.looseRoutesById[match.routeId];
1645
1854
  const searchInfo = (() => {
1646
1855
  // Validate the search params and stabilize them
1647
1856
  const parentSearchInfo = {
@@ -1675,28 +1884,28 @@
1675
1884
  Object.assign(match, searchInfo);
1676
1885
  });
1677
1886
  return matches;
1678
- });
1679
- const cancelMatch = useStableCallback(id => {
1680
- getRouteMatch(state, id)?.abortController?.abort();
1681
- });
1682
- const cancelMatches = useStableCallback(state => {
1683
- state.matches.forEach(match => {
1684
- cancelMatch(match.id);
1887
+ };
1888
+ cancelMatch = id => {
1889
+ getRouteMatch(this.state, id)?.abortController?.abort();
1890
+ };
1891
+ cancelMatches = () => {
1892
+ this.state.matches.forEach(match => {
1893
+ this.cancelMatch(match.id);
1685
1894
  });
1686
- });
1687
- const buildLocation = useStableCallback(opts => {
1895
+ };
1896
+ buildLocation = opts => {
1688
1897
  const build = (dest = {}, matches) => {
1689
- const from = latestLocationRef.current;
1898
+ const from = this.latestLocation;
1690
1899
  const fromPathname = dest.from ?? from.pathname;
1691
- let pathname = resolvePathWithBase(fromPathname, `${dest.to ?? ''}`);
1692
- const fromMatches = matchRoutes(fromPathname, from.search);
1900
+ let pathname = this.resolvePathWithBase(fromPathname, `${dest.to ?? ''}`);
1901
+ const fromMatches = this.matchRoutes(fromPathname, from.search);
1693
1902
  const stayingMatches = matches?.filter(d => fromMatches?.find(e => e.routeId === d.routeId));
1694
1903
  const prevParams = {
1695
1904
  ...last(fromMatches)?.params
1696
1905
  };
1697
1906
  let nextParams = (dest.params ?? true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
1698
1907
  if (nextParams) {
1699
- matches?.map(d => looseRoutesById[d.routeId].options.stringifyParams).filter(Boolean).forEach(fn => {
1908
+ matches?.map(d => this.looseRoutesById[d.routeId].options.stringifyParams).filter(Boolean).forEach(fn => {
1700
1909
  nextParams = {
1701
1910
  ...nextParams,
1702
1911
  ...fn(nextParams)
@@ -1704,8 +1913,8 @@
1704
1913
  });
1705
1914
  }
1706
1915
  pathname = interpolatePath(pathname, nextParams ?? {});
1707
- const preSearchFilters = stayingMatches?.map(match => looseRoutesById[match.routeId].options.preSearchFilters ?? []).flat().filter(Boolean) ?? [];
1708
- const postSearchFilters = stayingMatches?.map(match => looseRoutesById[match.routeId].options.postSearchFilters ?? []).flat().filter(Boolean) ?? [];
1916
+ const preSearchFilters = stayingMatches?.map(match => this.looseRoutesById[match.routeId].options.preSearchFilters ?? []).flat().filter(Boolean) ?? [];
1917
+ const postSearchFilters = stayingMatches?.map(match => this.looseRoutesById[match.routeId].options.postSearchFilters ?? []).flat().filter(Boolean) ?? [];
1709
1918
 
1710
1919
  // Pre filters first
1711
1920
  const preFilteredSearch = preSearchFilters?.length ? preSearchFilters?.reduce((prev, next) => next(prev), from.search) : from.search;
@@ -1719,7 +1928,7 @@
1719
1928
  // Then post filters
1720
1929
  const postFilteredSearch = postSearchFilters?.length ? postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
1721
1930
  const search = replaceEqualDeep(from.search, postFilteredSearch);
1722
- const searchStr = options.stringifySearch(search);
1931
+ const searchStr = this.options.stringifySearch(search);
1723
1932
  const hash = dest.hash === true ? from.hash : dest.hash ? functionalUpdate(dest.hash, from.hash) : from.hash;
1724
1933
  const hashStr = hash ? `#${hash}` : '';
1725
1934
  let nextState = dest.state === true ? from.state : dest.state ? functionalUpdate(dest.state, from.state) : from.state;
@@ -1730,7 +1939,7 @@
1730
1939
  searchStr,
1731
1940
  state: nextState,
1732
1941
  hash,
1733
- href: history.createHref(`${pathname}${searchStr}${hashStr}`),
1942
+ href: this.history.createHref(`${pathname}${searchStr}${hashStr}`),
1734
1943
  unmaskOnReload: dest.unmaskOnReload
1735
1944
  };
1736
1945
  };
@@ -1739,8 +1948,8 @@
1739
1948
  let maskedNext = maskedDest ? build(maskedDest) : undefined;
1740
1949
  if (!maskedNext) {
1741
1950
  let params = {};
1742
- let foundMask = options.routeMasks?.find(d => {
1743
- const match = matchPathname(basepath, next.pathname, {
1951
+ let foundMask = this.options.routeMasks?.find(d => {
1952
+ const match = matchPathname(this.basepath, next.pathname, {
1744
1953
  to: d.from,
1745
1954
  caseSensitive: false,
1746
1955
  fuzzy: false
@@ -1760,8 +1969,8 @@
1760
1969
  maskedNext = build(maskedDest);
1761
1970
  }
1762
1971
  }
1763
- const nextMatches = matchRoutes(next.pathname, next.search);
1764
- const maskedMatches = maskedNext ? matchRoutes(maskedNext.pathname, maskedNext.search) : undefined;
1972
+ const nextMatches = this.matchRoutes(next.pathname, next.search);
1973
+ const maskedMatches = maskedNext ? this.matchRoutes(maskedNext.pathname, maskedNext.search) : undefined;
1765
1974
  const maskedFinal = maskedNext ? build(maskedDest, maskedMatches) : undefined;
1766
1975
  const final = build(dest, nextMatches);
1767
1976
  if (maskedFinal) {
@@ -1776,13 +1985,13 @@
1776
1985
  });
1777
1986
  }
1778
1987
  return buildWithMatches(opts);
1779
- });
1780
- const commitLocation = useStableCallback(async ({
1988
+ };
1989
+ commitLocation = async ({
1781
1990
  startTransition,
1782
1991
  ...next
1783
1992
  }) => {
1784
- if (navigateTimeoutRef.current) clearTimeout(navigateTimeoutRef.current);
1785
- const isSameUrl = latestLocationRef.current.href === next.href;
1993
+ if (this.navigateTimeout) clearTimeout(this.navigateTimeout);
1994
+ const isSameUrl = this.latestLocation.href === next.href;
1786
1995
 
1787
1996
  // If the next urls are the same and we're not replacing,
1788
1997
  // do nothing
@@ -1809,37 +2018,37 @@
1809
2018
  }
1810
2019
  }
1811
2020
  };
1812
- if (nextHistory.unmaskOnReload ?? options.unmaskOnReload ?? false) {
1813
- nextHistory.state.__tempKey = tempLocationKeyRef.current;
2021
+ if (nextHistory.unmaskOnReload ?? this.options.unmaskOnReload ?? false) {
2022
+ nextHistory.state.__tempKey = this.tempLocationKey;
1814
2023
  }
1815
2024
  }
1816
2025
  const apply = () => {
1817
- history[next.replace ? 'replace' : 'push'](nextHistory.href, nextHistory.state);
2026
+ this.history[next.replace ? 'replace' : 'push'](nextHistory.href, nextHistory.state);
1818
2027
  };
1819
2028
  if (startTransition ?? true) {
1820
- startReactTransition(apply);
2029
+ this.startReactTransition(apply);
1821
2030
  } else {
1822
2031
  apply();
1823
2032
  }
1824
2033
  }
1825
- resetNextScrollRef.current = next.resetScroll ?? true;
1826
- return latestLoadPromiseRef.current;
1827
- });
1828
- const buildAndCommitLocation = useStableCallback(({
2034
+ this.resetNextScroll = next.resetScroll ?? true;
2035
+ return this.latestLoadPromise;
2036
+ };
2037
+ buildAndCommitLocation = ({
1829
2038
  replace,
1830
2039
  resetScroll,
1831
2040
  startTransition,
1832
2041
  ...rest
1833
2042
  } = {}) => {
1834
- const location = buildLocation(rest);
1835
- return commitLocation({
2043
+ const location = this.buildLocation(rest);
2044
+ return this.commitLocation({
1836
2045
  ...location,
1837
2046
  startTransition,
1838
2047
  replace,
1839
2048
  resetScroll
1840
2049
  });
1841
- });
1842
- const navigate = useStableCallback(({
2050
+ };
2051
+ navigate = ({
1843
2052
  from,
1844
2053
  to = '',
1845
2054
  ...rest
@@ -1857,13 +2066,13 @@
1857
2066
  isExternal = true;
1858
2067
  } catch (e) {}
1859
2068
  invariant(!isExternal, 'Attempting to navigate to external url with this.navigate!');
1860
- return buildAndCommitLocation({
2069
+ return this.buildAndCommitLocation({
1861
2070
  ...rest,
1862
2071
  from: fromString,
1863
2072
  to: toString
1864
2073
  });
1865
- });
1866
- const loadMatches = useStableCallback(async ({
2074
+ };
2075
+ loadMatches = async ({
1867
2076
  checkLatest,
1868
2077
  matches,
1869
2078
  preload
@@ -1875,7 +2084,7 @@
1875
2084
  try {
1876
2085
  for (let [index, match] of matches.entries()) {
1877
2086
  const parentMatch = matches[index - 1];
1878
- const route = looseRoutesById[match.routeId];
2087
+ const route = this.looseRoutesById[match.routeId];
1879
2088
  const handleError = (err, code) => {
1880
2089
  err.routerCode = code;
1881
2090
  firstBadMatchIndex = firstBadMatchIndex ?? index;
@@ -1904,19 +2113,21 @@
1904
2113
  if (match.searchError) {
1905
2114
  handleError(match.searchError, 'VALIDATE_SEARCH');
1906
2115
  }
1907
- const parentContext = parentMatch?.context ?? options.context ?? {};
2116
+ const parentContext = parentMatch?.context ?? this.options.context ?? {};
1908
2117
  const beforeLoadContext = (await route.options.beforeLoad?.({
1909
2118
  search: match.search,
1910
2119
  abortController: match.abortController,
1911
2120
  params: match.params,
1912
2121
  preload: !!preload,
1913
2122
  context: parentContext,
1914
- location: state.location,
1915
- navigate: opts => navigate({
2123
+ location: this.state.location,
2124
+ // TOOD: just expose state and router, etc
2125
+ navigate: opts => this.navigate({
1916
2126
  ...opts,
1917
2127
  from: match.pathname
1918
2128
  }),
1919
- buildLocation
2129
+ buildLocation: this.buildLocation,
2130
+ cause: match.cause
1920
2131
  })) ?? {};
1921
2132
  const context = {
1922
2133
  ...parentContext,
@@ -1933,7 +2144,7 @@
1933
2144
  }
1934
2145
  } catch (err) {
1935
2146
  if (isRedirect(err)) {
1936
- if (!preload) navigate(err);
2147
+ if (!preload) this.navigate(err);
1937
2148
  return matches;
1938
2149
  }
1939
2150
  throw err;
@@ -1943,11 +2154,11 @@
1943
2154
  validResolvedMatches.forEach((match, index) => {
1944
2155
  matchPromises.push((async () => {
1945
2156
  const parentMatchPromise = matchPromises[index - 1];
1946
- const route = looseRoutesById[match.routeId];
2157
+ const route = this.looseRoutesById[match.routeId];
1947
2158
  const handleIfRedirect = err => {
1948
2159
  if (isRedirect(err)) {
1949
2160
  if (!preload) {
1950
- navigate(err);
2161
+ this.navigate(err);
1951
2162
  }
1952
2163
  return true;
1953
2164
  }
@@ -1960,9 +2171,8 @@
1960
2171
  invalid: false
1961
2172
  };
1962
2173
  if (match.isFetching) {
1963
- loadPromise = getRouteMatch(state, match.id)?.loadPromise;
2174
+ loadPromise = getRouteMatch(this.state, match.id)?.loadPromise;
1964
2175
  } else {
1965
- const cause = state.matches.find(d => d.id === match.id) ? 'stay' : 'enter';
1966
2176
  const loaderContext = {
1967
2177
  params: match.params,
1968
2178
  search: match.search,
@@ -1970,20 +2180,20 @@
1970
2180
  parentMatchPromise,
1971
2181
  abortController: match.abortController,
1972
2182
  context: match.context,
1973
- location: state.location,
1974
- navigate: opts => navigate({
2183
+ location: this.state.location,
2184
+ navigate: opts => this.navigate({
1975
2185
  ...opts,
1976
2186
  from: match.pathname
1977
2187
  }),
1978
- cause
2188
+ cause: match.cause
1979
2189
  };
1980
2190
 
1981
2191
  // Default to reloading the route all the time
1982
2192
  let shouldReload = true;
1983
2193
  let shouldReloadDeps = typeof route.options.shouldReload === 'function' ? route.options.shouldReload?.(loaderContext) : !!(route.options.shouldReload ?? true);
1984
- if (cause === 'enter') {
2194
+ if (match.cause === 'enter') {
1985
2195
  match.shouldReloadDeps = shouldReloadDeps;
1986
- } else if (cause === 'stay') {
2196
+ } else if (match.cause === 'stay') {
1987
2197
  if (typeof shouldReloadDeps === 'object') {
1988
2198
  // compare the deps to see if they've changed
1989
2199
  shouldReload = !deepEqual(shouldReloadDeps, match.shouldReloadDeps);
@@ -2019,7 +2229,7 @@
2019
2229
  loadPromise
2020
2230
  };
2021
2231
  if (!preload) {
2022
- setState(s => ({
2232
+ this.setState(s => ({
2023
2233
  ...s,
2024
2234
  matches: s.matches.map(d => d.id === match.id ? match : d)
2025
2235
  }));
@@ -2054,7 +2264,7 @@
2054
2264
  };
2055
2265
  }
2056
2266
  if (!preload) {
2057
- setState(s => ({
2267
+ this.setState(s => ({
2058
2268
  ...s,
2059
2269
  matches: s.matches.map(d => d.id === match.id ? match : d)
2060
2270
  }));
@@ -2063,17 +2273,17 @@
2063
2273
  });
2064
2274
  await Promise.all(matchPromises);
2065
2275
  return matches;
2066
- });
2067
- const load = useStableCallback(async () => {
2276
+ };
2277
+ load = async () => {
2068
2278
  const promise = new Promise(async (resolve, reject) => {
2069
- const next = latestLocationRef.current;
2070
- const prevLocation = state.resolvedLocation;
2279
+ const next = this.latestLocation;
2280
+ const prevLocation = this.state.resolvedLocation;
2071
2281
  const pathDidChange = prevLocation.href !== next.href;
2072
2282
  let latestPromise;
2073
2283
 
2074
2284
  // Cancel any pending matches
2075
- cancelMatches(state);
2076
- router.emit({
2285
+ this.cancelMatches();
2286
+ this.emit({
2077
2287
  type: 'onBeforeLoad',
2078
2288
  fromLocation: prevLocation,
2079
2289
  toLocation: next,
@@ -2081,14 +2291,14 @@
2081
2291
  });
2082
2292
 
2083
2293
  // Match the routes
2084
- let matches = matchRoutes(next.pathname, next.search, {
2294
+ let matches = this.matchRoutes(next.pathname, next.search, {
2085
2295
  debug: true
2086
2296
  });
2087
- pendingMatchesRef.current = matches;
2088
- const previousMatches = state.matches;
2297
+ this.pendingMatches = matches;
2298
+ const previousMatches = this.state.matches;
2089
2299
 
2090
2300
  // Ingest the new matches
2091
- setState(s => ({
2301
+ this.setState(s => ({
2092
2302
  ...s,
2093
2303
  status: 'pending',
2094
2304
  location: next,
@@ -2097,9 +2307,9 @@
2097
2307
  try {
2098
2308
  try {
2099
2309
  // Load the matches
2100
- await loadMatches({
2310
+ await this.loadMatches({
2101
2311
  matches,
2102
- checkLatest: () => checkLatest(promise)
2312
+ checkLatest: () => this.checkLatest(promise)
2103
2313
  });
2104
2314
  } catch (err) {
2105
2315
  // swallow this error, since we'll display the
@@ -2107,12 +2317,12 @@
2107
2317
  }
2108
2318
 
2109
2319
  // Only apply the latest transition
2110
- if (latestPromise = checkLatest(promise)) {
2320
+ if (latestPromise = this.checkLatest(promise)) {
2111
2321
  return latestPromise;
2112
2322
  }
2113
- const exitingMatchIds = previousMatches.filter(id => !pendingMatchesRef.current.includes(id));
2114
- const enteringMatchIds = pendingMatchesRef.current.filter(id => !previousMatches.includes(id));
2115
- const stayingMatchIds = previousMatches.filter(id => pendingMatchesRef.current.includes(id))
2323
+ const exitingMatchIds = previousMatches.filter(id => !this.pendingMatches.includes(id));
2324
+ const enteringMatchIds = this.pendingMatches.filter(id => !previousMatches.includes(id));
2325
+ const stayingMatchIds = previousMatches.filter(id => this.pendingMatches.includes(id))
2116
2326
 
2117
2327
  // setState((s) => ({
2118
2328
  // ...s,
@@ -2124,10 +2334,10 @@
2124
2334
  ;
2125
2335
  [[exitingMatchIds, 'onLeave'], [enteringMatchIds, 'onEnter'], [stayingMatchIds, 'onTransition']].forEach(([matches, hook]) => {
2126
2336
  matches.forEach(match => {
2127
- looseRoutesById[match.routeId].options[hook]?.(match);
2337
+ this.looseRoutesById[match.routeId].options[hook]?.(match);
2128
2338
  });
2129
2339
  });
2130
- router.emit({
2340
+ this.emit({
2131
2341
  type: 'onLoad',
2132
2342
  fromLocation: prevLocation,
2133
2343
  toLocation: next,
@@ -2136,28 +2346,28 @@
2136
2346
  resolve();
2137
2347
  } catch (err) {
2138
2348
  // Only apply the latest transition
2139
- if (latestPromise = checkLatest(promise)) {
2349
+ if (latestPromise = this.checkLatest(promise)) {
2140
2350
  return latestPromise;
2141
2351
  }
2142
2352
  reject(err);
2143
2353
  }
2144
2354
  });
2145
- latestLoadPromiseRef.current = promise;
2146
- return latestLoadPromiseRef.current;
2147
- });
2148
- const preloadRoute = useStableCallback(async (navigateOpts = state.location) => {
2149
- let next = buildLocation(navigateOpts);
2150
- let matches = matchRoutes(next.pathname, next.search, {
2355
+ this.latestLoadPromise = promise;
2356
+ return this.latestLoadPromise;
2357
+ };
2358
+ preloadRoute = async (navigateOpts = this.state.location) => {
2359
+ let next = this.buildLocation(navigateOpts);
2360
+ let matches = this.matchRoutes(next.pathname, next.search, {
2151
2361
  throwOnError: true
2152
2362
  });
2153
- await loadMatches({
2363
+ await this.loadMatches({
2154
2364
  matches,
2155
2365
  preload: true,
2156
2366
  checkLatest: () => undefined
2157
2367
  });
2158
2368
  return [last(matches), matches];
2159
- });
2160
- const buildLink = useStableCallback(dest => {
2369
+ };
2370
+ buildLink = dest => {
2161
2371
  // If this link simply reloads the current route,
2162
2372
  // make sure it has a new key so it will trigger a data refresh
2163
2373
 
@@ -2183,18 +2393,18 @@
2183
2393
  };
2184
2394
  } catch (e) {}
2185
2395
  const nextOpts = dest;
2186
- const next = buildLocation(nextOpts);
2187
- const preload = userPreload ?? options.defaultPreload;
2188
- const preloadDelay = userPreloadDelay ?? options.defaultPreloadDelay ?? 0;
2396
+ const next = this.buildLocation(nextOpts);
2397
+ const preload = userPreload ?? this.options.defaultPreload;
2398
+ const preloadDelay = userPreloadDelay ?? this.options.defaultPreloadDelay ?? 0;
2189
2399
 
2190
2400
  // Compare path/hash for matches
2191
- const currentPathSplit = latestLocationRef.current.pathname.split('/');
2401
+ const currentPathSplit = this.latestLocation.pathname.split('/');
2192
2402
  const nextPathSplit = next.pathname.split('/');
2193
2403
  const pathIsFuzzyEqual = nextPathSplit.every((d, i) => d === currentPathSplit[i]);
2194
- // Combine the matches based on user options
2195
- const pathTest = activeOptions?.exact ? latestLocationRef.current.pathname === next.pathname : pathIsFuzzyEqual;
2196
- const hashTest = activeOptions?.includeHash ? latestLocationRef.current.hash === next.hash : true;
2197
- const searchTest = activeOptions?.includeSearch ?? true ? deepEqual(latestLocationRef.current.search, next.search, true) : true;
2404
+ // Combine the matches based on user this.options
2405
+ const pathTest = activeOptions?.exact ? this.latestLocation.pathname === next.pathname : pathIsFuzzyEqual;
2406
+ const hashTest = activeOptions?.includeHash ? this.latestLocation.hash === next.hash : true;
2407
+ const searchTest = activeOptions?.includeSearch ?? true ? deepEqual(this.latestLocation.search, next.search, true) : true;
2198
2408
 
2199
2409
  // The final "active" test
2200
2410
  const isActive = pathTest && hashTest && searchTest;
@@ -2205,7 +2415,7 @@
2205
2415
  e.preventDefault();
2206
2416
 
2207
2417
  // All is well? Navigate!
2208
- commitLocation({
2418
+ this.commitLocation({
2209
2419
  ...next,
2210
2420
  replace,
2211
2421
  resetScroll,
@@ -2217,384 +2427,184 @@
2217
2427
  // The click handler
2218
2428
  const handleFocus = e => {
2219
2429
  if (preload) {
2220
- preloadRoute(nextOpts).catch(err => {
2430
+ this.preloadRoute(nextOpts).catch(err => {
2221
2431
  console.warn(err);
2222
2432
  console.warn(preloadWarning);
2223
2433
  });
2224
2434
  }
2225
2435
  };
2226
2436
  const handleTouchStart = e => {
2227
- preloadRoute(nextOpts).catch(err => {
2437
+ this.preloadRoute(nextOpts).catch(err => {
2228
2438
  console.warn(err);
2229
2439
  console.warn(preloadWarning);
2230
2440
  });
2231
2441
  };
2232
- const handleEnter = e => {
2233
- const target = e.target || {};
2234
- if (preload) {
2235
- if (target.preloadTimeout) {
2236
- return;
2237
- }
2238
- target.preloadTimeout = setTimeout(() => {
2239
- target.preloadTimeout = null;
2240
- preloadRoute(nextOpts).catch(err => {
2241
- console.warn(err);
2242
- console.warn(preloadWarning);
2243
- });
2244
- }, preloadDelay);
2245
- }
2246
- };
2247
- const handleLeave = e => {
2248
- const target = e.target || {};
2249
- if (target.preloadTimeout) {
2250
- clearTimeout(target.preloadTimeout);
2251
- target.preloadTimeout = null;
2252
- }
2253
- };
2254
- return {
2255
- type: 'internal',
2256
- next,
2257
- handleFocus,
2258
- handleClick,
2259
- handleEnter,
2260
- handleLeave,
2261
- handleTouchStart,
2262
- isActive,
2263
- disabled
2264
- };
2265
- });
2266
- React__namespace.useLayoutEffect(() => {
2267
- const unsub = history.subscribe(() => {
2268
- latestLocationRef.current = parseLocation(latestLocationRef.current);
2269
- if (state.location !== latestLocationRef.current) {
2270
- startReactTransition(() => {
2271
- try {
2272
- load();
2273
- } catch (err) {
2274
- console.error(err);
2275
- }
2276
- });
2277
- }
2278
- });
2279
- const nextLocation = buildLocation({
2280
- search: true,
2281
- params: true,
2282
- hash: true,
2283
- state: true
2284
- });
2285
- if (state.location.href !== nextLocation.href) {
2286
- commitLocation({
2287
- ...nextLocation,
2288
- replace: true
2289
- });
2290
- }
2291
- return () => {
2292
- unsub();
2293
- };
2294
- }, [history]);
2295
- const matchRoute = useStableCallback((location, opts) => {
2296
- location = {
2297
- ...location,
2298
- to: location.to ? resolvePathWithBase(location.from || '', location.to) : undefined
2299
- };
2300
- const next = buildLocation(location);
2301
- if (opts?.pending && state.status !== 'pending') {
2302
- return false;
2303
- }
2304
- const baseLocation = opts?.pending ? latestLocationRef.current : state.resolvedLocation;
2305
-
2306
- // const baseLocation = state.resolvedLocation
2307
-
2308
- if (!baseLocation) {
2309
- return false;
2310
- }
2311
- const match = matchPathname(basepath, baseLocation.pathname, {
2312
- ...opts,
2313
- to: next.pathname
2314
- });
2315
- if (!match) {
2316
- return false;
2317
- }
2318
- if (match && (opts?.includeSearch ?? true)) {
2319
- return deepEqual(baseLocation.search, next.search, true) ? match : false;
2320
- }
2321
- return match;
2322
- });
2323
- const injectedHtmlRef = React__namespace.useRef([]);
2324
- const injectHtml = useStableCallback(async html => {
2325
- injectedHtmlRef.current.push(html);
2326
- });
2327
- const dehydrateData = useStableCallback((key, getData) => {
2328
- if (typeof document === 'undefined') {
2329
- const strKey = typeof key === 'string' ? key : JSON.stringify(key);
2330
- injectHtml(async () => {
2331
- const id = `__TSR_DEHYDRATED__${strKey}`;
2332
- const data = typeof getData === 'function' ? await getData() : getData;
2333
- return `<script id='${id}' suppressHydrationWarning>window["__TSR_DEHYDRATED__${escapeJSON(strKey)}"] = ${JSON.stringify(data)}
2334
- ;(() => {
2335
- var el = document.getElementById('${id}')
2336
- el.parentElement.removeChild(el)
2337
- })()
2338
- </script>`;
2339
- });
2340
- return () => hydrateData(key);
2341
- }
2342
- return () => undefined;
2343
- });
2344
- const hydrateData = useStableCallback(key => {
2345
- if (typeof document !== 'undefined') {
2346
- const strKey = typeof key === 'string' ? key : JSON.stringify(key);
2347
- return window[`__TSR_DEHYDRATED__${strKey}`];
2348
- }
2349
- return undefined;
2350
- });
2351
- React__namespace.useLayoutEffect(() => {
2352
- startReactTransition(() => {
2353
- try {
2354
- load();
2355
- } catch (err) {
2356
- console.error(err);
2357
- }
2358
- });
2359
- }, []);
2360
- const routerContextValue = {
2361
- routeTree: router.routeTree,
2362
- navigate,
2363
- buildLink,
2364
- state,
2365
- matchRoute,
2366
- routesById,
2367
- options,
2368
- history,
2369
- load,
2370
- buildLocation,
2371
- subscribe: router.subscribe,
2372
- resetNextScrollRef,
2373
- injectedHtmlRef,
2374
- injectHtml,
2375
- dehydrateData,
2376
- hydrateData
2377
- };
2378
- return /*#__PURE__*/React__namespace.createElement(routerContext.Provider, {
2379
- value: routerContextValue
2380
- }, /*#__PURE__*/React__namespace.createElement(Matches, null));
2381
- }
2382
- function getRouteMatch(state, id) {
2383
- return [...state.pendingMatches, ...state.matches].find(d => d.id === id);
2384
- }
2385
- function useRouterState(opts) {
2386
- const {
2387
- state
2388
- } = useRouter();
2389
- // return useStore(router.__store, opts?.select as any)
2390
- return opts?.select ? opts.select(state) : state;
2391
- }
2392
- function useRouter() {
2393
- const resolvedContext = window.__TSR_ROUTER_CONTEXT__ || routerContext;
2394
- const value = React__namespace.useContext(resolvedContext);
2395
- warning(value, 'useRouter must be used inside a <RouterProvider> component!');
2396
- return value;
2397
- }
2398
-
2399
- function defer(_promise) {
2400
- const promise = _promise;
2401
- if (!promise.__deferredState) {
2402
- promise.__deferredState = {
2403
- uid: Math.random().toString(36).slice(2),
2404
- status: 'pending'
2405
- };
2406
- const state = promise.__deferredState;
2407
- promise.then(data => {
2408
- state.status = 'success';
2409
- state.data = data;
2410
- }).catch(error => {
2411
- state.status = 'error';
2412
- state.error = error;
2413
- });
2414
- }
2415
- return promise;
2416
- }
2417
- function isDehydratedDeferred(obj) {
2418
- return typeof obj === 'object' && obj !== null && !(obj instanceof Promise) && !obj.then && '__deferredState' in obj;
2419
- }
2420
-
2421
- function useAwaited({
2422
- promise
2423
- }) {
2424
- const router = useRouter();
2425
- let state = promise.__deferredState;
2426
- const key = `__TSR__DEFERRED__${state.uid}`;
2427
- if (isDehydratedDeferred(promise)) {
2428
- state = router.hydrateData(key);
2429
- promise = Promise.resolve(state.data);
2430
- promise.__deferredState = state;
2431
- }
2432
- if (state.status === 'pending') {
2433
- throw promise;
2434
- }
2435
- if (state.status === 'error') {
2436
- throw state.error;
2437
- }
2438
- router.dehydrateData(key, state);
2439
- return [state.data];
2440
- }
2441
- function Await(props) {
2442
- const awaited = useAwaited(props);
2443
- return props.children(...awaited);
2444
- }
2445
-
2446
- class FileRoute {
2447
- constructor(path) {
2448
- this.path = path;
2449
- }
2450
- createRoute = options => {
2451
- const route = new Route(options);
2452
- route.isRoot = false;
2453
- return route;
2454
- };
2455
- }
2456
-
2457
- function lazyRouteComponent(importer, exportName) {
2458
- let loadPromise;
2459
- const load = () => {
2460
- if (!loadPromise) {
2461
- loadPromise = importer();
2462
- }
2463
- return loadPromise;
2464
- };
2465
- const lazyComp = /*#__PURE__*/React__namespace.lazy(async () => {
2466
- const moduleExports = await load();
2467
- const comp = moduleExports[exportName ?? 'default'];
2468
- return {
2469
- default: comp
2470
- };
2471
- });
2472
- lazyComp.preload = load;
2473
- return lazyComp;
2474
- }
2475
-
2476
- function _extends() {
2477
- _extends = Object.assign ? Object.assign.bind() : function (target) {
2478
- for (var i = 1; i < arguments.length; i++) {
2479
- var source = arguments[i];
2480
- for (var key in source) {
2481
- if (Object.prototype.hasOwnProperty.call(source, key)) {
2482
- target[key] = source[key];
2442
+ const handleEnter = e => {
2443
+ const target = e.target || {};
2444
+ if (preload) {
2445
+ if (target.preloadTimeout) {
2446
+ return;
2483
2447
  }
2448
+ target.preloadTimeout = setTimeout(() => {
2449
+ target.preloadTimeout = null;
2450
+ this.preloadRoute(nextOpts).catch(err => {
2451
+ console.warn(err);
2452
+ console.warn(preloadWarning);
2453
+ });
2454
+ }, preloadDelay);
2484
2455
  }
2485
- }
2486
- return target;
2487
- };
2488
- return _extends.apply(this, arguments);
2489
- }
2490
-
2491
- function useLinkProps(options) {
2492
- const {
2493
- buildLink
2494
- } = useRouter();
2495
- const match = useMatch({
2496
- strict: false
2497
- });
2498
- const {
2499
- // custom props
2500
- type,
2501
- children,
2502
- target,
2503
- activeProps = () => ({
2504
- className: 'active'
2505
- }),
2506
- inactiveProps = () => ({}),
2507
- activeOptions,
2508
- disabled,
2509
- hash,
2510
- search,
2511
- params,
2512
- to,
2513
- state,
2514
- mask,
2515
- preload,
2516
- preloadDelay,
2517
- replace,
2518
- startTransition,
2519
- resetScroll,
2520
- // element props
2521
- style,
2522
- className,
2523
- onClick,
2524
- onFocus,
2525
- onMouseEnter,
2526
- onMouseLeave,
2527
- onTouchStart,
2528
- ...rest
2529
- } = options;
2530
- const linkInfo = buildLink({
2531
- from: options.to ? match.pathname : undefined,
2532
- ...options
2533
- });
2534
- if (linkInfo.type === 'external') {
2535
- const {
2536
- href
2537
- } = linkInfo;
2456
+ };
2457
+ const handleLeave = e => {
2458
+ const target = e.target || {};
2459
+ if (target.preloadTimeout) {
2460
+ clearTimeout(target.preloadTimeout);
2461
+ target.preloadTimeout = null;
2462
+ }
2463
+ };
2538
2464
  return {
2539
- href
2465
+ type: 'internal',
2466
+ next,
2467
+ handleFocus,
2468
+ handleClick,
2469
+ handleEnter,
2470
+ handleLeave,
2471
+ handleTouchStart,
2472
+ isActive,
2473
+ disabled
2540
2474
  };
2541
- }
2542
- const {
2543
- handleClick,
2544
- handleFocus,
2545
- handleEnter,
2546
- handleLeave,
2547
- handleTouchStart,
2548
- isActive,
2549
- next
2550
- } = linkInfo;
2551
- const composeHandlers = handlers => e => {
2552
- if (e.persist) e.persist();
2553
- handlers.filter(Boolean).forEach(handler => {
2554
- if (e.defaultPrevented) return;
2555
- handler(e);
2475
+ };
2476
+ matchRoute = (location, opts) => {
2477
+ location = {
2478
+ ...location,
2479
+ to: location.to ? this.resolvePathWithBase(location.from || '', location.to) : undefined
2480
+ };
2481
+ const next = this.buildLocation(location);
2482
+ if (opts?.pending && this.state.status !== 'pending') {
2483
+ return false;
2484
+ }
2485
+ const baseLocation = opts?.pending ? this.latestLocation : this.state.resolvedLocation;
2486
+
2487
+ // const baseLocation = state.resolvedLocation
2488
+
2489
+ if (!baseLocation) {
2490
+ return false;
2491
+ }
2492
+ const match = matchPathname(this.basepath, baseLocation.pathname, {
2493
+ ...opts,
2494
+ to: next.pathname
2556
2495
  });
2496
+ if (!match) {
2497
+ return false;
2498
+ }
2499
+ if (match && (opts?.includeSearch ?? true)) {
2500
+ return deepEqual(baseLocation.search, next.search, true) ? match : false;
2501
+ }
2502
+ return match;
2503
+ };
2504
+ injectHtml = async html => {
2505
+ this.injectedHtml.push(html);
2506
+ };
2507
+ dehydrateData = (key, getData) => {
2508
+ if (typeof document === 'undefined') {
2509
+ const strKey = typeof key === 'string' ? key : JSON.stringify(key);
2510
+ this.injectHtml(async () => {
2511
+ const id = `__TSR_DEHYDRATED__${strKey}`;
2512
+ const data = typeof getData === 'function' ? await getData() : getData;
2513
+ return `<script id='${id}' suppressHydrationWarning>window["__TSR_DEHYDRATED__${escapeJSON(strKey)}"] = ${JSON.stringify(data)}
2514
+ ;(() => {
2515
+ var el = document.getElementById('${id}')
2516
+ el.parentElement.removeChild(el)
2517
+ })()
2518
+ </script>`;
2519
+ });
2520
+ return () => this.hydrateData(key);
2521
+ }
2522
+ return () => undefined;
2523
+ };
2524
+ hydrateData = key => {
2525
+ if (typeof document !== 'undefined') {
2526
+ const strKey = typeof key === 'string' ? key : JSON.stringify(key);
2527
+ return window[`__TSR_DEHYDRATED__${strKey}`];
2528
+ }
2529
+ return undefined;
2557
2530
  };
2558
2531
 
2559
- // Get the active props
2560
- const resolvedActiveProps = isActive ? functionalUpdate(activeProps, {}) ?? {} : {};
2532
+ // dehydrate = (): DehydratedRouter => {
2533
+ // return {
2534
+ // state: {
2535
+ // dehydratedMatches: this.state.matches.map((d) =>
2536
+ // pick(d, ['fetchedAt', 'invalid', 'id', 'status', 'updatedAt']),
2537
+ // ),
2538
+ // },
2539
+ // }
2540
+ // }
2561
2541
 
2562
- // Get the inactive props
2563
- const resolvedInactiveProps = isActive ? {} : functionalUpdate(inactiveProps, {}) ?? {};
2564
- return {
2565
- ...resolvedActiveProps,
2566
- ...resolvedInactiveProps,
2567
- ...rest,
2568
- href: disabled ? undefined : next.maskedLocation ? next.maskedLocation.href : next.href,
2569
- onClick: composeHandlers([onClick, handleClick]),
2570
- onFocus: composeHandlers([onFocus, handleFocus]),
2571
- onMouseEnter: composeHandlers([onMouseEnter, handleEnter]),
2572
- onMouseLeave: composeHandlers([onMouseLeave, handleLeave]),
2573
- onTouchStart: composeHandlers([onTouchStart, handleTouchStart]),
2574
- target,
2575
- style: {
2576
- ...style,
2577
- ...resolvedActiveProps.style,
2578
- ...resolvedInactiveProps.style
2579
- },
2580
- className: [className, resolvedActiveProps.className, resolvedInactiveProps.className].filter(Boolean).join(' ') || undefined,
2581
- ...(disabled ? {
2582
- role: 'link',
2583
- 'aria-disabled': true
2584
- } : undefined),
2585
- ['data-status']: isActive ? 'active' : undefined
2542
+ // hydrate = async (__do_not_use_server_ctx?: HydrationCtx) => {
2543
+ // let _ctx = __do_not_use_server_ctx
2544
+ // // Client hydrates from window
2545
+ // if (typeof document !== 'undefined') {
2546
+ // _ctx = window.__TSR_DEHYDRATED__
2547
+ // }
2548
+
2549
+ // invariant(
2550
+ // _ctx,
2551
+ // 'Expected to find a __TSR_DEHYDRATED__ property on window... but we did not. Did you forget to render <DehydrateRouter /> in your app?',
2552
+ // )
2553
+
2554
+ // const ctx = _ctx
2555
+ // this.dehydratedData = ctx.payload as any
2556
+ // this.options.hydrate?.(ctx.payload as any)
2557
+ // const dehydratedState = ctx.router.state
2558
+
2559
+ // let matches = this.matchRoutes(
2560
+ // this.state.location.pathname,
2561
+ // this.state.location.search,
2562
+ // ).map((match) => {
2563
+ // const dehydratedMatch = dehydratedState.dehydratedMatches.find(
2564
+ // (d) => d.id === match.id,
2565
+ // )
2566
+
2567
+ // invariant(
2568
+ // dehydratedMatch,
2569
+ // `Could not find a client-side match for dehydrated match with id: ${match.id}!`,
2570
+ // )
2571
+
2572
+ // if (dehydratedMatch) {
2573
+ // return {
2574
+ // ...match,
2575
+ // ...dehydratedMatch,
2576
+ // }
2577
+ // }
2578
+ // return match
2579
+ // })
2580
+
2581
+ // this.setState((s) => {
2582
+ // return {
2583
+ // ...s,
2584
+ // matches: dehydratedState.dehydratedMatches as any,
2585
+ // }
2586
+ // })
2587
+ // }
2588
+
2589
+ // resolveMatchPromise = (matchId: string, key: string, value: any) => {
2590
+ // state.matches
2591
+ // .find((d) => d.id === matchId)
2592
+ // ?.__promisesByKey[key]?.resolve(value)
2593
+ // }
2594
+ }
2595
+
2596
+ // A function that takes an import() argument which is a function and returns a new function that will
2597
+ // proxy arguments from the caller to the imported function, retaining all type
2598
+ // information along the way
2599
+ function lazyFn(fn, key) {
2600
+ return async (...args) => {
2601
+ const imported = await fn();
2602
+ return imported[key || 'default'](...args);
2586
2603
  };
2587
2604
  }
2588
- const Link = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
2589
- const linkProps = useLinkProps(props);
2590
- return /*#__PURE__*/React__namespace.createElement("a", _extends({
2591
- ref: ref
2592
- }, linkProps, {
2593
- children: typeof props.children === 'function' ? props.children({
2594
- isActive: linkProps['data-status'] === 'active'
2595
- }) : props.children
2596
- }));
2597
- });
2605
+ function isCtrlEvent(e) {
2606
+ return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
2607
+ }
2598
2608
 
2599
2609
  const useLayoutEffect = typeof window !== 'undefined' ? React__namespace.useLayoutEffect : React__namespace.useEffect;
2600
2610
  const windowKey = 'window';
@@ -2604,11 +2614,7 @@
2604
2614
  const sessionsStorage = typeof window !== 'undefined' && window.sessionStorage;
2605
2615
  const defaultGetKey = location => location.state.key;
2606
2616
  function useScrollRestoration(options) {
2607
- const {
2608
- state,
2609
- subscribe,
2610
- resetNextScrollRef
2611
- } = useRouter();
2617
+ const router = useRouter();
2612
2618
  useLayoutEffect(() => {
2613
2619
  const getKey = options?.getKey || defaultGetKey;
2614
2620
  if (sessionsStorage) {
@@ -2664,7 +2670,7 @@
2664
2670
  if (typeof document !== 'undefined') {
2665
2671
  document.addEventListener('scroll', onScroll, true);
2666
2672
  }
2667
- const unsubOnBeforeLoad = subscribe('onBeforeLoad', event => {
2673
+ const unsubOnBeforeLoad = router.subscribe('onBeforeLoad', event => {
2668
2674
  if (event.pathChanged) {
2669
2675
  const restoreKey = getKey(event.fromLocation);
2670
2676
  for (const elementSelector in cache.state.next) {
@@ -2694,12 +2700,12 @@
2694
2700
  }
2695
2701
  }
2696
2702
  });
2697
- const unsubOnResolved = subscribe('onResolved', event => {
2703
+ const unsubOnResolved = router.subscribe('onResolved', event => {
2698
2704
  if (event.pathChanged) {
2699
- if (!resetNextScrollRef.current) {
2705
+ if (!router.resetNextScroll) {
2700
2706
  return;
2701
2707
  }
2702
- resetNextScrollRef.current = true;
2708
+ router.resetNextScroll = true;
2703
2709
  const getKey = options?.getKey || defaultGetKey;
2704
2710
  const restoreKey = getKey(event.toLocation);
2705
2711
  let windowRestored = false;