@tanstack/router-devtools 0.0.1-beta.278 → 0.0.1-beta.280

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.
@@ -265,8 +265,8 @@ function TanStackRouterDevtools({
265
265
  function RouteComp({
266
266
  route,
267
267
  isRoot,
268
- activeRouteId,
269
- setActiveRouteId
268
+ activeId,
269
+ setActiveId
270
270
  }) {
271
271
  const routerState = reactRouter.useRouterState();
272
272
  const matches = routerState.status === 'pending' ? routerState.pendingMatches ?? [] : routerState.matches;
@@ -276,7 +276,7 @@ function RouteComp({
276
276
  "aria-label": `Open match details for ${route.id}`,
277
277
  onClick: () => {
278
278
  if (match) {
279
- setActiveRouteId(activeRouteId === route.id ? '' : route.id);
279
+ setActiveId(activeId === route.id ? '' : route.id);
280
280
  }
281
281
  },
282
282
  style: {
@@ -284,14 +284,15 @@ function RouteComp({
284
284
  borderBottom: `solid 1px ${theme.defaultTheme.grayAlt}`,
285
285
  cursor: match ? 'pointer' : 'default',
286
286
  alignItems: 'center',
287
- background: route.id === activeRouteId ? 'rgba(255,255,255,.1)' : undefined
287
+ background: route.id === activeId ? 'rgba(255,255,255,.1)' : undefined,
288
+ padding: '.25rem .5rem',
289
+ gap: '.5rem'
288
290
  }
289
291
  }, isRoot ? null : /*#__PURE__*/React.createElement("div", {
290
292
  style: {
291
293
  flex: '0 0 auto',
292
294
  width: '.7rem',
293
295
  height: '.7rem',
294
- margin: '.5rem .75rem',
295
296
  alignItems: 'center',
296
297
  justifyContent: 'center',
297
298
  fontWeight: 'bold',
@@ -300,21 +301,29 @@ function RouteComp({
300
301
  background: utils.getRouteStatusColor(matches, route, theme.defaultTheme),
301
302
  opacity: match ? 1 : 0.3
302
303
  }
303
- }), /*#__PURE__*/React.createElement(styledComponents.Code, {
304
+ }), /*#__PURE__*/React.createElement("div", {
304
305
  style: {
305
306
  flex: '1 0 auto',
306
307
  display: 'flex',
307
308
  justifyContent: 'space-between',
308
- padding: '.25rem .5rem .25rem 0',
309
- paddingLeft: isRoot ? '.5rem' : 0,
309
+ alignItems: 'center',
310
+ padding: isRoot ? '0 .25rem' : 0,
310
311
  opacity: match ? 1 : 0.7,
311
312
  fontSize: '0.7rem'
312
313
  }
313
- }, /*#__PURE__*/React.createElement("span", null, route.path || reactRouter.trimPath(route.id), " "), match ? /*#__PURE__*/React.createElement("span", {
314
+ }, /*#__PURE__*/React.createElement(styledComponents.Code, null, route.path || reactRouter.trimPath(route.id), " "), /*#__PURE__*/React.createElement("div", {
315
+ style: {
316
+ display: 'flex',
317
+ alignItems: 'center',
318
+ gap: '.5rem'
319
+ }
320
+ }, match ? /*#__PURE__*/React.createElement(styledComponents.Code, {
314
321
  style: {
315
322
  opacity: 0.3
316
323
  }
317
- }, match.id) : null)), route.children?.length ? /*#__PURE__*/React.createElement("div", {
324
+ }, match.id) : null, /*#__PURE__*/React.createElement(AgeTicker, {
325
+ match: match
326
+ })))), route.children?.length ? /*#__PURE__*/React.createElement("div", {
318
327
  style: {
319
328
  marginLeft: isRoot ? 0 : '1rem',
320
329
  borderLeft: isRoot ? '' : `solid 1px ${theme.defaultTheme.grayAlt}`
@@ -324,8 +333,8 @@ function RouteComp({
324
333
  }).map(r => /*#__PURE__*/React.createElement(RouteComp, {
325
334
  key: r.id,
326
335
  route: r,
327
- activeRouteId: activeRouteId,
328
- setActiveRouteId: setActiveRouteId
336
+ activeId: activeId,
337
+ setActiveId: setActiveId
329
338
  }))) : null);
330
339
  }
331
340
  const TanStackRouterDevtoolsPanel = /*#__PURE__*/React.forwardRef(function TanStackRouterDevtoolsPanel(props, ref) {
@@ -338,31 +347,19 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React.forwardRef(function TanSt
338
347
  } = props;
339
348
  const router = reactRouter.useRouter();
340
349
  const routerState = reactRouter.useRouterState();
341
- const matches = [...(routerState.pendingMatches ?? []), ...routerState.matches];
350
+ const matches = [...(routerState.pendingMatches ?? []), ...routerState.matches, ...routerState.cachedMatches];
342
351
  reactRouter.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.');
343
352
 
344
353
  // useStore(router.__store)
345
354
 
346
355
  const [showMatches, setShowMatches] = useLocalStorage.default('tanstackRouterDevtoolsShowMatches', true);
347
- const [activeRouteId, setActiveRouteId] = useLocalStorage.default('tanstackRouterDevtoolsActiveRouteId', '');
348
- const activeMatch = React.useMemo(() => matches.find(d => d.routeId === activeRouteId), [matches, activeRouteId]);
356
+ const [activeId, setActiveId] = useLocalStorage.default('tanstackRouterDevtoolsActiveRouteId', '');
357
+ const activeMatch = React.useMemo(() => matches.find(d => d.routeId === activeId || d.id === activeId), [matches, activeId]);
349
358
  const hasSearch = Object.keys(routerState.location.search || {}).length;
350
-
351
- // const preloadMatches = matches.filter((match) => {
352
- // return (
353
- // !state.matchIds.includes(match.id) &&
354
- // !state.pendingMatchIds.includes(match.id)
355
- // )
356
- // })
357
-
358
- // React.useEffect(() => {
359
- // const interval = setInterval(() => {
360
- // router.cleanMatches()
361
- // }, 1000)
362
-
363
- // return () => clearInterval(interval)
364
- // }, [router])
365
-
359
+ const explorerState = {
360
+ ...router,
361
+ state: router.state
362
+ };
366
363
  return /*#__PURE__*/React.createElement(theme.ThemeProvider, {
367
364
  theme: theme.defaultTheme
368
365
  }, /*#__PURE__*/React.createElement(styledComponents.Panel, _rollupPluginBabelHelpers.extends({
@@ -467,10 +464,11 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React.forwardRef(function TanSt
467
464
  }
468
465
  }, /*#__PURE__*/React.createElement(Explorer.default, {
469
466
  label: "Router",
470
- value: router,
467
+ value: Object.fromEntries(utils.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]))),
471
468
  defaultExpanded: {
472
469
  state: {},
473
- context: {}
470
+ context: {},
471
+ options: {}
474
472
  },
475
473
  filterSubEntries: subEntries => {
476
474
  return subEntries.filter(d => typeof d.value !== 'function');
@@ -534,9 +532,16 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React.forwardRef(function TanSt
534
532
  zIndex: 1,
535
533
  display: 'flex',
536
534
  alignItems: 'center',
535
+ justifyContent: 'space-between',
537
536
  gap: '.5rem',
538
537
  fontWeight: 'bold'
539
538
  }
539
+ }, /*#__PURE__*/React.createElement("div", {
540
+ style: {
541
+ display: 'flex',
542
+ alignItems: 'center',
543
+ gap: '.5rem'
544
+ }
540
545
  }, /*#__PURE__*/React.createElement("button", {
541
546
  type: "button",
542
547
  onClick: () => {
@@ -565,17 +570,23 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React.forwardRef(function TanSt
565
570
  color: 'inherit',
566
571
  cursor: 'pointer'
567
572
  }
568
- }, "Matches")), !showMatches ? /*#__PURE__*/React.createElement(RouteComp, {
573
+ }, "Matches")), /*#__PURE__*/React.createElement("div", {
574
+ style: {
575
+ opacity: 0.3,
576
+ fontSize: '0.7rem',
577
+ fontWeight: 'normal'
578
+ }
579
+ }, "age / staleTime / gcTime")), !showMatches ? /*#__PURE__*/React.createElement(RouteComp, {
569
580
  route: router.routeTree,
570
581
  isRoot: true,
571
- activeRouteId: activeRouteId,
572
- setActiveRouteId: setActiveRouteId
582
+ activeId: activeId,
583
+ setActiveId: setActiveId
573
584
  }) : /*#__PURE__*/React.createElement("div", null, (routerState.status === 'pending' ? routerState.pendingMatches ?? [] : routerState.matches).map((match, i) => {
574
585
  return /*#__PURE__*/React.createElement("div", {
575
- key: match.routeId || i,
586
+ key: match.id || i,
576
587
  role: "button",
577
- "aria-label": `Open match details for ${match.routeId}`,
578
- onClick: () => setActiveRouteId(activeRouteId === match.routeId ? '' : match.routeId),
588
+ "aria-label": `Open match details for ${match.id}`,
589
+ onClick: () => setActiveId(activeId === match.id ? '' : match.id),
579
590
  style: {
580
591
  display: 'flex',
581
592
  borderBottom: `solid 1px ${theme.defaultTheme.grayAlt}`,
@@ -601,8 +612,73 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React.forwardRef(function TanSt
601
612
  padding: '.5em',
602
613
  fontSize: '0.7rem'
603
614
  }
604
- }, `${match.id}`));
605
- })))), activeMatch ? /*#__PURE__*/React.createElement(styledComponents.ActivePanel, null, /*#__PURE__*/React.createElement("div", {
615
+ }, `${match.id}`), /*#__PURE__*/React.createElement(AgeTicker, {
616
+ match: match
617
+ }));
618
+ }))), routerState.cachedMatches?.length ? /*#__PURE__*/React.createElement("div", {
619
+ style: {
620
+ flex: '1 1 auto',
621
+ overflowY: 'auto',
622
+ maxHeight: '50%'
623
+ }
624
+ }, /*#__PURE__*/React.createElement("div", {
625
+ style: {
626
+ padding: '.5em',
627
+ background: theme.defaultTheme.backgroundAlt,
628
+ position: 'sticky',
629
+ top: 0,
630
+ zIndex: 1,
631
+ display: 'flex',
632
+ alignItems: 'center',
633
+ justifyContent: 'space-between',
634
+ gap: '.5rem',
635
+ fontWeight: 'bold'
636
+ }
637
+ }, /*#__PURE__*/React.createElement("div", null, "Cached Matches"), /*#__PURE__*/React.createElement("div", {
638
+ style: {
639
+ opacity: 0.3,
640
+ fontSize: '0.7rem',
641
+ fontWeight: 'normal'
642
+ }
643
+ }, "age / staleTime / gcTime")), /*#__PURE__*/React.createElement("div", null, routerState.cachedMatches.map(match => {
644
+ return /*#__PURE__*/React.createElement("div", {
645
+ key: match.id,
646
+ role: "button",
647
+ "aria-label": `Open match details for ${match.id}`,
648
+ onClick: () => setActiveId(activeId === match.id ? '' : match.id),
649
+ style: {
650
+ display: 'flex',
651
+ borderBottom: `solid 1px ${theme.defaultTheme.grayAlt}`,
652
+ cursor: 'pointer',
653
+ alignItems: 'center',
654
+ background: match === activeMatch ? 'rgba(255,255,255,.1)' : undefined,
655
+ fontSize: '0.7rem'
656
+ }
657
+ }, /*#__PURE__*/React.createElement("div", {
658
+ style: {
659
+ flex: '0 0 auto',
660
+ width: '.75rem',
661
+ height: '.75rem',
662
+ marginLeft: '.25rem',
663
+ background: utils.getStatusColor(match, theme.defaultTheme),
664
+ alignItems: 'center',
665
+ justifyContent: 'center',
666
+ fontWeight: 'bold',
667
+ borderRadius: '100%',
668
+ transition: 'all 1s ease-out'
669
+ }
670
+ }), /*#__PURE__*/React.createElement(styledComponents.Code, {
671
+ style: {
672
+ padding: '.5em'
673
+ }
674
+ }, `${match.id}`), /*#__PURE__*/React.createElement("div", {
675
+ style: {
676
+ marginLeft: 'auto'
677
+ }
678
+ }, /*#__PURE__*/React.createElement(AgeTicker, {
679
+ match: match
680
+ })));
681
+ }))) : null), activeMatch ? /*#__PURE__*/React.createElement(styledComponents.ActivePanel, null, /*#__PURE__*/React.createElement("div", {
606
682
  style: {
607
683
  padding: '.5em',
608
684
  background: theme.defaultTheme.backgroundAlt,
@@ -611,7 +687,11 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React.forwardRef(function TanSt
611
687
  bottom: 0,
612
688
  zIndex: 1
613
689
  }
614
- }, "Match Details"), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("table", null, /*#__PURE__*/React.createElement("tbody", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", {
690
+ }, "Match Details"), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("table", {
691
+ style: {
692
+ fontSize: '0.8rem'
693
+ }
694
+ }, /*#__PURE__*/React.createElement("tbody", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", {
615
695
  style: {
616
696
  opacity: '.5'
617
697
  }
@@ -623,7 +703,7 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React.forwardRef(function TanSt
623
703
  style: {
624
704
  opacity: '.5'
625
705
  }
626
- }, "Status"), /*#__PURE__*/React.createElement("td", null, activeMatch.status)), /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", {
706
+ }, "Status"), /*#__PURE__*/React.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.createElement("tr", null, /*#__PURE__*/React.createElement("td", {
627
707
  style: {
628
708
  opacity: '.5'
629
709
  }
@@ -693,6 +773,55 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React.forwardRef(function TanSt
693
773
  }, {})
694
774
  }))) : null));
695
775
  });
776
+ function AgeTicker({
777
+ match
778
+ }) {
779
+ const router = reactRouter.useRouter();
780
+ const rerender = React.useReducer(() => ({}), () => ({}))[1];
781
+ React.useEffect(() => {
782
+ const interval = setInterval(() => {
783
+ rerender();
784
+ }, 1000);
785
+ return () => {
786
+ clearInterval(interval);
787
+ };
788
+ }, []);
789
+ if (!match) {
790
+ return null;
791
+ }
792
+ const route = router.looseRoutesById[match?.routeId];
793
+ if (!route.options.loader) {
794
+ return null;
795
+ }
796
+ const age = Date.now() - match?.updatedAt;
797
+ const staleTime = route.options.staleTime ?? router.options.defaultStaleTime ?? 0;
798
+ const gcTime = route.options.gcTime ?? router.options.defaultGcTime ?? 30 * 60 * 1000;
799
+ return /*#__PURE__*/React.createElement("div", {
800
+ style: {
801
+ display: 'inline-flex',
802
+ alignItems: 'center',
803
+ gap: '.25rem',
804
+ color: age > staleTime ? theme.defaultTheme.warning : undefined
805
+ }
806
+ }, /*#__PURE__*/React.createElement("div", {
807
+ style: {}
808
+ }, formatTime(age)), /*#__PURE__*/React.createElement("div", null, "/"), /*#__PURE__*/React.createElement("div", null, formatTime(staleTime)), /*#__PURE__*/React.createElement("div", null, "/"), /*#__PURE__*/React.createElement("div", null, formatTime(gcTime)));
809
+ }
810
+ function formatTime(ms) {
811
+ const units = ['s', 'min', 'h', 'd'];
812
+ const values = [ms / 1000, ms / 60000, ms / 3600000, ms / 86400000];
813
+ let chosenUnitIndex = 0;
814
+ for (let i = 1; i < values.length; i++) {
815
+ if (values[i] < 1) break;
816
+ chosenUnitIndex = i;
817
+ }
818
+ const formatter = new Intl.NumberFormat(navigator.language, {
819
+ compactDisplay: 'short',
820
+ notation: 'compact',
821
+ maximumFractionDigits: 0
822
+ });
823
+ return formatter.format(values[chosenUnitIndex]) + units[chosenUnitIndex];
824
+ }
696
825
 
697
826
  exports.TanStackRouterDevtools = TanStackRouterDevtools;
698
827
  exports.TanStackRouterDevtoolsPanel = TanStackRouterDevtoolsPanel;