@tanstack/router-devtools 0.0.1-beta.99 → 1.0.0

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 (38) hide show
  1. package/LICENSE +1 -1
  2. package/build/cjs/Explorer.js +10 -8
  3. package/build/cjs/Explorer.js.map +1 -1
  4. package/build/cjs/_virtual/_rollupPluginBabelHelpers.js +2 -4
  5. package/build/cjs/_virtual/_rollupPluginBabelHelpers.js.map +1 -1
  6. package/build/cjs/devtools.js +351 -106
  7. package/build/cjs/devtools.js.map +1 -1
  8. package/build/cjs/index.js +1 -3
  9. package/build/cjs/index.js.map +1 -1
  10. package/build/cjs/styledComponents.js +1 -4
  11. package/build/cjs/styledComponents.js.map +1 -1
  12. package/build/cjs/theme.js +10 -16
  13. package/build/cjs/theme.js.map +1 -1
  14. package/build/cjs/useLocalStorage.js +5 -9
  15. package/build/cjs/useLocalStorage.js.map +1 -1
  16. package/build/cjs/useMediaQuery.js +4 -8
  17. package/build/cjs/useMediaQuery.js.map +1 -1
  18. package/build/cjs/utils.js +36 -16
  19. package/build/cjs/utils.js.map +1 -1
  20. package/build/esm/index.js +342 -65
  21. package/build/esm/index.js.map +1 -1
  22. package/build/stats-html.html +3494 -2700
  23. package/build/stats-react.json +393 -147
  24. package/build/types/Explorer.d.ts +10 -4
  25. package/build/types/devtools.d.ts +1 -1
  26. package/build/types/index.d.ts +77 -1
  27. package/build/types/styledComponents.d.ts +3 -3
  28. package/build/types/theme.d.ts +13 -13
  29. package/build/types/utils.d.ts +3 -2
  30. package/build/umd/index.development.js +662 -145
  31. package/build/umd/index.development.js.map +1 -1
  32. package/build/umd/index.production.js +4 -14
  33. package/build/umd/index.production.js.map +1 -1
  34. package/package.json +2 -3
  35. package/src/Explorer.tsx +5 -0
  36. package/src/devtools.tsx +574 -287
  37. package/src/theme.tsx +6 -6
  38. package/src/utils.ts +14 -4
@@ -1,5 +1,5 @@
1
1
  /**
2
- * router-devtools
2
+ * @tanstack/router-devtools/src/index.tsx
3
3
  *
4
4
  * Copyright (c) TanStack
5
5
  *
@@ -10,24 +10,18 @@
10
10
  */
11
11
  'use strict';
12
12
 
13
- Object.defineProperty(exports, '__esModule', { value: true });
14
-
15
13
  var _rollupPluginBabelHelpers = require('./_virtual/_rollupPluginBabelHelpers.js');
16
14
  var React = require('react');
17
- var router = require('@tanstack/router');
15
+ var reactRouter = require('@tanstack/react-router');
18
16
  var useLocalStorage = require('./useLocalStorage.js');
19
17
  var utils = require('./utils.js');
20
18
  var styledComponents = require('./styledComponents.js');
21
19
  var theme = require('./theme.js');
22
20
  var Explorer = require('./Explorer.js');
23
21
 
24
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
25
-
26
- var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
27
-
28
22
  const isServer = typeof window === 'undefined';
29
23
  function Logo(props) {
30
- return /*#__PURE__*/React__default["default"].createElement("div", _rollupPluginBabelHelpers["extends"]({}, props, {
24
+ return /*#__PURE__*/React.createElement("div", _rollupPluginBabelHelpers.extends({}, props, {
31
25
  style: {
32
26
  ...(props.style ?? {}),
33
27
  display: 'flex',
@@ -37,11 +31,11 @@ function Logo(props) {
37
31
  fontWeight: 'bolder',
38
32
  lineHeight: '1'
39
33
  }
40
- }), /*#__PURE__*/React__default["default"].createElement("div", {
34
+ }), /*#__PURE__*/React.createElement("div", {
41
35
  style: {
42
36
  letterSpacing: '-0.05rem'
43
37
  }
44
- }, "TANSTACK"), /*#__PURE__*/React__default["default"].createElement("div", {
38
+ }, "TANSTACK"), /*#__PURE__*/React.createElement("div", {
45
39
  style: {
46
40
  backgroundImage: 'linear-gradient(to right, var(--tw-gradient-stops))',
47
41
  // @ts-ignore
@@ -64,10 +58,10 @@ function TanStackRouterDevtools({
64
58
  containerElement: Container = 'footer',
65
59
  router
66
60
  }) {
67
- const rootRef = React__default["default"].useRef(null);
68
- const panelRef = React__default["default"].useRef(null);
69
- const [isOpen, setIsOpen] = useLocalStorage["default"]('tanstackRouterDevtoolsOpen', initialIsOpen);
70
- const [devtoolsHeight, setDevtoolsHeight] = useLocalStorage["default"]('tanstackRouterDevtoolsHeight', null);
61
+ const rootRef = React.useRef(null);
62
+ const panelRef = React.useRef(null);
63
+ const [isOpen, setIsOpen] = useLocalStorage.default('tanstackRouterDevtoolsOpen', initialIsOpen);
64
+ const [devtoolsHeight, setDevtoolsHeight] = useLocalStorage.default('tanstackRouterDevtoolsHeight', null);
71
65
  const [isResolvedOpen, setIsResolvedOpen] = utils.useSafeState(false);
72
66
  const [isResizing, setIsResizing] = utils.useSafeState(false);
73
67
  const isMounted = utils.useIsMounted();
@@ -97,13 +91,13 @@ function TanStackRouterDevtools({
97
91
  document.addEventListener('mousemove', run);
98
92
  document.addEventListener('mouseup', unsub);
99
93
  };
100
- React__default["default"].useEffect(() => {
94
+ React.useEffect(() => {
101
95
  setIsResolvedOpen(isOpen ?? false);
102
96
  }, [isOpen, isResolvedOpen, setIsResolvedOpen]);
103
97
 
104
98
  // Toggle panel visibility before/after transition (depending on direction).
105
99
  // Prevents focusing in a closed panel.
106
- React__default["default"].useEffect(() => {
100
+ React.useEffect(() => {
107
101
  const ref = panelRef.current;
108
102
  if (ref) {
109
103
  const handlePanelTransitionStart = () => {
@@ -125,7 +119,7 @@ function TanStackRouterDevtools({
125
119
  }
126
120
  return;
127
121
  }, [isResolvedOpen]);
128
- React__default["default"][isServer ? 'useEffect' : 'useLayoutEffect'](() => {
122
+ React[isServer ? 'useEffect' : 'useLayoutEffect'](() => {
129
123
  if (isResolvedOpen) {
130
124
  const previousValue = rootRef.current?.parentElement?.style.paddingBottom;
131
125
  const run = () => {
@@ -164,12 +158,12 @@ function TanStackRouterDevtools({
164
158
 
165
159
  // Do not render on the server
166
160
  if (!isMounted()) return null;
167
- return /*#__PURE__*/React__default["default"].createElement(Container, {
161
+ return /*#__PURE__*/React.createElement(Container, {
168
162
  ref: rootRef,
169
163
  className: "TanStackRouterDevtools"
170
- }, /*#__PURE__*/React__default["default"].createElement(theme.ThemeProvider, {
164
+ }, /*#__PURE__*/React.createElement(theme.ThemeProvider, {
171
165
  theme: theme.defaultTheme
172
- }, /*#__PURE__*/React__default["default"].createElement(TanStackRouterDevtoolsPanel, _rollupPluginBabelHelpers["extends"]({
166
+ }, /*#__PURE__*/React.createElement(TanStackRouterDevtoolsPanel, _rollupPluginBabelHelpers.extends({
173
167
  ref: panelRef
174
168
  }, otherPanelProps, {
175
169
  router: router,
@@ -205,7 +199,7 @@ function TanStackRouterDevtools({
205
199
  isOpen: isResolvedOpen,
206
200
  setIsOpen: setIsOpen,
207
201
  handleDragStart: e => handleDragStart(panelRef.current, e)
208
- })), isResolvedOpen ? /*#__PURE__*/React__default["default"].createElement(styledComponents.Button, _rollupPluginBabelHelpers["extends"]({
202
+ })), isResolvedOpen ? /*#__PURE__*/React.createElement(styledComponents.Button, _rollupPluginBabelHelpers.extends({
209
203
  type: "button",
210
204
  "aria-label": "Close TanStack Router Devtools"
211
205
  }, otherCloseButtonProps, {
@@ -229,7 +223,7 @@ function TanStackRouterDevtools({
229
223
  }),
230
224
  ...closeButtonStyle
231
225
  }
232
- }), "Close") : null), !isResolvedOpen ? /*#__PURE__*/React__default["default"].createElement("button", _rollupPluginBabelHelpers["extends"]({
226
+ }), "Close") : null), !isResolvedOpen ? /*#__PURE__*/React.createElement("button", _rollupPluginBabelHelpers.extends({
233
227
  type: "button"
234
228
  }, otherToggleButtonProps, {
235
229
  "aria-label": "Open TanStack Router Devtools",
@@ -264,11 +258,86 @@ function TanStackRouterDevtools({
264
258
  }),
265
259
  ...toggleButtonStyle
266
260
  }
267
- }), /*#__PURE__*/React__default["default"].createElement(Logo, {
261
+ }), /*#__PURE__*/React.createElement(Logo, {
268
262
  "aria-hidden": true
269
263
  })) : null);
270
264
  }
271
- const TanStackRouterDevtoolsPanel = /*#__PURE__*/React__default["default"].forwardRef(function TanStackRouterDevtoolsPanel(props, ref) {
265
+ function RouteComp({
266
+ route,
267
+ isRoot,
268
+ activeId,
269
+ setActiveId
270
+ }) {
271
+ const routerState = reactRouter.useRouterState();
272
+ const matches = routerState.status === 'pending' ? routerState.pendingMatches ?? [] : routerState.matches;
273
+ const match = routerState.matches.find(d => d.routeId === route.id);
274
+ return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
275
+ role: "button",
276
+ "aria-label": `Open match details for ${route.id}`,
277
+ onClick: () => {
278
+ if (match) {
279
+ setActiveId(activeId === route.id ? '' : route.id);
280
+ }
281
+ },
282
+ style: {
283
+ display: 'flex',
284
+ borderBottom: `solid 1px ${theme.defaultTheme.grayAlt}`,
285
+ cursor: match ? 'pointer' : 'default',
286
+ alignItems: 'center',
287
+ background: route.id === activeId ? 'rgba(255,255,255,.1)' : undefined,
288
+ padding: '.25rem .5rem',
289
+ gap: '.5rem'
290
+ }
291
+ }, isRoot ? null : /*#__PURE__*/React.createElement("div", {
292
+ style: {
293
+ flex: '0 0 auto',
294
+ width: '.7rem',
295
+ height: '.7rem',
296
+ alignItems: 'center',
297
+ justifyContent: 'center',
298
+ fontWeight: 'bold',
299
+ borderRadius: '100%',
300
+ transition: 'all .2s ease-out',
301
+ background: utils.getRouteStatusColor(matches, route, theme.defaultTheme),
302
+ opacity: match ? 1 : 0.3
303
+ }
304
+ }), /*#__PURE__*/React.createElement("div", {
305
+ style: {
306
+ flex: '1 0 auto',
307
+ display: 'flex',
308
+ justifyContent: 'space-between',
309
+ alignItems: 'center',
310
+ padding: isRoot ? '0 .25rem' : 0,
311
+ opacity: match ? 1 : 0.7,
312
+ fontSize: '0.7rem'
313
+ }
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, {
321
+ style: {
322
+ opacity: 0.3
323
+ }
324
+ }, match.id) : null, /*#__PURE__*/React.createElement(AgeTicker, {
325
+ match: match
326
+ })))), route.children?.length ? /*#__PURE__*/React.createElement("div", {
327
+ style: {
328
+ marginLeft: isRoot ? 0 : '1rem',
329
+ borderLeft: isRoot ? '' : `solid 1px ${theme.defaultTheme.grayAlt}`
330
+ }
331
+ }, [...route.children].sort((a, b) => {
332
+ return a.rank - b.rank;
333
+ }).map(r => /*#__PURE__*/React.createElement(RouteComp, {
334
+ key: r.id,
335
+ route: r,
336
+ activeId: activeId,
337
+ setActiveId: setActiveId
338
+ }))) : null);
339
+ }
340
+ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React.forwardRef(function TanStackRouterDevtoolsPanel(props, ref) {
272
341
  const {
273
342
  isOpen = true,
274
343
  setIsOpen,
@@ -276,23 +345,27 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React__default["default"].forwa
276
345
  router: userRouter,
277
346
  ...panelProps
278
347
  } = props;
279
- const routerContextValue = React__default["default"].useContext(router.routerContext);
280
- const router$1 = userRouter ?? routerContextValue?.router;
281
- router.invariant(router$1, '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.');
282
- router.useStore(router$1.__store);
283
- const [activeRouteId, setActiveRouteId] = useLocalStorage["default"]('tanstackRouterDevtoolsActiveRouteId', '');
284
- const [activeMatchId, setActiveMatchId] = useLocalStorage["default"]('tanstackRouterDevtoolsActiveMatchId', '');
285
- React__default["default"].useEffect(() => {
286
- setActiveMatchId('');
287
- }, [activeRouteId]);
288
- const allMatches = React__default["default"].useMemo(() => [...Object.values(router$1.state.currentMatches), ...Object.values(router$1.state.pendingMatches ?? [])], [router$1.state.currentMatches, router$1.state.pendingMatches]);
289
- const activeMatch = allMatches?.find(d => d.id === activeMatchId) || allMatches?.find(d => d.route.id === activeRouteId);
290
- return /*#__PURE__*/React__default["default"].createElement(theme.ThemeProvider, {
348
+ const router = reactRouter.useRouter();
349
+ const routerState = reactRouter.useRouterState();
350
+ const matches = [...(routerState.pendingMatches ?? []), ...routerState.matches, ...routerState.cachedMatches];
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.');
352
+
353
+ // useStore(router.__store)
354
+
355
+ const [showMatches, setShowMatches] = useLocalStorage.default('tanstackRouterDevtoolsShowMatches', true);
356
+ const [activeId, setActiveId] = useLocalStorage.default('tanstackRouterDevtoolsActiveRouteId', '');
357
+ const activeMatch = React.useMemo(() => matches.find(d => d.routeId === activeId || d.id === activeId), [matches, activeId]);
358
+ const hasSearch = Object.keys(routerState.location.search || {}).length;
359
+ const explorerState = {
360
+ ...router,
361
+ state: router.state
362
+ };
363
+ return /*#__PURE__*/React.createElement(theme.ThemeProvider, {
291
364
  theme: theme.defaultTheme
292
- }, /*#__PURE__*/React__default["default"].createElement(styledComponents.Panel, _rollupPluginBabelHelpers["extends"]({
365
+ }, /*#__PURE__*/React.createElement(styledComponents.Panel, _rollupPluginBabelHelpers.extends({
293
366
  ref: ref,
294
367
  className: "TanStackRouterDevtoolsPanel"
295
- }, panelProps), /*#__PURE__*/React__default["default"].createElement("style", {
368
+ }, panelProps), /*#__PURE__*/React.createElement("style", {
296
369
  dangerouslySetInnerHTML: {
297
370
  __html: `
298
371
 
@@ -338,7 +411,7 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React__default["default"].forwa
338
411
 
339
412
  `
340
413
  }
341
- }), /*#__PURE__*/React__default["default"].createElement("div", {
414
+ }), /*#__PURE__*/React.createElement("div", {
342
415
  style: {
343
416
  position: 'absolute',
344
417
  left: 0,
@@ -350,7 +423,7 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React__default["default"].forwa
350
423
  zIndex: 100000
351
424
  },
352
425
  onMouseDown: handleDragStart
353
- }), /*#__PURE__*/React__default["default"].createElement("div", {
426
+ }), /*#__PURE__*/React.createElement("div", {
354
427
  style: {
355
428
  flex: '1 1 500px',
356
429
  minHeight: '40%',
@@ -360,7 +433,7 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React__default["default"].forwa
360
433
  display: 'flex',
361
434
  flexDirection: 'column'
362
435
  }
363
- }, /*#__PURE__*/React__default["default"].createElement("div", {
436
+ }, /*#__PURE__*/React.createElement("div", {
364
437
  style: {
365
438
  display: 'flex',
366
439
  justifyContent: 'start',
@@ -369,31 +442,38 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React__default["default"].forwa
369
442
  alignItems: 'center',
370
443
  background: theme.defaultTheme.backgroundAlt
371
444
  }
372
- }, /*#__PURE__*/React__default["default"].createElement(Logo, {
445
+ }, /*#__PURE__*/React.createElement(Logo, {
373
446
  "aria-hidden": true
374
- }), /*#__PURE__*/React__default["default"].createElement("div", {
447
+ }), /*#__PURE__*/React.createElement("div", {
375
448
  style: {
376
449
  fontSize: 'clamp(.8rem, 2vw, 1.3rem)',
377
450
  fontWeight: 'bold'
378
451
  }
379
- }, /*#__PURE__*/React__default["default"].createElement("span", {
452
+ }, /*#__PURE__*/React.createElement("span", {
380
453
  style: {
381
454
  fontWeight: 100
382
455
  }
383
- }, "Devtools"))), /*#__PURE__*/React__default["default"].createElement("div", {
456
+ }, "Devtools"))), /*#__PURE__*/React.createElement("div", {
384
457
  style: {
385
458
  overflowY: 'auto',
386
459
  flex: '1'
387
460
  }
388
- }, /*#__PURE__*/React__default["default"].createElement("div", {
461
+ }, /*#__PURE__*/React.createElement("div", {
389
462
  style: {
390
463
  padding: '.5em'
391
464
  }
392
- }, /*#__PURE__*/React__default["default"].createElement(Explorer["default"], {
465
+ }, /*#__PURE__*/React.createElement(Explorer.default, {
393
466
  label: "Router",
394
- value: router$1,
395
- defaultExpanded: {}
396
- })))), /*#__PURE__*/React__default["default"].createElement("div", {
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]))),
468
+ defaultExpanded: {
469
+ state: {},
470
+ context: {},
471
+ options: {}
472
+ },
473
+ filterSubEntries: subEntries => {
474
+ return subEntries.filter(d => typeof d.value !== 'function');
475
+ }
476
+ })))), /*#__PURE__*/React.createElement("div", {
397
477
  style: {
398
478
  flex: '1 1 500px',
399
479
  minHeight: '40%',
@@ -403,20 +483,110 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React__default["default"].forwa
403
483
  display: 'flex',
404
484
  flexDirection: 'column'
405
485
  }
406
- }, /*#__PURE__*/React__default["default"].createElement("div", {
486
+ }, /*#__PURE__*/React.createElement("div", {
487
+ style: {
488
+ flex: '1 1 auto',
489
+ overflowY: 'auto'
490
+ }
491
+ }, /*#__PURE__*/React.createElement("div", {
407
492
  style: {
408
493
  padding: '.5em',
409
494
  background: theme.defaultTheme.backgroundAlt,
410
495
  position: 'sticky',
411
496
  top: 0,
412
- zIndex: 1
497
+ zIndex: 1,
498
+ display: 'flex',
499
+ alignItems: 'center',
500
+ gap: '.5rem',
501
+ fontWeight: 'bold'
502
+ }
503
+ }, "Pathname", ' ', routerState.location.maskedLocation ? /*#__PURE__*/React.createElement("div", {
504
+ style: {
505
+ padding: '.1rem .5rem',
506
+ background: theme.defaultTheme.warning,
507
+ color: 'black',
508
+ borderRadius: '.5rem'
509
+ }
510
+ }, "Masked") : null), /*#__PURE__*/React.createElement("div", {
511
+ style: {
512
+ padding: '.5rem',
513
+ display: 'flex',
514
+ gap: '.5rem',
515
+ alignItems: 'center'
516
+ }
517
+ }, /*#__PURE__*/React.createElement("code", {
518
+ style: {
519
+ opacity: 0.6
520
+ }
521
+ }, routerState.location.pathname), routerState.location.maskedLocation ? /*#__PURE__*/React.createElement("code", {
522
+ style: {
523
+ color: theme.defaultTheme.warning,
524
+ fontWeight: 'bold'
525
+ }
526
+ }, routerState.location.maskedLocation.pathname) : null), /*#__PURE__*/React.createElement("div", {
527
+ style: {
528
+ padding: '.5em',
529
+ background: theme.defaultTheme.backgroundAlt,
530
+ position: 'sticky',
531
+ top: 0,
532
+ zIndex: 1,
533
+ display: 'flex',
534
+ alignItems: 'center',
535
+ justifyContent: 'space-between',
536
+ gap: '.5rem',
537
+ fontWeight: 'bold'
538
+ }
539
+ }, /*#__PURE__*/React.createElement("div", {
540
+ style: {
541
+ display: 'flex',
542
+ alignItems: 'center',
543
+ gap: '.5rem'
544
+ }
545
+ }, /*#__PURE__*/React.createElement("button", {
546
+ type: "button",
547
+ onClick: () => {
548
+ setShowMatches(false);
549
+ },
550
+ disabled: !showMatches,
551
+ style: {
552
+ appearance: 'none',
553
+ opacity: showMatches ? 0.5 : 1,
554
+ border: 0,
555
+ background: 'transparent',
556
+ color: 'inherit',
557
+ cursor: 'pointer'
558
+ }
559
+ }, "Routes"), "/", /*#__PURE__*/React.createElement("button", {
560
+ type: "button",
561
+ onClick: () => {
562
+ setShowMatches(true);
563
+ },
564
+ disabled: showMatches,
565
+ style: {
566
+ appearance: 'none',
567
+ opacity: !showMatches ? 0.5 : 1,
568
+ border: 0,
569
+ background: 'transparent',
570
+ color: 'inherit',
571
+ cursor: 'pointer'
413
572
  }
414
- }, "Active Matches"), router$1.state.currentMatches.map((match, i) => {
415
- return /*#__PURE__*/React__default["default"].createElement("div", {
416
- key: match.route.id || i,
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, {
580
+ route: router.routeTree,
581
+ isRoot: true,
582
+ activeId: activeId,
583
+ setActiveId: setActiveId
584
+ }) : /*#__PURE__*/React.createElement("div", null, (routerState.status === 'pending' ? routerState.pendingMatches ?? [] : routerState.matches).map((match, i) => {
585
+ return /*#__PURE__*/React.createElement("div", {
586
+ key: match.id || i,
417
587
  role: "button",
418
- "aria-label": `Open match details for ${match.route.id}`,
419
- onClick: () => setActiveRouteId(activeRouteId === match.route.id ? '' : match.route.id),
588
+ "aria-label": `Open match details for ${match.id}`,
589
+ onClick: () => setActiveId(activeId === match.id ? '' : match.id),
420
590
  style: {
421
591
  display: 'flex',
422
592
  borderBottom: `solid 1px ${theme.defaultTheme.grayAlt}`,
@@ -424,7 +594,7 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React__default["default"].forwa
424
594
  alignItems: 'center',
425
595
  background: match === activeMatch ? 'rgba(255,255,255,.1)' : undefined
426
596
  }
427
- }, /*#__PURE__*/React__default["default"].createElement("div", {
597
+ }, /*#__PURE__*/React.createElement("div", {
428
598
  style: {
429
599
  flex: '0 0 auto',
430
600
  width: '1.3rem',
@@ -437,51 +607,78 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React__default["default"].forwa
437
607
  borderRadius: '.25rem',
438
608
  transition: 'all .2s ease-out'
439
609
  }
440
- }), /*#__PURE__*/React__default["default"].createElement(styledComponents.Code, {
610
+ }), /*#__PURE__*/React.createElement(styledComponents.Code, {
441
611
  style: {
442
- padding: '.5em'
612
+ padding: '.5em',
613
+ fontSize: '0.7rem'
443
614
  }
444
- }, `${match.id}`));
445
- }), router$1.state.pendingMatches?.length ? /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, /*#__PURE__*/React__default["default"].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", {
446
625
  style: {
447
- marginTop: '2rem',
448
626
  padding: '.5em',
449
627
  background: theme.defaultTheme.backgroundAlt,
450
628
  position: 'sticky',
451
629
  top: 0,
452
- zIndex: 1
630
+ zIndex: 1,
631
+ display: 'flex',
632
+ alignItems: 'center',
633
+ justifyContent: 'space-between',
634
+ gap: '.5rem',
635
+ fontWeight: 'bold'
453
636
  }
454
- }, "Pending Matches"), router$1.state.pendingMatches?.map((match, i) => {
455
- return /*#__PURE__*/React__default["default"].createElement("div", {
456
- key: match.route.id || i,
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,
457
646
  role: "button",
458
- "aria-label": `Open match details for ${match.route.id}`,
459
- onClick: () => setActiveRouteId(activeRouteId === match.route.id ? '' : match.route.id),
647
+ "aria-label": `Open match details for ${match.id}`,
648
+ onClick: () => setActiveId(activeId === match.id ? '' : match.id),
460
649
  style: {
461
650
  display: 'flex',
462
651
  borderBottom: `solid 1px ${theme.defaultTheme.grayAlt}`,
463
652
  cursor: 'pointer',
464
- background: match === activeMatch ? 'rgba(255,255,255,.1)' : undefined
653
+ alignItems: 'center',
654
+ background: match === activeMatch ? 'rgba(255,255,255,.1)' : undefined,
655
+ fontSize: '0.7rem'
465
656
  }
466
- }, /*#__PURE__*/React__default["default"].createElement("div", {
657
+ }, /*#__PURE__*/React.createElement("div", {
467
658
  style: {
468
659
  flex: '0 0 auto',
469
- width: '1.3rem',
470
- height: '1.3rem',
660
+ width: '.75rem',
661
+ height: '.75rem',
471
662
  marginLeft: '.25rem',
472
663
  background: utils.getStatusColor(match, theme.defaultTheme),
473
664
  alignItems: 'center',
474
665
  justifyContent: 'center',
475
666
  fontWeight: 'bold',
476
- borderRadius: '.25rem',
477
- transition: 'all .2s ease-out'
667
+ borderRadius: '100%',
668
+ transition: 'all 1s ease-out'
478
669
  }
479
- }), /*#__PURE__*/React__default["default"].createElement(styledComponents.Code, {
670
+ }), /*#__PURE__*/React.createElement(styledComponents.Code, {
480
671
  style: {
481
672
  padding: '.5em'
482
673
  }
483
- }, `${match.id}`));
484
- })) : null), activeMatch ? /*#__PURE__*/React__default["default"].createElement(styledComponents.ActivePanel, null, /*#__PURE__*/React__default["default"].createElement("div", {
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", {
485
682
  style: {
486
683
  padding: '.5em',
487
684
  background: theme.defaultTheme.backgroundAlt,
@@ -490,23 +687,27 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React__default["default"].forwa
490
687
  bottom: 0,
491
688
  zIndex: 1
492
689
  }
493
- }, "Match Details"), /*#__PURE__*/React__default["default"].createElement("div", null, /*#__PURE__*/React__default["default"].createElement("table", null, /*#__PURE__*/React__default["default"].createElement("tbody", null, /*#__PURE__*/React__default["default"].createElement("tr", null, /*#__PURE__*/React__default["default"].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", {
494
695
  style: {
495
696
  opacity: '.5'
496
697
  }
497
- }, "ID"), /*#__PURE__*/React__default["default"].createElement("td", null, /*#__PURE__*/React__default["default"].createElement(styledComponents.Code, {
698
+ }, "ID"), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(styledComponents.Code, {
498
699
  style: {
499
700
  lineHeight: '1.8em'
500
701
  }
501
- }, JSON.stringify(activeMatch.id, null, 2)))), /*#__PURE__*/React__default["default"].createElement("tr", null, /*#__PURE__*/React__default["default"].createElement("td", {
702
+ }, JSON.stringify(activeMatch.id, null, 2)))), /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", {
502
703
  style: {
503
704
  opacity: '.5'
504
705
  }
505
- }, "Status"), /*#__PURE__*/React__default["default"].createElement("td", null, activeMatch.state.status)), /*#__PURE__*/React__default["default"].createElement("tr", null, /*#__PURE__*/React__default["default"].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", {
506
707
  style: {
507
708
  opacity: '.5'
508
709
  }
509
- }, "Last Updated"), /*#__PURE__*/React__default["default"].createElement("td", null, activeMatch.state.updatedAt ? new Date(activeMatch.state.updatedAt).toLocaleTimeString() : 'N/A'))))), /*#__PURE__*/React__default["default"].createElement("div", {
710
+ }, "Last Updated"), /*#__PURE__*/React.createElement("td", null, activeMatch.updatedAt ? new Date(activeMatch.updatedAt).toLocaleTimeString() : 'N/A'))))), activeMatch.loaderData ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
510
711
  style: {
511
712
  background: theme.defaultTheme.backgroundAlt,
512
713
  padding: '.5em',
@@ -515,17 +716,15 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React__default["default"].forwa
515
716
  bottom: 0,
516
717
  zIndex: 1
517
718
  }
518
- }, "Actions"), /*#__PURE__*/React__default["default"].createElement("div", {
719
+ }, "Loader Data"), /*#__PURE__*/React.createElement("div", {
519
720
  style: {
520
- padding: '0.5em'
521
- }
522
- }, /*#__PURE__*/React__default["default"].createElement(styledComponents.Button, {
523
- type: "button",
524
- onClick: () => activeMatch.load(),
525
- style: {
526
- background: theme.defaultTheme.gray
721
+ padding: '.5em'
527
722
  }
528
- }, "Reload")), /*#__PURE__*/React__default["default"].createElement("div", {
723
+ }, /*#__PURE__*/React.createElement(Explorer.default, {
724
+ label: "loaderData",
725
+ value: activeMatch.loaderData,
726
+ defaultExpanded: {}
727
+ }))) : null, /*#__PURE__*/React.createElement("div", {
529
728
  style: {
530
729
  background: theme.defaultTheme.backgroundAlt,
531
730
  padding: '.5em',
@@ -534,15 +733,15 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React__default["default"].forwa
534
733
  bottom: 0,
535
734
  zIndex: 1
536
735
  }
537
- }, "Explorer"), /*#__PURE__*/React__default["default"].createElement("div", {
736
+ }, "Explorer"), /*#__PURE__*/React.createElement("div", {
538
737
  style: {
539
738
  padding: '.5em'
540
739
  }
541
- }, /*#__PURE__*/React__default["default"].createElement(Explorer["default"], {
740
+ }, /*#__PURE__*/React.createElement(Explorer.default, {
542
741
  label: "Match",
543
742
  value: activeMatch,
544
743
  defaultExpanded: {}
545
- }))) : null, /*#__PURE__*/React__default["default"].createElement("div", {
744
+ }))) : null, hasSearch ? /*#__PURE__*/React.createElement("div", {
546
745
  style: {
547
746
  flex: '1 1 500px',
548
747
  minHeight: '40%',
@@ -552,31 +751,77 @@ const TanStackRouterDevtoolsPanel = /*#__PURE__*/React__default["default"].forwa
552
751
  display: 'flex',
553
752
  flexDirection: 'column'
554
753
  }
555
- }, /*#__PURE__*/React__default["default"].createElement("div", {
754
+ }, /*#__PURE__*/React.createElement("div", {
556
755
  style: {
557
756
  padding: '.5em',
558
757
  background: theme.defaultTheme.backgroundAlt,
559
758
  position: 'sticky',
560
759
  top: 0,
561
760
  bottom: 0,
562
- zIndex: 1
761
+ zIndex: 1,
762
+ fontWeight: 'bold'
563
763
  }
564
- }, "Search Params"), /*#__PURE__*/React__default["default"].createElement("div", {
764
+ }, "Search Params"), /*#__PURE__*/React.createElement("div", {
565
765
  style: {
566
766
  padding: '.5em'
567
767
  }
568
- }, Object.keys(router.last(router$1.state.currentMatches)?.state.search || {}).length ? /*#__PURE__*/React__default["default"].createElement(Explorer["default"], {
569
- value: router.last(router$1.state.currentMatches)?.state.search || {},
570
- defaultExpanded: Object.keys(router.last(router$1.state.currentMatches)?.state.search || {}).reduce((obj, next) => {
768
+ }, /*#__PURE__*/React.createElement(Explorer.default, {
769
+ value: routerState.location.search || {},
770
+ defaultExpanded: Object.keys(routerState.location.search || {}).reduce((obj, next) => {
571
771
  obj[next] = {};
572
772
  return obj;
573
773
  }, {})
574
- }) : /*#__PURE__*/React__default["default"].createElement("em", {
774
+ }))) : null));
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", {
575
800
  style: {
576
- opacity: 0.5
801
+ display: 'inline-flex',
802
+ alignItems: 'center',
803
+ gap: '.25rem',
804
+ color: age > staleTime ? theme.defaultTheme.warning : undefined
577
805
  }
578
- }, '{ }')))));
579
- });
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
+ }
580
825
 
581
826
  exports.TanStackRouterDevtools = TanStackRouterDevtools;
582
827
  exports.TanStackRouterDevtoolsPanel = TanStackRouterDevtoolsPanel;