@tanstack/react-router 0.0.1-beta.185 → 0.0.1-beta.187

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tanstack/react-router",
3
3
  "author": "Tanner Linsley",
4
- "version": "0.0.1-beta.185",
4
+ "version": "0.0.1-beta.187",
5
5
  "license": "MIT",
6
6
  "repository": "tanstack/router",
7
7
  "homepage": "https://tanstack.com/router",
@@ -44,7 +44,7 @@
44
44
  "tiny-warning": "^1.0.3",
45
45
  "@tanstack/react-store": "^0.0.1",
46
46
  "@gisatcz/cross-package-react-context": "^0.2.0",
47
- "@tanstack/router-core": "0.0.1-beta.185"
47
+ "@tanstack/router-core": "0.0.1-beta.187"
48
48
  },
49
49
  "scripts": {
50
50
  "build": "rollup --config rollup.config.js"
package/src/react.tsx CHANGED
@@ -22,7 +22,7 @@ import {
22
22
  ResolveId,
23
23
  AnySearchSchema,
24
24
  ParsePathParams,
25
- MergeParamsFromParent,
25
+ MergeFromFromParent,
26
26
  RouteContext,
27
27
  AnyContext,
28
28
  UseLoaderResult,
@@ -37,8 +37,13 @@ import {
37
37
  AllParams,
38
38
  rootRouteId,
39
39
  AnyPathParams,
40
+ Expand,
41
+ ResolveAllParams,
40
42
  } from '@tanstack/router-core'
41
43
 
44
+ const useLayoutEffect =
45
+ typeof document !== 'undefined' ? React.useLayoutEffect : React.useEffect
46
+
42
47
  declare module '@tanstack/router-core' {
43
48
  interface RegisterRouteComponent<
44
49
  TLoader = unknown,
@@ -104,18 +109,17 @@ declare module '@tanstack/router-core' {
104
109
  TParentRoute,
105
110
  TSearchSchema
106
111
  >,
107
- TParams extends RouteConstraints['TParams'] = Record<
108
- ParsePathParams<TPath>,
109
- string
112
+ TParams extends RouteConstraints['TParams'] = Expand<
113
+ Record<ParsePathParams<TPath>, string>
110
114
  >,
111
- TAllParams extends RouteConstraints['TAllParams'] = MergeParamsFromParent<
112
- TParentRoute['types']['allParams'],
115
+ TAllParams extends RouteConstraints['TAllParams'] = ResolveAllParams<
116
+ TParentRoute,
113
117
  TParams
114
118
  >,
115
119
  TParentContext extends RouteConstraints['TParentContext'] = TParentRoute['types']['routeContext'],
116
120
  TAllParentContext extends RouteConstraints['TAllParentContext'] = TParentRoute['types']['context'],
117
121
  TRouteContext extends RouteConstraints['TRouteContext'] = RouteContext,
118
- TAllContext extends RouteConstraints['TAllContext'] = MergeParamsFromParent<
122
+ TAllContext extends RouteConstraints['TAllContext'] = MergeFromFromParent<
119
123
  TParentRoute['types']['context'],
120
124
  TRouteContext
121
125
  >,
@@ -333,9 +337,18 @@ export function lazyRouteComponent<
333
337
  }
334
338
 
335
339
  export type LinkPropsOptions<
336
- TFrom extends RoutePaths<RegisteredRouter['routeTree']> = '/',
340
+ TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
341
+ TFrom extends RoutePaths<TRouteTree> = '/',
337
342
  TTo extends string = '',
338
- > = LinkOptions<RegisteredRouter['routeTree'], TFrom, TTo> & {
343
+ TMaskFrom extends RoutePaths<TRouteTree> = '/',
344
+ TMaskTo extends string = '',
345
+ > = LinkOptions<
346
+ RegisteredRouter['routeTree'],
347
+ TFrom,
348
+ TTo,
349
+ TMaskFrom,
350
+ TMaskTo
351
+ > & {
339
352
  // A function that returns additional props for the `active` state of this link. These props override other props passed to the link (`style`'s are merged, `className`'s are concatenated)
340
353
  activeProps?:
341
354
  | React.AnchorHTMLAttributes<HTMLAnchorElement>
@@ -349,14 +362,21 @@ export type LinkPropsOptions<
349
362
  }
350
363
 
351
364
  export type MakeUseMatchRouteOptions<
352
- TFrom extends RoutePaths<RegisteredRouter['routeTree']> = '/',
365
+ TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
366
+ TFrom extends RoutePaths<TRouteTree> = '/',
353
367
  TTo extends string = '',
354
- > = ToOptions<RegisteredRouter['routeTree'], TFrom, TTo> & MatchRouteOptions
368
+ TMaskFrom extends RoutePaths<TRouteTree> = '/',
369
+ TMaskTo extends string = '',
370
+ > = ToOptions<RegisteredRouter['routeTree'], TFrom, TTo, TMaskFrom, TMaskTo> &
371
+ MatchRouteOptions
355
372
 
356
373
  export type MakeMatchRouteOptions<
357
- TFrom extends RoutePaths<RegisteredRouter['routeTree']> = '/',
374
+ TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
375
+ TFrom extends RoutePaths<TRouteTree> = '/',
358
376
  TTo extends string = '',
359
- > = ToOptions<RegisteredRouter['routeTree'], TFrom, TTo> &
377
+ TMaskFrom extends RoutePaths<TRouteTree> = '/',
378
+ TMaskTo extends string = '',
379
+ > = ToOptions<RegisteredRouter['routeTree'], TFrom, TTo, TMaskFrom, TMaskTo> &
360
380
  MatchRouteOptions & {
361
381
  // If a function is passed as a child, it will be given the `isActive` boolean to aid in further styling on the element it returns
362
382
  children?:
@@ -370,14 +390,21 @@ export type MakeMatchRouteOptions<
370
390
  }
371
391
 
372
392
  export type MakeLinkPropsOptions<
373
- TFrom extends string = '/',
393
+ TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
394
+ TFrom extends RoutePaths<TRouteTree> = '/',
374
395
  TTo extends string = '',
375
- > = LinkPropsOptions<TFrom, TTo> & React.AnchorHTMLAttributes<HTMLAnchorElement>
396
+ TMaskFrom extends RoutePaths<TRouteTree> = '/',
397
+ TMaskTo extends string = '',
398
+ > = LinkPropsOptions<TRouteTree, TFrom, TTo, TMaskFrom, TMaskTo> &
399
+ React.AnchorHTMLAttributes<HTMLAnchorElement>
376
400
 
377
401
  export type MakeLinkOptions<
378
- TFrom extends RoutePaths<RegisteredRouter['routeTree']> = '/',
402
+ TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
403
+ TFrom extends RoutePaths<TRouteTree> = '/',
379
404
  TTo extends string = '',
380
- > = LinkPropsOptions<TFrom, TTo> &
405
+ TMaskFrom extends RoutePaths<TRouteTree> = '/',
406
+ TMaskTo extends string = '',
407
+ > = LinkPropsOptions<TRouteTree, TFrom, TTo, TMaskFrom, TMaskTo> &
381
408
  Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'children'> & {
382
409
  // If a function is passed as a child, it will be given the `isActive` boolean to aid in further styling on the element it returns
383
410
  children?:
@@ -394,10 +421,13 @@ export type PromptProps = {
394
421
  //
395
422
 
396
423
  export function useLinkProps<
397
- TFrom extends string = '/',
424
+ TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
425
+ TFrom extends RoutePaths<TRouteTree> = '/',
398
426
  TTo extends string = '',
427
+ TMaskFrom extends RoutePaths<TRouteTree> = '/',
428
+ TMaskTo extends string = '',
399
429
  >(
400
- options: MakeLinkPropsOptions<TFrom, TTo>,
430
+ options: MakeLinkPropsOptions<TRouteTree, TFrom, TTo, TMaskFrom, TMaskTo>,
401
431
  ): React.AnchorHTMLAttributes<HTMLAnchorElement> {
402
432
  const router = useRouter()
403
433
 
@@ -415,6 +445,8 @@ export function useLinkProps<
415
445
  search,
416
446
  params,
417
447
  to = '.',
448
+ state,
449
+ mask,
418
450
  preload,
419
451
  preloadDelay,
420
452
  replace,
@@ -477,7 +509,11 @@ export function useLinkProps<
477
509
  ...resolvedActiveProps,
478
510
  ...resolvedInactiveProps,
479
511
  ...rest,
480
- href: disabled ? undefined : next.href,
512
+ href: disabled
513
+ ? undefined
514
+ : next.maskedLocation
515
+ ? next.maskedLocation.href
516
+ : next.href,
481
517
  onClick: composeHandlers([onClick, handleReactClick]),
482
518
  onFocus: composeHandlers([onFocus, handleFocus]),
483
519
  onMouseEnter: composeHandlers([onMouseEnter, handleEnter]),
@@ -509,10 +545,13 @@ export function useLinkProps<
509
545
 
510
546
  export interface LinkComponent<TProps extends Record<string, any> = {}> {
511
547
  <
512
- TFrom extends RoutePaths<RegisteredRouter['routeTree']> = '/',
548
+ TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
549
+ TFrom extends RoutePaths<TRouteTree> = '/',
513
550
  TTo extends string = '',
551
+ TMaskFrom extends RoutePaths<TRouteTree> = '/',
552
+ TMaskTo extends string = '',
514
553
  >(
515
- props: MakeLinkOptions<TFrom, TTo> &
554
+ props: MakeLinkOptions<TRouteTree, TFrom, TTo, TMaskFrom, TMaskTo> &
516
555
  TProps &
517
556
  React.RefAttributes<HTMLAnchorElement>,
518
557
  ): ReactNode
@@ -538,9 +577,20 @@ export const Link: LinkComponent = React.forwardRef((props: any, ref) => {
538
577
  }) as any
539
578
 
540
579
  export function Navigate<
541
- TFrom extends RoutePaths<RegisteredRouter['routeTree']> = '/',
580
+ TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
581
+ TFrom extends RoutePaths<TRouteTree> = '/',
542
582
  TTo extends string = '',
543
- >(props: NavigateOptions<RegisteredRouter['routeTree'], TFrom, TTo>): null {
583
+ TMaskFrom extends RoutePaths<TRouteTree> = '/',
584
+ TMaskTo extends string = '',
585
+ >(
586
+ props: NavigateOptions<
587
+ RegisteredRouter['routeTree'],
588
+ TFrom,
589
+ TTo,
590
+ TMaskFrom,
591
+ TMaskTo
592
+ >,
593
+ ): null {
544
594
  const router = useRouter()
545
595
 
546
596
  React.useLayoutEffect(() => {
@@ -604,11 +654,31 @@ function Matches() {
604
654
  },
605
655
  })
606
656
 
657
+ const locationKey = useRouterState({
658
+ select: (d) => d.resolvedLocation.state?.key,
659
+ })
660
+
661
+ const route = router.getRoute(rootRouteId)
662
+
663
+ const errorComponent = React.useCallback(
664
+ (props: any) => {
665
+ return React.createElement(ErrorComponent, {
666
+ ...props,
667
+ useMatch: route.useMatch,
668
+ useContext: route.useContext,
669
+ useRouteContext: route.useRouteContext,
670
+ useSearch: route.useSearch,
671
+ useParams: route.useParams,
672
+ })
673
+ },
674
+ [route],
675
+ )
676
+
607
677
  return (
608
678
  <matchIdsContext.Provider value={[undefined!, ...matchIds]}>
609
679
  <CatchBoundary
610
- errorComponent={ErrorComponent}
611
- route={router.getRoute(rootRouteId)}
680
+ resetKey={locationKey}
681
+ errorComponent={errorComponent}
612
682
  onCatch={() => {
613
683
  warning(
614
684
  false,
@@ -826,15 +896,24 @@ export function useParams<
826
896
  }
827
897
 
828
898
  export function useNavigate<
829
- TDefaultFrom extends RoutePaths<RegisteredRouter['routeTree']> = '/',
899
+ TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
900
+ TDefaultFrom extends RoutePaths<TRouteTree> = '/',
830
901
  >(defaultOpts?: { from?: TDefaultFrom }) {
831
902
  const router = useRouter()
832
903
  return React.useCallback(
833
904
  <
834
- TFrom extends RoutePaths<RegisteredRouter['routeTree']> = TDefaultFrom,
905
+ TFrom extends RoutePaths<TRouteTree> = TDefaultFrom,
835
906
  TTo extends string = '',
907
+ TMaskFrom extends RoutePaths<TRouteTree> = '/',
908
+ TMaskTo extends string = '',
836
909
  >(
837
- opts?: NavigateOptions<RegisteredRouter['routeTree'], TFrom, TTo>,
910
+ opts?: NavigateOptions<
911
+ RegisteredRouter['routeTree'],
912
+ TFrom,
913
+ TTo,
914
+ TMaskFrom,
915
+ TMaskTo
916
+ >,
838
917
  ) => {
839
918
  return router.navigate({ ...defaultOpts, ...(opts as any) })
840
919
  },
@@ -846,8 +925,20 @@ export function useMatchRoute() {
846
925
  const router = useRouter()
847
926
 
848
927
  return React.useCallback(
849
- <TFrom extends string = '/', TTo extends string = ''>(
850
- opts: MakeUseMatchRouteOptions<TFrom, TTo>,
928
+ <
929
+ TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
930
+ TFrom extends RoutePaths<TRouteTree> = '/',
931
+ TTo extends string = '',
932
+ TMaskFrom extends RoutePaths<TRouteTree> = '/',
933
+ TMaskTo extends string = '',
934
+ >(
935
+ opts: MakeUseMatchRouteOptions<
936
+ TRouteTree,
937
+ TFrom,
938
+ TTo,
939
+ TMaskFrom,
940
+ TMaskTo
941
+ >,
851
942
  ) => {
852
943
  const { pending, caseSensitive, ...rest } = opts
853
944
 
@@ -860,11 +951,17 @@ export function useMatchRoute() {
860
951
  )
861
952
  }
862
953
 
863
- export function MatchRoute<TFrom extends string = '/', TTo extends string = ''>(
864
- props: MakeMatchRouteOptions<TFrom, TTo>,
954
+ export function MatchRoute<
955
+ TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
956
+ TFrom extends RoutePaths<TRouteTree> = '/',
957
+ TTo extends string = '',
958
+ TMaskFrom extends RoutePaths<TRouteTree> = '/',
959
+ TMaskTo extends string = '',
960
+ >(
961
+ props: MakeMatchRouteOptions<TRouteTree, TFrom, TTo, TMaskFrom, TMaskTo>,
865
962
  ): any {
866
963
  const matchRoute = useMatchRoute()
867
- const params = matchRoute(props)
964
+ const params = matchRoute(props as any)
868
965
 
869
966
  if (typeof props.children === 'function') {
870
967
  return (props.children as any)(params)
@@ -890,12 +987,15 @@ function Match({ matchIds }: { matchIds: string[] }) {
890
987
  const matchId = matchIds[0]!
891
988
  const routeId = router.getRouteMatch(matchId)!.routeId
892
989
  const route = router.getRoute(routeId)
990
+ const locationKey = useRouterState({
991
+ select: (s) => s.resolvedLocation.state?.key,
992
+ })
893
993
 
894
994
  const PendingComponent = (route.options.pendingComponent ??
895
995
  router.options.defaultPendingComponent ??
896
996
  defaultPending) as any
897
997
 
898
- const errorComponent =
998
+ const routeErrorComponent =
899
999
  route.options.errorComponent ??
900
1000
  router.options.defaultErrorComponent ??
901
1001
  ErrorComponent
@@ -905,7 +1005,23 @@ function Match({ matchIds }: { matchIds: string[] }) {
905
1005
  ? React.Suspense
906
1006
  : SafeFragment
907
1007
 
908
- const ResolvedCatchBoundary = !!errorComponent ? CatchBoundary : SafeFragment
1008
+ const ResolvedCatchBoundary = !!routeErrorComponent
1009
+ ? CatchBoundary
1010
+ : SafeFragment
1011
+
1012
+ const errorComponent = React.useCallback(
1013
+ (props: any) => {
1014
+ return React.createElement(routeErrorComponent, {
1015
+ ...props,
1016
+ useMatch: route.useMatch,
1017
+ useContext: route.useContext,
1018
+ useRouteContext: route.useRouteContext,
1019
+ useSearch: route.useSearch,
1020
+ useParams: route.useParams,
1021
+ })
1022
+ },
1023
+ [route],
1024
+ )
909
1025
 
910
1026
  return (
911
1027
  <matchIdsContext.Provider value={matchIds}>
@@ -919,9 +1035,8 @@ function Match({ matchIds }: { matchIds: string[] }) {
919
1035
  })}
920
1036
  >
921
1037
  <ResolvedCatchBoundary
922
- key={route.id}
1038
+ resetKey={locationKey}
923
1039
  errorComponent={errorComponent}
924
- route={route}
925
1040
  onCatch={() => {
926
1041
  warning(false, `Error in route match: ${matchId}`)
927
1042
  }}
@@ -1028,80 +1143,58 @@ export function useHydrate() {
1028
1143
  // there has to be a better way to reset error boundaries when the
1029
1144
  // router's location key changes.
1030
1145
 
1031
- class CatchBoundary extends React.Component<{
1146
+ export function CatchBoundary(props: {
1147
+ resetKey: string
1032
1148
  children: any
1033
- errorComponent: any
1034
- route: AnyRoute
1035
- onCatch: (error: any, info: any) => void
1036
- }> {
1037
- state = {
1038
- error: false,
1039
- info: undefined,
1040
- }
1041
- componentDidCatch(error: any, info: any) {
1042
- this.props.onCatch(error, info)
1043
- this.setState({
1044
- error,
1045
- info,
1046
- })
1047
- }
1048
- render() {
1049
- return (
1050
- <CatchBoundaryInner
1051
- {...this.props}
1052
- errorState={this.state}
1053
- reset={() => this.setState({})}
1054
- />
1055
- )
1056
- }
1057
- }
1058
-
1059
- function CatchBoundaryInner(props: {
1060
- children: any
1061
- errorComponent: any
1062
- route: AnyRoute
1063
- errorState: { error: unknown; info: any }
1064
- reset: () => void
1149
+ errorComponent?: any
1150
+ onCatch: (error: any) => void
1065
1151
  }) {
1066
- const locationKey = useRouterState({
1067
- select: (d) => d.resolvedLocation.key,
1068
- })
1069
-
1070
- const [activeErrorState, setActiveErrorState] = React.useState(
1071
- props.errorState,
1072
- )
1073
1152
  const errorComponent = props.errorComponent ?? ErrorComponent
1074
- const prevKeyRef = React.useRef('' as any)
1075
1153
 
1076
- React.useEffect(() => {
1077
- if (activeErrorState) {
1078
- if (locationKey !== prevKeyRef.current) {
1079
- setActiveErrorState({} as any)
1080
- }
1081
- }
1154
+ return (
1155
+ <CatchBoundaryImpl
1156
+ resetKey={props.resetKey}
1157
+ onCatch={props.onCatch}
1158
+ children={({ error }) => {
1159
+ if (error) {
1160
+ return React.createElement(errorComponent, {
1161
+ error,
1162
+ })
1163
+ }
1082
1164
 
1083
- prevKeyRef.current = locationKey
1084
- }, [activeErrorState, locationKey])
1165
+ return props.children
1166
+ }}
1167
+ />
1168
+ )
1169
+ }
1085
1170
 
1086
- React.useEffect(() => {
1087
- if (props.errorState.error) {
1088
- setActiveErrorState(props.errorState)
1171
+ export class CatchBoundaryImpl extends React.Component<{
1172
+ resetKey: string
1173
+ children: (props: { error: any; reset: () => void }) => any
1174
+ onCatch?: (error: any) => void
1175
+ }> {
1176
+ state = { error: null } as any
1177
+ static getDerivedStateFromError(error: any) {
1178
+ return { error }
1179
+ }
1180
+ componentDidUpdate(
1181
+ prevProps: Readonly<{
1182
+ resetKey: string
1183
+ children: (props: { error: any; reset: () => void }) => any
1184
+ onCatch?: ((error: any, info: any) => void) | undefined
1185
+ }>,
1186
+ prevState: any,
1187
+ ): void {
1188
+ if (prevState.error && prevProps.resetKey !== this.props.resetKey) {
1189
+ this.setState({ error: null })
1089
1190
  }
1090
- // props.reset()
1091
- }, [props.errorState.error])
1092
-
1093
- if (props.errorState.error && activeErrorState.error) {
1094
- return React.createElement(errorComponent, {
1095
- ...activeErrorState,
1096
- useMatch: props.route.useMatch,
1097
- useContext: props.route.useContext,
1098
- useRouteContext: props.route.useRouteContext,
1099
- useSearch: props.route.useSearch,
1100
- useParams: props.route.useParams,
1101
- })
1102
1191
  }
1103
-
1104
- return props.children
1192
+ componentDidCatch(error: any) {
1193
+ this.props.onCatch?.(error)
1194
+ }
1195
+ render() {
1196
+ return this.props.children(this.state)
1197
+ }
1105
1198
  }
1106
1199
 
1107
1200
  export function ErrorComponent({ error }: { error: any }) {