@tanstack/router-devtools 0.0.1-beta.279 → 0.0.1-beta.281

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.
@@ -207,6 +207,25 @@ function scheduleMicrotask(callback) {
207
207
  throw error;
208
208
  }));
209
209
  }
210
+ function multiSortBy(arr, accessors = [d => d]) {
211
+ return arr.map((d, i) => [d, i]).sort(([a, ai], [b, bi]) => {
212
+ for (const accessor of accessors) {
213
+ const ao = accessor(a);
214
+ const bo = accessor(b);
215
+ if (typeof ao === 'undefined') {
216
+ if (typeof bo === 'undefined') {
217
+ continue;
218
+ }
219
+ return 1;
220
+ }
221
+ if (ao === bo) {
222
+ continue;
223
+ }
224
+ return ao > bo ? 1 : -1;
225
+ }
226
+ return ai - bi;
227
+ }).map(([d]) => d);
228
+ }
210
229
 
211
230
  const Panel = styled('div', (_props, theme) => ({
212
231
  fontSize: 'clamp(12px, 1.5vw, 14px)',
@@ -680,8 +699,8 @@ function TanStackRouterDevtools({
680
699
  function RouteComp({
681
700
  route,
682
701
  isRoot,
683
- activeRouteId,
684
- setActiveRouteId
702
+ activeId,
703
+ setActiveId
685
704
  }) {
686
705
  const routerState = useRouterState();
687
706
  const matches = routerState.status === 'pending' ? routerState.pendingMatches ?? [] : routerState.matches;
@@ -691,7 +710,7 @@ function RouteComp({
691
710
  "aria-label": `Open match details for ${route.id}`,
692
711
  onClick: () => {
693
712
  if (match) {
694
- setActiveRouteId(activeRouteId === route.id ? '' : route.id);
713
+ setActiveId(activeId === route.id ? '' : route.id);
695
714
  }
696
715
  },
697
716
  style: {
@@ -699,14 +718,15 @@ function RouteComp({
699
718
  borderBottom: `solid 1px ${defaultTheme.grayAlt}`,
700
719
  cursor: match ? 'pointer' : 'default',
701
720
  alignItems: 'center',
702
- background: route.id === activeRouteId ? 'rgba(255,255,255,.1)' : undefined
721
+ background: route.id === activeId ? 'rgba(255,255,255,.1)' : undefined,
722
+ padding: '.25rem .5rem',
723
+ gap: '.5rem'
703
724
  }
704
725
  }, isRoot ? null : /*#__PURE__*/React__default.createElement("div", {
705
726
  style: {
706
727
  flex: '0 0 auto',
707
728
  width: '.7rem',
708
729
  height: '.7rem',
709
- margin: '.5rem .75rem',
710
730
  alignItems: 'center',
711
731
  justifyContent: 'center',
712
732
  fontWeight: 'bold',
@@ -715,21 +735,29 @@ function RouteComp({
715
735
  background: getRouteStatusColor(matches, route, defaultTheme),
716
736
  opacity: match ? 1 : 0.3
717
737
  }
718
- }), /*#__PURE__*/React__default.createElement(Code, {
738
+ }), /*#__PURE__*/React__default.createElement("div", {
719
739
  style: {
720
740
  flex: '1 0 auto',
721
741
  display: 'flex',
722
742
  justifyContent: 'space-between',
723
- padding: '.25rem .5rem .25rem 0',
724
- paddingLeft: isRoot ? '.5rem' : 0,
743
+ alignItems: 'center',
744
+ padding: isRoot ? '0 .25rem' : 0,
725
745
  opacity: match ? 1 : 0.7,
726
746
  fontSize: '0.7rem'
727
747
  }
728
- }, /*#__PURE__*/React__default.createElement("span", null, route.path || trimPath(route.id), " "), match ? /*#__PURE__*/React__default.createElement("span", {
748
+ }, /*#__PURE__*/React__default.createElement(Code, null, route.path || trimPath(route.id), " "), /*#__PURE__*/React__default.createElement("div", {
749
+ style: {
750
+ display: 'flex',
751
+ alignItems: 'center',
752
+ gap: '.5rem'
753
+ }
754
+ }, match ? /*#__PURE__*/React__default.createElement(Code, {
729
755
  style: {
730
756
  opacity: 0.3
731
757
  }
732
- }, match.id) : null)), route.children?.length ? /*#__PURE__*/React__default.createElement("div", {
758
+ }, match.id) : null, /*#__PURE__*/React__default.createElement(AgeTicker, {
759
+ match: match
760
+ })))), route.children?.length ? /*#__PURE__*/React__default.createElement("div", {
733
761
  style: {
734
762
  marginLeft: isRoot ? 0 : '1rem',
735
763
  borderLeft: isRoot ? '' : `solid 1px ${defaultTheme.grayAlt}`
@@ -739,8 +767,8 @@ function RouteComp({
739
767
  }).map(r => /*#__PURE__*/React__default.createElement(RouteComp, {
740
768
  key: r.id,
741
769
  route: r,
742
- activeRouteId: activeRouteId,
743
- setActiveRouteId: setActiveRouteId
770
+ activeId: activeId,
771
+ setActiveId: setActiveId
744
772
  }))) : null);
745
773
  }
746
774
  const TanStackRouterDevtoolsPanel = /*#__PURE__*/React__default.forwardRef(function TanStackRouterDevtoolsPanel(props, ref) {
@@ -753,31 +781,19 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React__default.forwardRef(funct
753
781
  } = props;
754
782
  const router = useRouter();
755
783
  const routerState = useRouterState();
756
- const matches = [...(routerState.pendingMatches ?? []), ...routerState.matches];
784
+ const matches = [...(routerState.pendingMatches ?? []), ...routerState.matches, ...routerState.cachedMatches];
757
785
  invariant(router, 'No router was found for the TanStack Router Devtools. Please place the devtools in the <RouterProvider> component tree or pass the router instance to the devtools manually.');
758
786
 
759
787
  // useStore(router.__store)
760
788
 
761
789
  const [showMatches, setShowMatches] = useLocalStorage('tanstackRouterDevtoolsShowMatches', true);
762
- const [activeRouteId, setActiveRouteId] = useLocalStorage('tanstackRouterDevtoolsActiveRouteId', '');
763
- const activeMatch = React__default.useMemo(() => matches.find(d => d.routeId === activeRouteId), [matches, activeRouteId]);
790
+ const [activeId, setActiveId] = useLocalStorage('tanstackRouterDevtoolsActiveRouteId', '');
791
+ const activeMatch = React__default.useMemo(() => matches.find(d => d.routeId === activeId || d.id === activeId), [matches, activeId]);
764
792
  const hasSearch = Object.keys(routerState.location.search || {}).length;
765
-
766
- // const preloadMatches = matches.filter((match) => {
767
- // return (
768
- // !state.matchIds.includes(match.id) &&
769
- // !state.pendingMatchIds.includes(match.id)
770
- // )
771
- // })
772
-
773
- // React.useEffect(() => {
774
- // const interval = setInterval(() => {
775
- // router.cleanMatches()
776
- // }, 1000)
777
-
778
- // return () => clearInterval(interval)
779
- // }, [router])
780
-
793
+ const explorerState = {
794
+ ...router,
795
+ state: router.state
796
+ };
781
797
  return /*#__PURE__*/React__default.createElement(ThemeProvider, {
782
798
  theme: defaultTheme
783
799
  }, /*#__PURE__*/React__default.createElement(Panel, _extends({
@@ -882,10 +898,11 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React__default.forwardRef(funct
882
898
  }
883
899
  }, /*#__PURE__*/React__default.createElement(Explorer, {
884
900
  label: "Router",
885
- value: router,
901
+ value: Object.fromEntries(multiSortBy(Object.keys(explorerState), ['state', 'routesById', 'routesByPath', 'flatRoutes', 'options'].map(d => dd => dd !== d)).map(key => [key, explorerState[key]]).filter(d => typeof d[1] !== 'function' && !['__store', 'basepath', 'injectedHtml', 'subscribers', 'latestLoadPromise', 'navigateTimeout', 'resetNextScroll', 'tempLocationKey', 'latestLocation', 'routeTree', 'history'].includes(d[0]))),
886
902
  defaultExpanded: {
887
903
  state: {},
888
- context: {}
904
+ context: {},
905
+ options: {}
889
906
  },
890
907
  filterSubEntries: subEntries => {
891
908
  return subEntries.filter(d => typeof d.value !== 'function');
@@ -949,9 +966,16 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React__default.forwardRef(funct
949
966
  zIndex: 1,
950
967
  display: 'flex',
951
968
  alignItems: 'center',
969
+ justifyContent: 'space-between',
952
970
  gap: '.5rem',
953
971
  fontWeight: 'bold'
954
972
  }
973
+ }, /*#__PURE__*/React__default.createElement("div", {
974
+ style: {
975
+ display: 'flex',
976
+ alignItems: 'center',
977
+ gap: '.5rem'
978
+ }
955
979
  }, /*#__PURE__*/React__default.createElement("button", {
956
980
  type: "button",
957
981
  onClick: () => {
@@ -980,17 +1004,23 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React__default.forwardRef(funct
980
1004
  color: 'inherit',
981
1005
  cursor: 'pointer'
982
1006
  }
983
- }, "Matches")), !showMatches ? /*#__PURE__*/React__default.createElement(RouteComp, {
1007
+ }, "Matches")), /*#__PURE__*/React__default.createElement("div", {
1008
+ style: {
1009
+ opacity: 0.3,
1010
+ fontSize: '0.7rem',
1011
+ fontWeight: 'normal'
1012
+ }
1013
+ }, "age / staleTime / gcTime")), !showMatches ? /*#__PURE__*/React__default.createElement(RouteComp, {
984
1014
  route: router.routeTree,
985
1015
  isRoot: true,
986
- activeRouteId: activeRouteId,
987
- setActiveRouteId: setActiveRouteId
1016
+ activeId: activeId,
1017
+ setActiveId: setActiveId
988
1018
  }) : /*#__PURE__*/React__default.createElement("div", null, (routerState.status === 'pending' ? routerState.pendingMatches ?? [] : routerState.matches).map((match, i) => {
989
1019
  return /*#__PURE__*/React__default.createElement("div", {
990
- key: match.routeId || i,
1020
+ key: match.id || i,
991
1021
  role: "button",
992
- "aria-label": `Open match details for ${match.routeId}`,
993
- onClick: () => setActiveRouteId(activeRouteId === match.routeId ? '' : match.routeId),
1022
+ "aria-label": `Open match details for ${match.id}`,
1023
+ onClick: () => setActiveId(activeId === match.id ? '' : match.id),
994
1024
  style: {
995
1025
  display: 'flex',
996
1026
  borderBottom: `solid 1px ${defaultTheme.grayAlt}`,
@@ -1016,8 +1046,73 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React__default.forwardRef(funct
1016
1046
  padding: '.5em',
1017
1047
  fontSize: '0.7rem'
1018
1048
  }
1019
- }, `${match.id}`));
1020
- })))), activeMatch ? /*#__PURE__*/React__default.createElement(ActivePanel, null, /*#__PURE__*/React__default.createElement("div", {
1049
+ }, `${match.id}`), /*#__PURE__*/React__default.createElement(AgeTicker, {
1050
+ match: match
1051
+ }));
1052
+ }))), routerState.cachedMatches?.length ? /*#__PURE__*/React__default.createElement("div", {
1053
+ style: {
1054
+ flex: '1 1 auto',
1055
+ overflowY: 'auto',
1056
+ maxHeight: '50%'
1057
+ }
1058
+ }, /*#__PURE__*/React__default.createElement("div", {
1059
+ style: {
1060
+ padding: '.5em',
1061
+ background: defaultTheme.backgroundAlt,
1062
+ position: 'sticky',
1063
+ top: 0,
1064
+ zIndex: 1,
1065
+ display: 'flex',
1066
+ alignItems: 'center',
1067
+ justifyContent: 'space-between',
1068
+ gap: '.5rem',
1069
+ fontWeight: 'bold'
1070
+ }
1071
+ }, /*#__PURE__*/React__default.createElement("div", null, "Cached Matches"), /*#__PURE__*/React__default.createElement("div", {
1072
+ style: {
1073
+ opacity: 0.3,
1074
+ fontSize: '0.7rem',
1075
+ fontWeight: 'normal'
1076
+ }
1077
+ }, "age / staleTime / gcTime")), /*#__PURE__*/React__default.createElement("div", null, routerState.cachedMatches.map(match => {
1078
+ return /*#__PURE__*/React__default.createElement("div", {
1079
+ key: match.id,
1080
+ role: "button",
1081
+ "aria-label": `Open match details for ${match.id}`,
1082
+ onClick: () => setActiveId(activeId === match.id ? '' : match.id),
1083
+ style: {
1084
+ display: 'flex',
1085
+ borderBottom: `solid 1px ${defaultTheme.grayAlt}`,
1086
+ cursor: 'pointer',
1087
+ alignItems: 'center',
1088
+ background: match === activeMatch ? 'rgba(255,255,255,.1)' : undefined,
1089
+ fontSize: '0.7rem'
1090
+ }
1091
+ }, /*#__PURE__*/React__default.createElement("div", {
1092
+ style: {
1093
+ flex: '0 0 auto',
1094
+ width: '.75rem',
1095
+ height: '.75rem',
1096
+ marginLeft: '.25rem',
1097
+ background: getStatusColor(match, defaultTheme),
1098
+ alignItems: 'center',
1099
+ justifyContent: 'center',
1100
+ fontWeight: 'bold',
1101
+ borderRadius: '100%',
1102
+ transition: 'all 1s ease-out'
1103
+ }
1104
+ }), /*#__PURE__*/React__default.createElement(Code, {
1105
+ style: {
1106
+ padding: '.5em'
1107
+ }
1108
+ }, `${match.id}`), /*#__PURE__*/React__default.createElement("div", {
1109
+ style: {
1110
+ marginLeft: 'auto'
1111
+ }
1112
+ }, /*#__PURE__*/React__default.createElement(AgeTicker, {
1113
+ match: match
1114
+ })));
1115
+ }))) : null), activeMatch ? /*#__PURE__*/React__default.createElement(ActivePanel, null, /*#__PURE__*/React__default.createElement("div", {
1021
1116
  style: {
1022
1117
  padding: '.5em',
1023
1118
  background: defaultTheme.backgroundAlt,
@@ -1026,7 +1121,11 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React__default.forwardRef(funct
1026
1121
  bottom: 0,
1027
1122
  zIndex: 1
1028
1123
  }
1029
- }, "Match Details"), /*#__PURE__*/React__default.createElement("div", null, /*#__PURE__*/React__default.createElement("table", null, /*#__PURE__*/React__default.createElement("tbody", null, /*#__PURE__*/React__default.createElement("tr", null, /*#__PURE__*/React__default.createElement("td", {
1124
+ }, "Match Details"), /*#__PURE__*/React__default.createElement("div", null, /*#__PURE__*/React__default.createElement("table", {
1125
+ style: {
1126
+ fontSize: '0.8rem'
1127
+ }
1128
+ }, /*#__PURE__*/React__default.createElement("tbody", null, /*#__PURE__*/React__default.createElement("tr", null, /*#__PURE__*/React__default.createElement("td", {
1030
1129
  style: {
1031
1130
  opacity: '.5'
1032
1131
  }
@@ -1038,7 +1137,7 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React__default.forwardRef(funct
1038
1137
  style: {
1039
1138
  opacity: '.5'
1040
1139
  }
1041
- }, "Status"), /*#__PURE__*/React__default.createElement("td", null, activeMatch.status)), /*#__PURE__*/React__default.createElement("tr", null, /*#__PURE__*/React__default.createElement("td", {
1140
+ }, "Status"), /*#__PURE__*/React__default.createElement("td", null, routerState.pendingMatches?.find(d => d.id === activeMatch.id) ? 'Pending' : routerState.matches?.find(d => d.id === activeMatch.id) ? 'Active' : 'Cached', ' ', "- ", activeMatch.status)), /*#__PURE__*/React__default.createElement("tr", null, /*#__PURE__*/React__default.createElement("td", {
1042
1141
  style: {
1043
1142
  opacity: '.5'
1044
1143
  }
@@ -1108,6 +1207,55 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React__default.forwardRef(funct
1108
1207
  }, {})
1109
1208
  }))) : null));
1110
1209
  });
1210
+ function AgeTicker({
1211
+ match
1212
+ }) {
1213
+ const router = useRouter();
1214
+ const rerender = React__default.useReducer(() => ({}), () => ({}))[1];
1215
+ React__default.useEffect(() => {
1216
+ const interval = setInterval(() => {
1217
+ rerender();
1218
+ }, 1000);
1219
+ return () => {
1220
+ clearInterval(interval);
1221
+ };
1222
+ }, []);
1223
+ if (!match) {
1224
+ return null;
1225
+ }
1226
+ const route = router.looseRoutesById[match?.routeId];
1227
+ if (!route.options.loader) {
1228
+ return null;
1229
+ }
1230
+ const age = Date.now() - match?.updatedAt;
1231
+ const staleTime = route.options.staleTime ?? router.options.defaultStaleTime ?? 0;
1232
+ const gcTime = route.options.gcTime ?? router.options.defaultGcTime ?? 30 * 60 * 1000;
1233
+ return /*#__PURE__*/React__default.createElement("div", {
1234
+ style: {
1235
+ display: 'inline-flex',
1236
+ alignItems: 'center',
1237
+ gap: '.25rem',
1238
+ color: age > staleTime ? defaultTheme.warning : undefined
1239
+ }
1240
+ }, /*#__PURE__*/React__default.createElement("div", {
1241
+ style: {}
1242
+ }, formatTime(age)), /*#__PURE__*/React__default.createElement("div", null, "/"), /*#__PURE__*/React__default.createElement("div", null, formatTime(staleTime)), /*#__PURE__*/React__default.createElement("div", null, "/"), /*#__PURE__*/React__default.createElement("div", null, formatTime(gcTime)));
1243
+ }
1244
+ function formatTime(ms) {
1245
+ const units = ['s', 'min', 'h', 'd'];
1246
+ const values = [ms / 1000, ms / 60000, ms / 3600000, ms / 86400000];
1247
+ let chosenUnitIndex = 0;
1248
+ for (let i = 1; i < values.length; i++) {
1249
+ if (values[i] < 1) break;
1250
+ chosenUnitIndex = i;
1251
+ }
1252
+ const formatter = new Intl.NumberFormat(navigator.language, {
1253
+ compactDisplay: 'short',
1254
+ notation: 'compact',
1255
+ maximumFractionDigits: 0
1256
+ });
1257
+ return formatter.format(values[chosenUnitIndex]) + units[chosenUnitIndex];
1258
+ }
1111
1259
 
1112
1260
  export { TanStackRouterDevtools, TanStackRouterDevtoolsPanel };
1113
1261
  //# sourceMappingURL=index.js.map