@tanstack/react-router 1.48.4 → 1.49.1

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.
Files changed (56) hide show
  1. package/dist/cjs/Matches.cjs +3 -1
  2. package/dist/cjs/Matches.cjs.map +1 -1
  3. package/dist/cjs/Matches.d.cts +5 -4
  4. package/dist/cjs/fileRoute.cjs.map +1 -1
  5. package/dist/cjs/fileRoute.d.cts +4 -5
  6. package/dist/cjs/index.cjs +2 -0
  7. package/dist/cjs/index.cjs.map +1 -1
  8. package/dist/cjs/index.d.cts +3 -1
  9. package/dist/cjs/link.cjs.map +1 -1
  10. package/dist/cjs/link.d.cts +1 -1
  11. package/dist/cjs/path.cjs +6 -9
  12. package/dist/cjs/path.cjs.map +1 -1
  13. package/dist/cjs/route.cjs +1 -1
  14. package/dist/cjs/route.cjs.map +1 -1
  15. package/dist/cjs/route.d.cts +80 -61
  16. package/dist/cjs/router.cjs +90 -57
  17. package/dist/cjs/router.cjs.map +1 -1
  18. package/dist/cjs/router.d.cts +22 -9
  19. package/dist/cjs/transformer.cjs +39 -0
  20. package/dist/cjs/transformer.cjs.map +1 -0
  21. package/dist/cjs/transformer.d.cts +5 -0
  22. package/dist/cjs/utils.cjs.map +1 -1
  23. package/dist/cjs/utils.d.cts +1 -0
  24. package/dist/esm/Matches.d.ts +5 -4
  25. package/dist/esm/Matches.js +3 -1
  26. package/dist/esm/Matches.js.map +1 -1
  27. package/dist/esm/fileRoute.d.ts +4 -5
  28. package/dist/esm/fileRoute.js.map +1 -1
  29. package/dist/esm/index.d.ts +3 -1
  30. package/dist/esm/index.js +2 -0
  31. package/dist/esm/index.js.map +1 -1
  32. package/dist/esm/link.d.ts +1 -1
  33. package/dist/esm/link.js.map +1 -1
  34. package/dist/esm/path.js +6 -9
  35. package/dist/esm/path.js.map +1 -1
  36. package/dist/esm/route.d.ts +80 -61
  37. package/dist/esm/route.js +1 -1
  38. package/dist/esm/route.js.map +1 -1
  39. package/dist/esm/router.d.ts +22 -9
  40. package/dist/esm/router.js +91 -58
  41. package/dist/esm/router.js.map +1 -1
  42. package/dist/esm/transformer.d.ts +5 -0
  43. package/dist/esm/transformer.js +39 -0
  44. package/dist/esm/transformer.js.map +1 -0
  45. package/dist/esm/utils.d.ts +1 -0
  46. package/dist/esm/utils.js.map +1 -1
  47. package/package.json +2 -2
  48. package/src/Matches.tsx +11 -7
  49. package/src/fileRoute.ts +28 -22
  50. package/src/index.tsx +5 -1
  51. package/src/link.tsx +10 -6
  52. package/src/path.ts +7 -10
  53. package/src/route.ts +375 -190
  54. package/src/router.ts +144 -75
  55. package/src/transformer.ts +49 -0
  56. package/src/utils.ts +5 -0
@@ -10,6 +10,7 @@ const utils = require("./utils.cjs");
10
10
  const path = require("./path.cjs");
11
11
  const redirects = require("./redirects.cjs");
12
12
  const notFound = require("./not-found.cjs");
13
+ const transformer = require("./transformer.cjs");
13
14
  const componentTypes = [
14
15
  "component",
15
16
  "errorComponent",
@@ -210,12 +211,12 @@ class Router {
210
211
  });
211
212
  return resolvedPath;
212
213
  };
213
- this.matchRoutes = (pathname, locationSearch, opts) => {
214
+ this.matchRoutes = (next, opts) => {
214
215
  let routeParams = {};
215
216
  const foundRoute = this.flatRoutes.find((route) => {
216
217
  const matchedParams = path.matchPathname(
217
218
  this.basepath,
218
- path.trimPathRight(pathname),
219
+ path.trimPathRight(next.pathname),
219
220
  {
220
221
  to: route.fullPath,
221
222
  caseSensitive: route.options.caseSensitive ?? this.options.caseSensitive,
@@ -235,7 +236,7 @@ class Router {
235
236
  // If we found a route, and it's not an index route and we have left over path
236
237
  foundRoute ? foundRoute.path !== "/" && routeParams["**"] : (
237
238
  // Or if we didn't find a route and we have left over path
238
- path.trimPathRight(pathname)
239
+ path.trimPathRight(next.pathname)
239
240
  )
240
241
  ) {
241
242
  if (this.options.notFoundRoute) {
@@ -284,10 +285,10 @@ class Router {
284
285
  });
285
286
  const matches = [];
286
287
  matchedRoutes.forEach((route, index) => {
287
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
288
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
288
289
  const parentMatch = matches[index - 1];
289
290
  const [preMatchSearch, searchError] = (() => {
290
- const parentSearch = (parentMatch == null ? void 0 : parentMatch.search) ?? locationSearch;
291
+ const parentSearch = (parentMatch == null ? void 0 : parentMatch.search) ?? next.search;
291
292
  try {
292
293
  const validator = typeof route.options.validateSearch === "object" ? route.options.validateSearch.parse : route.options.validateSearch;
293
294
  const search = (validator == null ? void 0 : validator(parentSearch)) ?? {};
@@ -345,8 +346,9 @@ class Router {
345
346
  isFetching: false,
346
347
  error: void 0,
347
348
  paramsError: parseErrors[index],
348
- routeContext: void 0,
349
- context: void 0,
349
+ __routeContext: {},
350
+ __beforeLoadContext: {},
351
+ context: {},
350
352
  abortController: new AbortController(),
351
353
  fetchCount: 0,
352
354
  cause,
@@ -375,6 +377,30 @@ class Router {
375
377
  }
376
378
  match.search = utils.replaceEqualDeep(match.search, preMatchSearch);
377
379
  match.searchError = searchError;
380
+ const parentMatchId = parentMatch == null ? void 0 : parentMatch.id;
381
+ const parentContext = !parentMatchId ? this.options.context ?? {} : parentMatch.context ?? this.options.context ?? {};
382
+ match.context = {
383
+ ...parentContext,
384
+ ...match.__routeContext,
385
+ ...match.__beforeLoadContext
386
+ };
387
+ const contextFnContext = {
388
+ search: match.search,
389
+ params: match.params,
390
+ context: match.context,
391
+ location: next,
392
+ navigate: (opts2) => this.navigate({ ...opts2, _fromLocation: next }),
393
+ buildLocation: this.buildLocation,
394
+ cause: match.cause,
395
+ abortController: match.abortController,
396
+ preload: !!match.preload
397
+ };
398
+ match.__routeContext = ((_l = (_k = route.options).context) == null ? void 0 : _l.call(_k, contextFnContext)) ?? {};
399
+ match.context = {
400
+ ...parentContext,
401
+ ...match.__routeContext,
402
+ ...match.__beforeLoadContext
403
+ };
378
404
  matches.push(match);
379
405
  });
380
406
  return matches;
@@ -394,10 +420,10 @@ class Router {
394
420
  this.buildLocation = (opts) => {
395
421
  const build = (dest = {}, matches) => {
396
422
  var _a, _b, _c;
397
- const fromMatches = dest._fromLocation != null ? this.matchRoutes(
398
- dest._fromLocation.pathname,
399
- dest.fromSearch || dest._fromLocation.search
400
- ) : this.state.matches;
423
+ const fromMatches = dest._fromLocation != null ? this.matchRoutes({
424
+ ...dest._fromLocation,
425
+ search: dest.fromSearch || dest._fromLocation.search
426
+ }) : this.state.matches;
401
427
  const fromMatch = dest.from != null ? fromMatches.find(
402
428
  (d) => path.matchPathname(this.basepath, path.trimPathRight(d.pathname), {
403
429
  to: dest.from,
@@ -489,8 +515,8 @@ class Router {
489
515
  maskedNext = build(maskedDest);
490
516
  }
491
517
  }
492
- const nextMatches = this.matchRoutes(next.pathname, next.search);
493
- const maskedMatches = maskedNext ? this.matchRoutes(maskedNext.pathname, maskedNext.search) : void 0;
518
+ const nextMatches = this.matchRoutes(next);
519
+ const maskedMatches = maskedNext ? this.matchRoutes(maskedNext) : void 0;
494
520
  const maskedFinal = maskedNext ? build(maskedDest, maskedMatches) : void 0;
495
521
  const final = build(dest, nextMatches);
496
522
  if (maskedFinal) {
@@ -568,6 +594,13 @@ class Router {
568
594
  ignoreBlocker,
569
595
  ...rest
570
596
  } = {}) => {
597
+ const href = rest.href;
598
+ if (href) {
599
+ const parsed = history.parseHref(href, {});
600
+ rest.to = parsed.pathname;
601
+ rest.search = this.options.parseSearch(parsed.search);
602
+ rest.hash = parsed.hash;
603
+ }
571
604
  const location = this.buildLocation(rest);
572
605
  return this.commitLocation({
573
606
  ...location,
@@ -577,7 +610,7 @@ class Router {
577
610
  ignoreBlocker
578
611
  });
579
612
  };
580
- this.navigate = ({ from, to, __isRedirect, ...rest }) => {
613
+ this.navigate = ({ to, __isRedirect, ...rest }) => {
581
614
  const toString = String(to);
582
615
  let isExternal;
583
616
  try {
@@ -591,7 +624,6 @@ class Router {
591
624
  );
592
625
  return this.buildAndCommitLocation({
593
626
  ...rest,
594
- from,
595
627
  to
596
628
  // to: toString,
597
629
  });
@@ -604,7 +636,8 @@ class Router {
604
636
  }));
605
637
  let redirect;
606
638
  let notFound$1;
607
- const loadPromise = new Promise((resolve) => {
639
+ let loadPromise;
640
+ loadPromise = new Promise((resolve) => {
608
641
  this.startReactTransition(async () => {
609
642
  var _a;
610
643
  try {
@@ -614,7 +647,7 @@ class Router {
614
647
  this.cancelMatches();
615
648
  let pendingMatches;
616
649
  this.__store.batch(() => {
617
- pendingMatches = this.matchRoutes(next.pathname, next.search);
650
+ pendingMatches = this.matchRoutes(next);
618
651
  this.__store.setState((s) => ({
619
652
  ...s,
620
653
  status: "pending",
@@ -834,6 +867,7 @@ class Router {
834
867
  };
835
868
  for (const [index, { id: matchId, routeId }] of matches.entries()) {
836
869
  const existingMatch = this.getMatch(matchId);
870
+ const parentMatchId = (_a = matches[index - 1]) == null ? void 0 : _a.id;
837
871
  if (
838
872
  // If we are in the middle of a load, either of these will be present
839
873
  // (not to be confused with `loadPromise`, which is always defined)
@@ -852,13 +886,6 @@ class Router {
852
886
  }));
853
887
  const route = this.looseRoutesById[routeId];
854
888
  const abortController = new AbortController();
855
- const parentMatchId = (_a = matches[index - 1]) == null ? void 0 : _a.id;
856
- const getParentContext = () => {
857
- if (!parentMatchId) {
858
- return this.options.context ?? {};
859
- }
860
- return this.getMatch(parentMatchId).context ?? this.options.context ?? {};
861
- };
862
889
  const pendingMs = route.options.pendingMs ?? this.options.defaultPendingMs;
863
890
  const shouldPending = !!(onReady && !this.isServer && !preload && (route.options.loader || route.options.beforeLoad) && typeof pendingMs === "number" && pendingMs !== Infinity && (route.options.pendingComponent ?? this.options.defaultPendingComponent));
864
891
  let pendingTimeout;
@@ -877,47 +904,54 @@ class Router {
877
904
  if (searchError) {
878
905
  handleSerialError(index, searchError, "VALIDATE_SEARCH");
879
906
  }
880
- const parentContext = getParentContext();
907
+ const getParentMatchContext = () => parentMatchId ? this.getMatch(parentMatchId).context : this.options.context ?? {};
881
908
  updateMatch(matchId, (prev) => ({
882
909
  ...prev,
883
910
  isFetching: "beforeLoad",
884
911
  fetchCount: prev.fetchCount + 1,
885
- routeContext: utils.replaceEqualDeep(
886
- prev.routeContext,
887
- parentContext
888
- ),
889
- context: utils.replaceEqualDeep(prev.context, parentContext),
890
912
  abortController,
891
- pendingTimeout
913
+ pendingTimeout,
914
+ context: {
915
+ ...getParentMatchContext(),
916
+ ...prev.__routeContext,
917
+ ...prev.__beforeLoadContext
918
+ }
892
919
  }));
893
- const { search, params, routeContext, cause } = this.getMatch(matchId);
920
+ const { search, params, context, cause } = this.getMatch(matchId);
894
921
  const beforeLoadFnContext = {
895
922
  search,
896
923
  abortController,
897
924
  params,
898
925
  preload: !!preload,
899
- context: routeContext,
926
+ context,
900
927
  location,
901
928
  navigate: (opts) => this.navigate({ ...opts, _fromLocation: location }),
902
929
  buildLocation: this.buildLocation,
903
930
  cause: preload ? "preload" : cause
904
931
  };
905
- const beforeLoadContext = await ((_c = (_b = route.options).beforeLoad) == null ? void 0 : _c.call(_b, beforeLoadFnContext)) ?? {};
932
+ let beforeLoadContext = await ((_c = (_b = route.options).beforeLoad) == null ? void 0 : _c.call(_b, beforeLoadFnContext)) ?? {};
933
+ if (this.serializeLoaderData) {
934
+ beforeLoadContext = this.serializeLoaderData(
935
+ "__beforeLoadContext",
936
+ beforeLoadContext,
937
+ {
938
+ router: this,
939
+ match: this.getMatch(matchId)
940
+ }
941
+ );
942
+ }
906
943
  if (redirects.isRedirect(beforeLoadContext) || notFound.isNotFound(beforeLoadContext)) {
907
944
  handleSerialError(index, beforeLoadContext, "BEFORE_LOAD");
908
945
  }
909
946
  updateMatch(matchId, (prev) => {
910
- const routeContext2 = {
911
- ...prev.routeContext,
912
- ...beforeLoadContext
913
- };
914
947
  return {
915
948
  ...prev,
916
- routeContext: utils.replaceEqualDeep(
917
- prev.routeContext,
918
- routeContext2
919
- ),
920
- context: utils.replaceEqualDeep(prev.context, routeContext2),
949
+ __beforeLoadContext: beforeLoadContext,
950
+ context: {
951
+ ...getParentMatchContext(),
952
+ ...prev.__routeContext,
953
+ ...beforeLoadContext
954
+ },
921
955
  abortController
922
956
  };
923
957
  });
@@ -1010,10 +1044,14 @@ class Router {
1010
1044
  await route._lazyPromise;
1011
1045
  let loaderData = await ((_b2 = (_a2 = route.options).loader) == null ? void 0 : _b2.call(_a2, getLoaderContext()));
1012
1046
  if (this.serializeLoaderData) {
1013
- loaderData = this.serializeLoaderData(loaderData, {
1014
- router: this,
1015
- match: this.getMatch(matchId)
1016
- });
1047
+ loaderData = this.serializeLoaderData(
1048
+ "loaderData",
1049
+ loaderData,
1050
+ {
1051
+ router: this,
1052
+ match: this.getMatch(matchId)
1053
+ }
1054
+ );
1017
1055
  }
1018
1056
  handleRedirectAndNotFound(
1019
1057
  this.getMatch(matchId),
@@ -1065,7 +1103,8 @@ class Router {
1065
1103
  }
1066
1104
  };
1067
1105
  const { status, invalid } = this.getMatch(matchId);
1068
- if (status === "success" && (invalid || (shouldReload ?? age > staleAge))) {
1106
+ if (preload && route.options.preload === false) {
1107
+ } else if (status === "success" && (invalid || (shouldReload ?? age > staleAge))) {
1069
1108
  ;
1070
1109
  (async () => {
1071
1110
  try {
@@ -1147,7 +1186,7 @@ class Router {
1147
1186
  };
1148
1187
  this.preloadRoute = async (opts) => {
1149
1188
  const next = this.buildLocation(opts);
1150
- let matches = this.matchRoutes(next.pathname, next.search, {
1189
+ let matches = this.matchRoutes(next, {
1151
1190
  throwOnError: true,
1152
1191
  preload: true
1153
1192
  });
@@ -1265,10 +1304,7 @@ class Router {
1265
1304
  this.dehydratedData = ctx.payload;
1266
1305
  (_c = (_b = this.options).hydrate) == null ? void 0 : _c.call(_b, ctx.payload);
1267
1306
  const dehydratedState = ctx.router.state;
1268
- const matches = this.matchRoutes(
1269
- this.state.location.pathname,
1270
- this.state.location.search
1271
- ).map((match) => {
1307
+ const matches = this.matchRoutes(this.state.location).map((match) => {
1272
1308
  const dehydratedMatch = dehydratedState.dehydratedMatches.find(
1273
1309
  (d) => d.id === match.id
1274
1310
  );
@@ -1368,10 +1404,7 @@ class Router {
1368
1404
  notFoundMode: options.notFoundMode ?? "fuzzy",
1369
1405
  stringifySearch: options.stringifySearch ?? searchParams.defaultStringifySearch,
1370
1406
  parseSearch: options.parseSearch ?? searchParams.defaultParseSearch,
1371
- transformer: options.transformer ?? {
1372
- parse: JSON.parse,
1373
- stringify: JSON.stringify
1374
- }
1407
+ transformer: options.transformer ?? transformer.defaultTransformer
1375
1408
  });
1376
1409
  if (typeof document !== "undefined") {
1377
1410
  window.__TSR__ROUTER__ = this;