@tanstack/react-router 0.0.1-beta.223 → 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,8 +1810,8 @@
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);
1608
- const cause = state.matches.find(d => d.id === matchId) ? 'stay' : 'enter';
1813
+ const existingMatch = getRouteMatch(this.state, matchId);
1814
+ const cause = this.state.matches.find(d => d.id === matchId) ? 'stay' : 'enter';
1609
1815
  if (existingMatch) {
1610
1816
  return {
1611
1817
  ...existingMatch,
@@ -1619,7 +1825,7 @@
1619
1825
  id: matchId,
1620
1826
  routeId: route.id,
1621
1827
  params: routeParams,
1622
- pathname: joinPaths([basepath, interpolatedPath]),
1828
+ pathname: joinPaths([this.basepath, interpolatedPath]),
1623
1829
  updatedAt: Date.now(),
1624
1830
  routeSearch: {},
1625
1831
  search: {},
@@ -1644,7 +1850,7 @@
1644
1850
  // so that we can use the parent match's search params and context
1645
1851
  matches.forEach((match, i) => {
1646
1852
  const parentMatch = matches[i - 1];
1647
- const route = looseRoutesById[match.routeId];
1853
+ const route = this.looseRoutesById[match.routeId];
1648
1854
  const searchInfo = (() => {
1649
1855
  // Validate the search params and stabilize them
1650
1856
  const parentSearchInfo = {
@@ -1678,28 +1884,28 @@
1678
1884
  Object.assign(match, searchInfo);
1679
1885
  });
1680
1886
  return matches;
1681
- });
1682
- const cancelMatch = useStableCallback(id => {
1683
- getRouteMatch(state, id)?.abortController?.abort();
1684
- });
1685
- const cancelMatches = useStableCallback(state => {
1686
- state.matches.forEach(match => {
1687
- 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);
1688
1894
  });
1689
- });
1690
- const buildLocation = useStableCallback(opts => {
1895
+ };
1896
+ buildLocation = opts => {
1691
1897
  const build = (dest = {}, matches) => {
1692
- const from = latestLocationRef.current;
1898
+ const from = this.latestLocation;
1693
1899
  const fromPathname = dest.from ?? from.pathname;
1694
- let pathname = resolvePathWithBase(fromPathname, `${dest.to ?? ''}`);
1695
- const fromMatches = matchRoutes(fromPathname, from.search);
1900
+ let pathname = this.resolvePathWithBase(fromPathname, `${dest.to ?? ''}`);
1901
+ const fromMatches = this.matchRoutes(fromPathname, from.search);
1696
1902
  const stayingMatches = matches?.filter(d => fromMatches?.find(e => e.routeId === d.routeId));
1697
1903
  const prevParams = {
1698
1904
  ...last(fromMatches)?.params
1699
1905
  };
1700
1906
  let nextParams = (dest.params ?? true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
1701
1907
  if (nextParams) {
1702
- 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 => {
1703
1909
  nextParams = {
1704
1910
  ...nextParams,
1705
1911
  ...fn(nextParams)
@@ -1707,8 +1913,8 @@
1707
1913
  });
1708
1914
  }
1709
1915
  pathname = interpolatePath(pathname, nextParams ?? {});
1710
- const preSearchFilters = stayingMatches?.map(match => looseRoutesById[match.routeId].options.preSearchFilters ?? []).flat().filter(Boolean) ?? [];
1711
- 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) ?? [];
1712
1918
 
1713
1919
  // Pre filters first
1714
1920
  const preFilteredSearch = preSearchFilters?.length ? preSearchFilters?.reduce((prev, next) => next(prev), from.search) : from.search;
@@ -1722,7 +1928,7 @@
1722
1928
  // Then post filters
1723
1929
  const postFilteredSearch = postSearchFilters?.length ? postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
1724
1930
  const search = replaceEqualDeep(from.search, postFilteredSearch);
1725
- const searchStr = options.stringifySearch(search);
1931
+ const searchStr = this.options.stringifySearch(search);
1726
1932
  const hash = dest.hash === true ? from.hash : dest.hash ? functionalUpdate(dest.hash, from.hash) : from.hash;
1727
1933
  const hashStr = hash ? `#${hash}` : '';
1728
1934
  let nextState = dest.state === true ? from.state : dest.state ? functionalUpdate(dest.state, from.state) : from.state;
@@ -1733,7 +1939,7 @@
1733
1939
  searchStr,
1734
1940
  state: nextState,
1735
1941
  hash,
1736
- href: history.createHref(`${pathname}${searchStr}${hashStr}`),
1942
+ href: this.history.createHref(`${pathname}${searchStr}${hashStr}`),
1737
1943
  unmaskOnReload: dest.unmaskOnReload
1738
1944
  };
1739
1945
  };
@@ -1742,8 +1948,8 @@
1742
1948
  let maskedNext = maskedDest ? build(maskedDest) : undefined;
1743
1949
  if (!maskedNext) {
1744
1950
  let params = {};
1745
- let foundMask = options.routeMasks?.find(d => {
1746
- const match = matchPathname(basepath, next.pathname, {
1951
+ let foundMask = this.options.routeMasks?.find(d => {
1952
+ const match = matchPathname(this.basepath, next.pathname, {
1747
1953
  to: d.from,
1748
1954
  caseSensitive: false,
1749
1955
  fuzzy: false
@@ -1763,8 +1969,8 @@
1763
1969
  maskedNext = build(maskedDest);
1764
1970
  }
1765
1971
  }
1766
- const nextMatches = matchRoutes(next.pathname, next.search);
1767
- 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;
1768
1974
  const maskedFinal = maskedNext ? build(maskedDest, maskedMatches) : undefined;
1769
1975
  const final = build(dest, nextMatches);
1770
1976
  if (maskedFinal) {
@@ -1779,13 +1985,13 @@
1779
1985
  });
1780
1986
  }
1781
1987
  return buildWithMatches(opts);
1782
- });
1783
- const commitLocation = useStableCallback(async ({
1988
+ };
1989
+ commitLocation = async ({
1784
1990
  startTransition,
1785
1991
  ...next
1786
1992
  }) => {
1787
- if (navigateTimeoutRef.current) clearTimeout(navigateTimeoutRef.current);
1788
- const isSameUrl = latestLocationRef.current.href === next.href;
1993
+ if (this.navigateTimeout) clearTimeout(this.navigateTimeout);
1994
+ const isSameUrl = this.latestLocation.href === next.href;
1789
1995
 
1790
1996
  // If the next urls are the same and we're not replacing,
1791
1997
  // do nothing
@@ -1812,37 +2018,37 @@
1812
2018
  }
1813
2019
  }
1814
2020
  };
1815
- if (nextHistory.unmaskOnReload ?? options.unmaskOnReload ?? false) {
1816
- nextHistory.state.__tempKey = tempLocationKeyRef.current;
2021
+ if (nextHistory.unmaskOnReload ?? this.options.unmaskOnReload ?? false) {
2022
+ nextHistory.state.__tempKey = this.tempLocationKey;
1817
2023
  }
1818
2024
  }
1819
2025
  const apply = () => {
1820
- history[next.replace ? 'replace' : 'push'](nextHistory.href, nextHistory.state);
2026
+ this.history[next.replace ? 'replace' : 'push'](nextHistory.href, nextHistory.state);
1821
2027
  };
1822
2028
  if (startTransition ?? true) {
1823
- startReactTransition(apply);
2029
+ this.startReactTransition(apply);
1824
2030
  } else {
1825
2031
  apply();
1826
2032
  }
1827
2033
  }
1828
- resetNextScrollRef.current = next.resetScroll ?? true;
1829
- return latestLoadPromiseRef.current;
1830
- });
1831
- const buildAndCommitLocation = useStableCallback(({
2034
+ this.resetNextScroll = next.resetScroll ?? true;
2035
+ return this.latestLoadPromise;
2036
+ };
2037
+ buildAndCommitLocation = ({
1832
2038
  replace,
1833
2039
  resetScroll,
1834
2040
  startTransition,
1835
2041
  ...rest
1836
2042
  } = {}) => {
1837
- const location = buildLocation(rest);
1838
- return commitLocation({
2043
+ const location = this.buildLocation(rest);
2044
+ return this.commitLocation({
1839
2045
  ...location,
1840
2046
  startTransition,
1841
2047
  replace,
1842
2048
  resetScroll
1843
2049
  });
1844
- });
1845
- const navigate = useStableCallback(({
2050
+ };
2051
+ navigate = ({
1846
2052
  from,
1847
2053
  to = '',
1848
2054
  ...rest
@@ -1860,13 +2066,13 @@
1860
2066
  isExternal = true;
1861
2067
  } catch (e) {}
1862
2068
  invariant(!isExternal, 'Attempting to navigate to external url with this.navigate!');
1863
- return buildAndCommitLocation({
2069
+ return this.buildAndCommitLocation({
1864
2070
  ...rest,
1865
2071
  from: fromString,
1866
2072
  to: toString
1867
2073
  });
1868
- });
1869
- const loadMatches = useStableCallback(async ({
2074
+ };
2075
+ loadMatches = async ({
1870
2076
  checkLatest,
1871
2077
  matches,
1872
2078
  preload
@@ -1878,7 +2084,7 @@
1878
2084
  try {
1879
2085
  for (let [index, match] of matches.entries()) {
1880
2086
  const parentMatch = matches[index - 1];
1881
- const route = looseRoutesById[match.routeId];
2087
+ const route = this.looseRoutesById[match.routeId];
1882
2088
  const handleError = (err, code) => {
1883
2089
  err.routerCode = code;
1884
2090
  firstBadMatchIndex = firstBadMatchIndex ?? index;
@@ -1907,19 +2113,20 @@
1907
2113
  if (match.searchError) {
1908
2114
  handleError(match.searchError, 'VALIDATE_SEARCH');
1909
2115
  }
1910
- const parentContext = parentMatch?.context ?? options.context ?? {};
2116
+ const parentContext = parentMatch?.context ?? this.options.context ?? {};
1911
2117
  const beforeLoadContext = (await route.options.beforeLoad?.({
1912
2118
  search: match.search,
1913
2119
  abortController: match.abortController,
1914
2120
  params: match.params,
1915
2121
  preload: !!preload,
1916
2122
  context: parentContext,
1917
- location: state.location,
1918
- navigate: opts => navigate({
2123
+ location: this.state.location,
2124
+ // TOOD: just expose state and router, etc
2125
+ navigate: opts => this.navigate({
1919
2126
  ...opts,
1920
2127
  from: match.pathname
1921
2128
  }),
1922
- buildLocation,
2129
+ buildLocation: this.buildLocation,
1923
2130
  cause: match.cause
1924
2131
  })) ?? {};
1925
2132
  const context = {
@@ -1937,7 +2144,7 @@
1937
2144
  }
1938
2145
  } catch (err) {
1939
2146
  if (isRedirect(err)) {
1940
- if (!preload) navigate(err);
2147
+ if (!preload) this.navigate(err);
1941
2148
  return matches;
1942
2149
  }
1943
2150
  throw err;
@@ -1947,11 +2154,11 @@
1947
2154
  validResolvedMatches.forEach((match, index) => {
1948
2155
  matchPromises.push((async () => {
1949
2156
  const parentMatchPromise = matchPromises[index - 1];
1950
- const route = looseRoutesById[match.routeId];
2157
+ const route = this.looseRoutesById[match.routeId];
1951
2158
  const handleIfRedirect = err => {
1952
2159
  if (isRedirect(err)) {
1953
2160
  if (!preload) {
1954
- navigate(err);
2161
+ this.navigate(err);
1955
2162
  }
1956
2163
  return true;
1957
2164
  }
@@ -1964,7 +2171,7 @@
1964
2171
  invalid: false
1965
2172
  };
1966
2173
  if (match.isFetching) {
1967
- loadPromise = getRouteMatch(state, match.id)?.loadPromise;
2174
+ loadPromise = getRouteMatch(this.state, match.id)?.loadPromise;
1968
2175
  } else {
1969
2176
  const loaderContext = {
1970
2177
  params: match.params,
@@ -1973,8 +2180,8 @@
1973
2180
  parentMatchPromise,
1974
2181
  abortController: match.abortController,
1975
2182
  context: match.context,
1976
- location: state.location,
1977
- navigate: opts => navigate({
2183
+ location: this.state.location,
2184
+ navigate: opts => this.navigate({
1978
2185
  ...opts,
1979
2186
  from: match.pathname
1980
2187
  }),
@@ -2022,7 +2229,7 @@
2022
2229
  loadPromise
2023
2230
  };
2024
2231
  if (!preload) {
2025
- setState(s => ({
2232
+ this.setState(s => ({
2026
2233
  ...s,
2027
2234
  matches: s.matches.map(d => d.id === match.id ? match : d)
2028
2235
  }));
@@ -2057,7 +2264,7 @@
2057
2264
  };
2058
2265
  }
2059
2266
  if (!preload) {
2060
- setState(s => ({
2267
+ this.setState(s => ({
2061
2268
  ...s,
2062
2269
  matches: s.matches.map(d => d.id === match.id ? match : d)
2063
2270
  }));
@@ -2066,17 +2273,17 @@
2066
2273
  });
2067
2274
  await Promise.all(matchPromises);
2068
2275
  return matches;
2069
- });
2070
- const load = useStableCallback(async () => {
2276
+ };
2277
+ load = async () => {
2071
2278
  const promise = new Promise(async (resolve, reject) => {
2072
- const next = latestLocationRef.current;
2073
- const prevLocation = state.resolvedLocation;
2279
+ const next = this.latestLocation;
2280
+ const prevLocation = this.state.resolvedLocation;
2074
2281
  const pathDidChange = prevLocation.href !== next.href;
2075
2282
  let latestPromise;
2076
2283
 
2077
2284
  // Cancel any pending matches
2078
- cancelMatches(state);
2079
- router.emit({
2285
+ this.cancelMatches();
2286
+ this.emit({
2080
2287
  type: 'onBeforeLoad',
2081
2288
  fromLocation: prevLocation,
2082
2289
  toLocation: next,
@@ -2084,14 +2291,14 @@
2084
2291
  });
2085
2292
 
2086
2293
  // Match the routes
2087
- let matches = matchRoutes(next.pathname, next.search, {
2294
+ let matches = this.matchRoutes(next.pathname, next.search, {
2088
2295
  debug: true
2089
2296
  });
2090
- pendingMatchesRef.current = matches;
2091
- const previousMatches = state.matches;
2297
+ this.pendingMatches = matches;
2298
+ const previousMatches = this.state.matches;
2092
2299
 
2093
2300
  // Ingest the new matches
2094
- setState(s => ({
2301
+ this.setState(s => ({
2095
2302
  ...s,
2096
2303
  status: 'pending',
2097
2304
  location: next,
@@ -2100,9 +2307,9 @@
2100
2307
  try {
2101
2308
  try {
2102
2309
  // Load the matches
2103
- await loadMatches({
2310
+ await this.loadMatches({
2104
2311
  matches,
2105
- checkLatest: () => checkLatest(promise)
2312
+ checkLatest: () => this.checkLatest(promise)
2106
2313
  });
2107
2314
  } catch (err) {
2108
2315
  // swallow this error, since we'll display the
@@ -2110,12 +2317,12 @@
2110
2317
  }
2111
2318
 
2112
2319
  // Only apply the latest transition
2113
- if (latestPromise = checkLatest(promise)) {
2320
+ if (latestPromise = this.checkLatest(promise)) {
2114
2321
  return latestPromise;
2115
2322
  }
2116
- const exitingMatchIds = previousMatches.filter(id => !pendingMatchesRef.current.includes(id));
2117
- const enteringMatchIds = pendingMatchesRef.current.filter(id => !previousMatches.includes(id));
2118
- 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))
2119
2326
 
2120
2327
  // setState((s) => ({
2121
2328
  // ...s,
@@ -2127,10 +2334,10 @@
2127
2334
  ;
2128
2335
  [[exitingMatchIds, 'onLeave'], [enteringMatchIds, 'onEnter'], [stayingMatchIds, 'onTransition']].forEach(([matches, hook]) => {
2129
2336
  matches.forEach(match => {
2130
- looseRoutesById[match.routeId].options[hook]?.(match);
2337
+ this.looseRoutesById[match.routeId].options[hook]?.(match);
2131
2338
  });
2132
2339
  });
2133
- router.emit({
2340
+ this.emit({
2134
2341
  type: 'onLoad',
2135
2342
  fromLocation: prevLocation,
2136
2343
  toLocation: next,
@@ -2139,28 +2346,28 @@
2139
2346
  resolve();
2140
2347
  } catch (err) {
2141
2348
  // Only apply the latest transition
2142
- if (latestPromise = checkLatest(promise)) {
2349
+ if (latestPromise = this.checkLatest(promise)) {
2143
2350
  return latestPromise;
2144
2351
  }
2145
2352
  reject(err);
2146
2353
  }
2147
2354
  });
2148
- latestLoadPromiseRef.current = promise;
2149
- return latestLoadPromiseRef.current;
2150
- });
2151
- const preloadRoute = useStableCallback(async (navigateOpts = state.location) => {
2152
- let next = buildLocation(navigateOpts);
2153
- 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, {
2154
2361
  throwOnError: true
2155
2362
  });
2156
- await loadMatches({
2363
+ await this.loadMatches({
2157
2364
  matches,
2158
2365
  preload: true,
2159
2366
  checkLatest: () => undefined
2160
2367
  });
2161
2368
  return [last(matches), matches];
2162
- });
2163
- const buildLink = useStableCallback(dest => {
2369
+ };
2370
+ buildLink = dest => {
2164
2371
  // If this link simply reloads the current route,
2165
2372
  // make sure it has a new key so it will trigger a data refresh
2166
2373
 
@@ -2186,18 +2393,18 @@
2186
2393
  };
2187
2394
  } catch (e) {}
2188
2395
  const nextOpts = dest;
2189
- const next = buildLocation(nextOpts);
2190
- const preload = userPreload ?? options.defaultPreload;
2191
- 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;
2192
2399
 
2193
2400
  // Compare path/hash for matches
2194
- const currentPathSplit = latestLocationRef.current.pathname.split('/');
2401
+ const currentPathSplit = this.latestLocation.pathname.split('/');
2195
2402
  const nextPathSplit = next.pathname.split('/');
2196
2403
  const pathIsFuzzyEqual = nextPathSplit.every((d, i) => d === currentPathSplit[i]);
2197
- // Combine the matches based on user options
2198
- const pathTest = activeOptions?.exact ? latestLocationRef.current.pathname === next.pathname : pathIsFuzzyEqual;
2199
- const hashTest = activeOptions?.includeHash ? latestLocationRef.current.hash === next.hash : true;
2200
- 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;
2201
2408
 
2202
2409
  // The final "active" test
2203
2410
  const isActive = pathTest && hashTest && searchTest;
@@ -2208,7 +2415,7 @@
2208
2415
  e.preventDefault();
2209
2416
 
2210
2417
  // All is well? Navigate!
2211
- commitLocation({
2418
+ this.commitLocation({
2212
2419
  ...next,
2213
2420
  replace,
2214
2421
  resetScroll,
@@ -2220,384 +2427,184 @@
2220
2427
  // The click handler
2221
2428
  const handleFocus = e => {
2222
2429
  if (preload) {
2223
- preloadRoute(nextOpts).catch(err => {
2430
+ this.preloadRoute(nextOpts).catch(err => {
2224
2431
  console.warn(err);
2225
2432
  console.warn(preloadWarning);
2226
2433
  });
2227
2434
  }
2228
2435
  };
2229
2436
  const handleTouchStart = e => {
2230
- preloadRoute(nextOpts).catch(err => {
2437
+ this.preloadRoute(nextOpts).catch(err => {
2231
2438
  console.warn(err);
2232
2439
  console.warn(preloadWarning);
2233
2440
  });
2234
2441
  };
2235
- const handleEnter = e => {
2236
- const target = e.target || {};
2237
- if (preload) {
2238
- if (target.preloadTimeout) {
2239
- return;
2240
- }
2241
- target.preloadTimeout = setTimeout(() => {
2242
- target.preloadTimeout = null;
2243
- preloadRoute(nextOpts).catch(err => {
2244
- console.warn(err);
2245
- console.warn(preloadWarning);
2246
- });
2247
- }, preloadDelay);
2248
- }
2249
- };
2250
- const handleLeave = e => {
2251
- const target = e.target || {};
2252
- if (target.preloadTimeout) {
2253
- clearTimeout(target.preloadTimeout);
2254
- target.preloadTimeout = null;
2255
- }
2256
- };
2257
- return {
2258
- type: 'internal',
2259
- next,
2260
- handleFocus,
2261
- handleClick,
2262
- handleEnter,
2263
- handleLeave,
2264
- handleTouchStart,
2265
- isActive,
2266
- disabled
2267
- };
2268
- });
2269
- React__namespace.useLayoutEffect(() => {
2270
- const unsub = history.subscribe(() => {
2271
- latestLocationRef.current = parseLocation(latestLocationRef.current);
2272
- if (state.location !== latestLocationRef.current) {
2273
- startReactTransition(() => {
2274
- try {
2275
- load();
2276
- } catch (err) {
2277
- console.error(err);
2278
- }
2279
- });
2280
- }
2281
- });
2282
- const nextLocation = buildLocation({
2283
- search: true,
2284
- params: true,
2285
- hash: true,
2286
- state: true
2287
- });
2288
- if (state.location.href !== nextLocation.href) {
2289
- commitLocation({
2290
- ...nextLocation,
2291
- replace: true
2292
- });
2293
- }
2294
- return () => {
2295
- unsub();
2296
- };
2297
- }, [history]);
2298
- const matchRoute = useStableCallback((location, opts) => {
2299
- location = {
2300
- ...location,
2301
- to: location.to ? resolvePathWithBase(location.from || '', location.to) : undefined
2302
- };
2303
- const next = buildLocation(location);
2304
- if (opts?.pending && state.status !== 'pending') {
2305
- return false;
2306
- }
2307
- const baseLocation = opts?.pending ? latestLocationRef.current : state.resolvedLocation;
2308
-
2309
- // const baseLocation = state.resolvedLocation
2310
-
2311
- if (!baseLocation) {
2312
- return false;
2313
- }
2314
- const match = matchPathname(basepath, baseLocation.pathname, {
2315
- ...opts,
2316
- to: next.pathname
2317
- });
2318
- if (!match) {
2319
- return false;
2320
- }
2321
- if (match && (opts?.includeSearch ?? true)) {
2322
- return deepEqual(baseLocation.search, next.search, true) ? match : false;
2323
- }
2324
- return match;
2325
- });
2326
- const injectedHtmlRef = React__namespace.useRef([]);
2327
- const injectHtml = useStableCallback(async html => {
2328
- injectedHtmlRef.current.push(html);
2329
- });
2330
- const dehydrateData = useStableCallback((key, getData) => {
2331
- if (typeof document === 'undefined') {
2332
- const strKey = typeof key === 'string' ? key : JSON.stringify(key);
2333
- injectHtml(async () => {
2334
- const id = `__TSR_DEHYDRATED__${strKey}`;
2335
- const data = typeof getData === 'function' ? await getData() : getData;
2336
- return `<script id='${id}' suppressHydrationWarning>window["__TSR_DEHYDRATED__${escapeJSON(strKey)}"] = ${JSON.stringify(data)}
2337
- ;(() => {
2338
- var el = document.getElementById('${id}')
2339
- el.parentElement.removeChild(el)
2340
- })()
2341
- </script>`;
2342
- });
2343
- return () => hydrateData(key);
2344
- }
2345
- return () => undefined;
2346
- });
2347
- const hydrateData = useStableCallback(key => {
2348
- if (typeof document !== 'undefined') {
2349
- const strKey = typeof key === 'string' ? key : JSON.stringify(key);
2350
- return window[`__TSR_DEHYDRATED__${strKey}`];
2351
- }
2352
- return undefined;
2353
- });
2354
- React__namespace.useLayoutEffect(() => {
2355
- startReactTransition(() => {
2356
- try {
2357
- load();
2358
- } catch (err) {
2359
- console.error(err);
2360
- }
2361
- });
2362
- }, []);
2363
- const routerContextValue = {
2364
- routeTree: router.routeTree,
2365
- navigate,
2366
- buildLink,
2367
- state,
2368
- matchRoute,
2369
- routesById,
2370
- options,
2371
- history,
2372
- load,
2373
- buildLocation,
2374
- subscribe: router.subscribe,
2375
- resetNextScrollRef,
2376
- injectedHtmlRef,
2377
- injectHtml,
2378
- dehydrateData,
2379
- hydrateData
2380
- };
2381
- return /*#__PURE__*/React__namespace.createElement(routerContext.Provider, {
2382
- value: routerContextValue
2383
- }, /*#__PURE__*/React__namespace.createElement(Matches, null));
2384
- }
2385
- function getRouteMatch(state, id) {
2386
- return [...state.pendingMatches, ...state.matches].find(d => d.id === id);
2387
- }
2388
- function useRouterState(opts) {
2389
- const {
2390
- state
2391
- } = useRouter();
2392
- // return useStore(router.__store, opts?.select as any)
2393
- return opts?.select ? opts.select(state) : state;
2394
- }
2395
- function useRouter() {
2396
- const resolvedContext = window.__TSR_ROUTER_CONTEXT__ || routerContext;
2397
- const value = React__namespace.useContext(resolvedContext);
2398
- warning(value, 'useRouter must be used inside a <RouterProvider> component!');
2399
- return value;
2400
- }
2401
-
2402
- function defer(_promise) {
2403
- const promise = _promise;
2404
- if (!promise.__deferredState) {
2405
- promise.__deferredState = {
2406
- uid: Math.random().toString(36).slice(2),
2407
- status: 'pending'
2408
- };
2409
- const state = promise.__deferredState;
2410
- promise.then(data => {
2411
- state.status = 'success';
2412
- state.data = data;
2413
- }).catch(error => {
2414
- state.status = 'error';
2415
- state.error = error;
2416
- });
2417
- }
2418
- return promise;
2419
- }
2420
- function isDehydratedDeferred(obj) {
2421
- return typeof obj === 'object' && obj !== null && !(obj instanceof Promise) && !obj.then && '__deferredState' in obj;
2422
- }
2423
-
2424
- function useAwaited({
2425
- promise
2426
- }) {
2427
- const router = useRouter();
2428
- let state = promise.__deferredState;
2429
- const key = `__TSR__DEFERRED__${state.uid}`;
2430
- if (isDehydratedDeferred(promise)) {
2431
- state = router.hydrateData(key);
2432
- promise = Promise.resolve(state.data);
2433
- promise.__deferredState = state;
2434
- }
2435
- if (state.status === 'pending') {
2436
- throw promise;
2437
- }
2438
- if (state.status === 'error') {
2439
- throw state.error;
2440
- }
2441
- router.dehydrateData(key, state);
2442
- return [state.data];
2443
- }
2444
- function Await(props) {
2445
- const awaited = useAwaited(props);
2446
- return props.children(...awaited);
2447
- }
2448
-
2449
- class FileRoute {
2450
- constructor(path) {
2451
- this.path = path;
2452
- }
2453
- createRoute = options => {
2454
- const route = new Route(options);
2455
- route.isRoot = false;
2456
- return route;
2457
- };
2458
- }
2459
-
2460
- function lazyRouteComponent(importer, exportName) {
2461
- let loadPromise;
2462
- const load = () => {
2463
- if (!loadPromise) {
2464
- loadPromise = importer();
2465
- }
2466
- return loadPromise;
2467
- };
2468
- const lazyComp = /*#__PURE__*/React__namespace.lazy(async () => {
2469
- const moduleExports = await load();
2470
- const comp = moduleExports[exportName ?? 'default'];
2471
- return {
2472
- default: comp
2473
- };
2474
- });
2475
- lazyComp.preload = load;
2476
- return lazyComp;
2477
- }
2478
-
2479
- function _extends() {
2480
- _extends = Object.assign ? Object.assign.bind() : function (target) {
2481
- for (var i = 1; i < arguments.length; i++) {
2482
- var source = arguments[i];
2483
- for (var key in source) {
2484
- if (Object.prototype.hasOwnProperty.call(source, key)) {
2485
- target[key] = source[key];
2442
+ const handleEnter = e => {
2443
+ const target = e.target || {};
2444
+ if (preload) {
2445
+ if (target.preloadTimeout) {
2446
+ return;
2486
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);
2487
2455
  }
2488
- }
2489
- return target;
2490
- };
2491
- return _extends.apply(this, arguments);
2492
- }
2493
-
2494
- function useLinkProps(options) {
2495
- const {
2496
- buildLink
2497
- } = useRouter();
2498
- const match = useMatch({
2499
- strict: false
2500
- });
2501
- const {
2502
- // custom props
2503
- type,
2504
- children,
2505
- target,
2506
- activeProps = () => ({
2507
- className: 'active'
2508
- }),
2509
- inactiveProps = () => ({}),
2510
- activeOptions,
2511
- disabled,
2512
- hash,
2513
- search,
2514
- params,
2515
- to,
2516
- state,
2517
- mask,
2518
- preload,
2519
- preloadDelay,
2520
- replace,
2521
- startTransition,
2522
- resetScroll,
2523
- // element props
2524
- style,
2525
- className,
2526
- onClick,
2527
- onFocus,
2528
- onMouseEnter,
2529
- onMouseLeave,
2530
- onTouchStart,
2531
- ...rest
2532
- } = options;
2533
- const linkInfo = buildLink({
2534
- from: options.to ? match.pathname : undefined,
2535
- ...options
2536
- });
2537
- if (linkInfo.type === 'external') {
2538
- const {
2539
- href
2540
- } = 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
+ };
2541
2464
  return {
2542
- href
2465
+ type: 'internal',
2466
+ next,
2467
+ handleFocus,
2468
+ handleClick,
2469
+ handleEnter,
2470
+ handleLeave,
2471
+ handleTouchStart,
2472
+ isActive,
2473
+ disabled
2543
2474
  };
2544
- }
2545
- const {
2546
- handleClick,
2547
- handleFocus,
2548
- handleEnter,
2549
- handleLeave,
2550
- handleTouchStart,
2551
- isActive,
2552
- next
2553
- } = linkInfo;
2554
- const composeHandlers = handlers => e => {
2555
- if (e.persist) e.persist();
2556
- handlers.filter(Boolean).forEach(handler => {
2557
- if (e.defaultPrevented) return;
2558
- 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
2559
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;
2560
2530
  };
2561
2531
 
2562
- // Get the active props
2563
- 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
+ // }
2564
2541
 
2565
- // Get the inactive props
2566
- const resolvedInactiveProps = isActive ? {} : functionalUpdate(inactiveProps, {}) ?? {};
2567
- return {
2568
- ...resolvedActiveProps,
2569
- ...resolvedInactiveProps,
2570
- ...rest,
2571
- href: disabled ? undefined : next.maskedLocation ? next.maskedLocation.href : next.href,
2572
- onClick: composeHandlers([onClick, handleClick]),
2573
- onFocus: composeHandlers([onFocus, handleFocus]),
2574
- onMouseEnter: composeHandlers([onMouseEnter, handleEnter]),
2575
- onMouseLeave: composeHandlers([onMouseLeave, handleLeave]),
2576
- onTouchStart: composeHandlers([onTouchStart, handleTouchStart]),
2577
- target,
2578
- style: {
2579
- ...style,
2580
- ...resolvedActiveProps.style,
2581
- ...resolvedInactiveProps.style
2582
- },
2583
- className: [className, resolvedActiveProps.className, resolvedInactiveProps.className].filter(Boolean).join(' ') || undefined,
2584
- ...(disabled ? {
2585
- role: 'link',
2586
- 'aria-disabled': true
2587
- } : undefined),
2588
- ['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);
2589
2603
  };
2590
2604
  }
2591
- const Link = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
2592
- const linkProps = useLinkProps(props);
2593
- return /*#__PURE__*/React__namespace.createElement("a", _extends({
2594
- ref: ref
2595
- }, linkProps, {
2596
- children: typeof props.children === 'function' ? props.children({
2597
- isActive: linkProps['data-status'] === 'active'
2598
- }) : props.children
2599
- }));
2600
- });
2605
+ function isCtrlEvent(e) {
2606
+ return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
2607
+ }
2601
2608
 
2602
2609
  const useLayoutEffect = typeof window !== 'undefined' ? React__namespace.useLayoutEffect : React__namespace.useEffect;
2603
2610
  const windowKey = 'window';
@@ -2607,11 +2614,7 @@
2607
2614
  const sessionsStorage = typeof window !== 'undefined' && window.sessionStorage;
2608
2615
  const defaultGetKey = location => location.state.key;
2609
2616
  function useScrollRestoration(options) {
2610
- const {
2611
- state,
2612
- subscribe,
2613
- resetNextScrollRef
2614
- } = useRouter();
2617
+ const router = useRouter();
2615
2618
  useLayoutEffect(() => {
2616
2619
  const getKey = options?.getKey || defaultGetKey;
2617
2620
  if (sessionsStorage) {
@@ -2667,7 +2670,7 @@
2667
2670
  if (typeof document !== 'undefined') {
2668
2671
  document.addEventListener('scroll', onScroll, true);
2669
2672
  }
2670
- const unsubOnBeforeLoad = subscribe('onBeforeLoad', event => {
2673
+ const unsubOnBeforeLoad = router.subscribe('onBeforeLoad', event => {
2671
2674
  if (event.pathChanged) {
2672
2675
  const restoreKey = getKey(event.fromLocation);
2673
2676
  for (const elementSelector in cache.state.next) {
@@ -2697,12 +2700,12 @@
2697
2700
  }
2698
2701
  }
2699
2702
  });
2700
- const unsubOnResolved = subscribe('onResolved', event => {
2703
+ const unsubOnResolved = router.subscribe('onResolved', event => {
2701
2704
  if (event.pathChanged) {
2702
- if (!resetNextScrollRef.current) {
2705
+ if (!router.resetNextScroll) {
2703
2706
  return;
2704
2707
  }
2705
- resetNextScrollRef.current = true;
2708
+ router.resetNextScroll = true;
2706
2709
  const getKey = options?.getKey || defaultGetKey;
2707
2710
  const restoreKey = getKey(event.toLocation);
2708
2711
  let windowRestored = false;