@tanstack/react-router-devtools 0.0.1-alpha.6 → 0.0.1-alpha.8

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-devtools",
3
3
  "author": "Tanner Linsley",
4
- "version": "0.0.1-alpha.6",
4
+ "version": "0.0.1-alpha.8",
5
5
  "license": "MIT",
6
6
  "repository": "tanstack/router",
7
7
  "homepage": "https://react-router.tanstack.com/",
@@ -35,7 +35,7 @@
35
35
  "src"
36
36
  ],
37
37
  "peerDependencies": {
38
- "@tanstack/react-router": "0.0.1-alpha.6",
38
+ "@tanstack/react-router": "0.0.1-alpha.8",
39
39
  "react": ">=16",
40
40
  "react-dom": ">=16"
41
41
  },
package/src/devtools.tsx CHANGED
@@ -3,7 +3,12 @@ import { Router, last } from '@tanstack/react-router'
3
3
  import { formatDistanceStrict } from 'date-fns'
4
4
 
5
5
  import useLocalStorage from './useLocalStorage'
6
- import { getStatusColor, useIsMounted, useSafeState } from './utils'
6
+ import {
7
+ getStatusColor,
8
+ multiSortBy,
9
+ useIsMounted,
10
+ useSafeState,
11
+ } from './utils'
7
12
  import { Panel, Button, Code, ActivePanel } from './styledComponents'
8
13
  import { ThemeProvider, defaultTheme as theme } from './theme'
9
14
  // import { getQueryStatusLabel, getQueryStatusColor } from './utils'
@@ -363,37 +368,12 @@ export const TanStackRouterDevtoolsPanel = React.forwardRef<
363
368
  router,
364
369
  ...panelProps
365
370
  } = props
366
- const routerExplorerValue = React.useMemo(() => {
367
- const {
368
- listeners,
369
- buildLocation,
370
- mount,
371
- update,
372
- buildNext,
373
- navigate,
374
- cancelMatches,
375
- loadLocation,
376
- cleanPreloadCache,
377
- loadRoute,
378
- matchRoutes,
379
- loadMatches,
380
- invalidateRoute,
381
- resolvePath,
382
- matchRoute,
383
- buildLink,
384
- __experimental__createSnapshot,
385
- destroy,
386
- ...rest
387
- } = router
388
-
389
- return rest
390
- }, [router.state])
391
371
 
392
372
  const rerender = React.useReducer(() => ({}), {})[1]
393
373
 
394
374
  React.useEffect(() => {
395
375
  let interval = setInterval(() => {
396
- router.cleanPreloadCache()
376
+ router.cleanMatchCache()
397
377
  // router.notify()
398
378
  rerender()
399
379
  }, 250)
@@ -408,30 +388,29 @@ export const TanStackRouterDevtoolsPanel = React.forwardRef<
408
388
  '',
409
389
  )
410
390
 
411
- const activeMatch = router.state.matches?.find(
412
- (d) => d.routeId === activeRouteId,
391
+ const [activeMatchId, setActiveMatchId] = useLocalStorage(
392
+ 'tanstackRouterDevtoolsActiveMatchId',
393
+ '',
413
394
  )
414
395
 
415
- const activeMatchExplorerValue = React.useMemo(() => {
416
- if (!activeMatch) {
417
- return {}
418
- }
419
-
420
- const {
421
- cancel,
422
- load,
423
- router,
424
- Link,
425
- MatchRoute,
426
- buildLink,
427
- linkProps,
428
- matchRoute,
429
- navigate,
430
- ...rest
431
- } = activeMatch
432
-
433
- return rest
434
- }, [activeMatch])
396
+ React.useEffect(() => {
397
+ setActiveMatchId('')
398
+ }, [activeRouteId])
399
+
400
+ const activeMatch =
401
+ Object.values(router.matchCache)?.find(
402
+ (d) => d.match.matchId === activeMatchId,
403
+ )?.match ?? router.state.matches?.find((d) => d.routeId === activeRouteId)
404
+
405
+ const matchCacheValues = multiSortBy(
406
+ Object.keys(router.matchCache)
407
+ .filter((key) => {
408
+ const cacheEntry = router.matchCache[key]!
409
+ return cacheEntry.gc > Date.now()
410
+ })
411
+ .map((key) => router.matchCache[key]!),
412
+ [(d) => (d.match.isFetching ? -1 : 1), (d) => -d.match.updatedAt!],
413
+ )
435
414
 
436
415
  return (
437
416
  <ThemeProvider theme={theme}>
@@ -550,11 +529,7 @@ export const TanStackRouterDevtoolsPanel = React.forwardRef<
550
529
  padding: '.5em',
551
530
  }}
552
531
  >
553
- <Explorer
554
- label="Router"
555
- value={routerExplorerValue}
556
- defaultExpanded={{}}
557
- />
532
+ <Explorer label="Router" value={router} defaultExpanded={{}} />
558
533
  </div>
559
534
  </div>
560
535
  </div>
@@ -578,7 +553,7 @@ export const TanStackRouterDevtoolsPanel = React.forwardRef<
578
553
  zIndex: 1,
579
554
  }}
580
555
  >
581
- Current Matches
556
+ Active Matches
582
557
  </div>
583
558
  {router.state.matches.map((match, i) => {
584
559
  return (
@@ -625,153 +600,165 @@ export const TanStackRouterDevtoolsPanel = React.forwardRef<
625
600
  </div>
626
601
  )
627
602
  })}
628
- <div
629
- style={{
630
- marginTop: '2rem',
631
- padding: '.5em',
632
- background: theme.backgroundAlt,
633
- position: 'sticky',
634
- top: 0,
635
- zIndex: 1,
636
- }}
637
- >
638
- Pending Matches
639
- </div>
640
- {router.state.pending?.matches.map((match, i) => {
641
- return (
603
+ {router.state.pending?.matches.length ? (
604
+ <>
642
605
  <div
643
- key={match.routeId || i}
644
- role="button"
645
- aria-label={`Open match details for ${match.routeId}`}
646
- onClick={() =>
647
- setActiveRouteId(
648
- activeRouteId === match.routeId ? '' : match.routeId,
649
- )
650
- }
651
606
  style={{
652
- display: 'flex',
653
- borderBottom: `solid 1px ${theme.grayAlt}`,
654
- cursor: 'pointer',
655
- background:
656
- match === activeMatch ? 'rgba(255,255,255,.1)' : undefined,
607
+ marginTop: '2rem',
608
+ padding: '.5em',
609
+ background: theme.backgroundAlt,
610
+ position: 'sticky',
611
+ top: 0,
612
+ zIndex: 1,
657
613
  }}
658
614
  >
659
- <div
660
- style={{
661
- flex: '0 0 auto',
662
- width: '1.3rem',
663
- height: '1.3rem',
664
- marginLeft: '.25rem',
665
- background: getStatusColor(match, theme),
666
- alignItems: 'center',
667
- justifyContent: 'center',
668
- fontWeight: 'bold',
669
- borderRadius: '.25rem',
670
- transition: 'all .2s ease-out',
671
- }}
672
- />
615
+ Pending Matches
616
+ </div>
617
+ {router.state.pending?.matches.map((match, i) => {
618
+ return (
619
+ <div
620
+ key={match.routeId || i}
621
+ role="button"
622
+ aria-label={`Open match details for ${match.routeId}`}
623
+ onClick={() =>
624
+ setActiveRouteId(
625
+ activeRouteId === match.routeId ? '' : match.routeId,
626
+ )
627
+ }
628
+ style={{
629
+ display: 'flex',
630
+ borderBottom: `solid 1px ${theme.grayAlt}`,
631
+ cursor: 'pointer',
632
+ background:
633
+ match === activeMatch
634
+ ? 'rgba(255,255,255,.1)'
635
+ : undefined,
636
+ }}
637
+ >
638
+ <div
639
+ style={{
640
+ flex: '0 0 auto',
641
+ width: '1.3rem',
642
+ height: '1.3rem',
643
+ marginLeft: '.25rem',
644
+ background: getStatusColor(match, theme),
645
+ alignItems: 'center',
646
+ justifyContent: 'center',
647
+ fontWeight: 'bold',
648
+ borderRadius: '.25rem',
649
+ transition: 'all .2s ease-out',
650
+ }}
651
+ />
673
652
 
674
- <Code
675
- style={{
676
- padding: '.5em',
653
+ <Code
654
+ style={{
655
+ padding: '.5em',
656
+ }}
657
+ >
658
+ {`${match.matchId}`}
659
+ </Code>
660
+ </div>
661
+ )
662
+ })}
663
+ </>
664
+ ) : null}
665
+ {matchCacheValues.length ? (
666
+ <>
667
+ <div
668
+ style={{
669
+ marginTop: '2rem',
670
+ padding: '.5em',
671
+ background: theme.backgroundAlt,
672
+ position: 'sticky',
673
+ top: 0,
674
+ bottom: 0,
675
+ zIndex: 1,
676
+ display: 'flex',
677
+ alignItems: 'center',
678
+ justifyContent: 'space-between',
679
+ }}
680
+ >
681
+ <div>Match Cache</div>
682
+ <Button
683
+ onClick={() => {
684
+ router.matchCache = {}
685
+ router.notify()
677
686
  }}
678
687
  >
679
- {`${match.matchId}`}
680
- </Code>
688
+ Clear
689
+ </Button>
681
690
  </div>
682
- )
683
- })}
684
- <div
685
- style={{
686
- marginTop: '2rem',
687
- padding: '.5em',
688
- background: theme.backgroundAlt,
689
- position: 'sticky',
690
- top: 0,
691
- zIndex: 1,
692
- }}
693
- >
694
- Preloading Matches
695
- </div>
696
- {Object.keys(router.preloadCache)
697
- .filter((key) => {
698
- const cacheEntry = router.preloadCache[key]!
699
- return (
700
- (cacheEntry.match.updatedAt ?? Date.now()) + cacheEntry.maxAge >
701
- Date.now()
702
- )
703
- })
704
- .map((key, i) => {
705
- const { match, maxAge } = router.preloadCache[key]!
706
-
707
- return (
708
- <div
709
- key={match.matchId || i}
710
- role="button"
711
- aria-label={`Open match details for ${match.matchId}`}
712
- onClick={() =>
713
- setActiveRouteId(
714
- activeRouteId === match.routeId ? '' : match.routeId,
715
- )
716
- }
717
- style={{
718
- display: 'flex',
719
- borderBottom: `solid 1px ${theme.grayAlt}`,
720
- cursor: 'pointer',
721
- background:
722
- match === activeMatch
723
- ? 'rgba(255,255,255,.1)'
724
- : undefined,
725
- }}
726
- >
691
+ {matchCacheValues.map((d, i) => {
692
+ const { match, gc } = d
693
+
694
+ return (
727
695
  <div
696
+ key={match.matchId || i}
697
+ role="button"
698
+ aria-label={`Open match details for ${match.matchId}`}
699
+ onClick={() =>
700
+ setActiveMatchId(
701
+ activeMatchId === match.matchId ? '' : match.matchId,
702
+ )
703
+ }
728
704
  style={{
729
705
  display: 'flex',
730
- flexDirection: 'column',
731
- padding: '.5rem',
732
- gap: '.3rem',
706
+ borderBottom: `solid 1px ${theme.grayAlt}`,
707
+ cursor: 'pointer',
708
+ background:
709
+ match === activeMatch
710
+ ? 'rgba(255,255,255,.1)'
711
+ : undefined,
733
712
  }}
734
713
  >
735
714
  <div
736
715
  style={{
737
716
  display: 'flex',
738
- alignItems: 'center',
739
- gap: '.5rem',
717
+ flexDirection: 'column',
718
+ padding: '.5rem',
719
+ gap: '.3rem',
740
720
  }}
741
721
  >
742
722
  <div
743
723
  style={{
744
- flex: '0 0 auto',
745
- width: '1.3rem',
746
- height: '1.3rem',
747
- background: getStatusColor(match, theme),
724
+ display: 'flex',
748
725
  alignItems: 'center',
749
- justifyContent: 'center',
750
- fontWeight: 'bold',
751
- borderRadius: '.25rem',
752
- transition: 'all .2s ease-out',
726
+ gap: '.5rem',
753
727
  }}
754
- />
755
- <Code>{`${match.matchId}`}</Code>
756
- </div>
757
- <span
758
- style={{
759
- opacity: '.5',
760
- }}
761
- >
762
- Expires{' '}
763
- {formatDistanceStrict(
764
- new Date(),
765
- new Date((match.updatedAt ?? Date.now()) + maxAge),
766
- {
728
+ >
729
+ <div
730
+ style={{
731
+ flex: '0 0 auto',
732
+ width: '1.3rem',
733
+ height: '1.3rem',
734
+ background: getStatusColor(match, theme),
735
+ alignItems: 'center',
736
+ justifyContent: 'center',
737
+ fontWeight: 'bold',
738
+ borderRadius: '.25rem',
739
+ transition: 'all .2s ease-out',
740
+ }}
741
+ />
742
+ <Code>{`${match.matchId}`}</Code>
743
+ </div>
744
+ <span
745
+ style={{
746
+ fontSize: '.7rem',
747
+ opacity: '.5',
748
+ lineHeight: 1,
749
+ }}
750
+ >
751
+ Expires{' '}
752
+ {formatDistanceStrict(new Date(gc), new Date(), {
767
753
  addSuffix: true,
768
- },
769
- )}
770
- </span>
754
+ })}
755
+ </span>
756
+ </div>
771
757
  </div>
772
- </div>
773
- )
774
- })}
758
+ )
759
+ })}
760
+ </>
761
+ ) : null}
775
762
  </div>
776
763
 
777
764
  {activeMatch ? (
@@ -782,6 +769,7 @@ export const TanStackRouterDevtoolsPanel = React.forwardRef<
782
769
  background: theme.backgroundAlt,
783
770
  position: 'sticky',
784
771
  top: 0,
772
+ bottom: 0,
785
773
  zIndex: 1,
786
774
  }}
787
775
  >
@@ -833,6 +821,7 @@ export const TanStackRouterDevtoolsPanel = React.forwardRef<
833
821
  padding: '.5em',
834
822
  position: 'sticky',
835
823
  top: 0,
824
+ bottom: 0,
836
825
  zIndex: 1,
837
826
  }}
838
827
  >
@@ -872,6 +861,7 @@ export const TanStackRouterDevtoolsPanel = React.forwardRef<
872
861
  padding: '.5em',
873
862
  position: 'sticky',
874
863
  top: 0,
864
+ bottom: 0,
875
865
  zIndex: 1,
876
866
  }}
877
867
  >
@@ -884,7 +874,7 @@ export const TanStackRouterDevtoolsPanel = React.forwardRef<
884
874
  >
885
875
  <Explorer
886
876
  label="Match"
887
- value={activeMatchExplorerValue}
877
+ value={activeMatch}
888
878
  defaultExpanded={{}}
889
879
  />
890
880
  </div>
@@ -907,10 +897,11 @@ export const TanStackRouterDevtoolsPanel = React.forwardRef<
907
897
  background: theme.backgroundAlt,
908
898
  position: 'sticky',
909
899
  top: 0,
900
+ bottom: 0,
910
901
  zIndex: 1,
911
902
  }}
912
903
  >
913
- Loader Data
904
+ All Loader Data
914
905
  </div>
915
906
  <div
916
907
  style={{
@@ -938,6 +929,7 @@ export const TanStackRouterDevtoolsPanel = React.forwardRef<
938
929
  background: theme.backgroundAlt,
939
930
  position: 'sticky',
940
931
  top: 0,
932
+ bottom: 0,
941
933
  zIndex: 1,
942
934
  }}
943
935
  >
package/src/utils.ts CHANGED
@@ -149,3 +149,33 @@ function scheduleMicrotask(callback: () => void) {
149
149
  }),
150
150
  )
151
151
  }
152
+
153
+ export function multiSortBy<T>(
154
+ arr: T[],
155
+ accessors: ((item: T) => any)[] = [(d) => d],
156
+ ): T[] {
157
+ return arr
158
+ .map((d, i) => [d, i] as const)
159
+ .sort(([a, ai], [b, bi]) => {
160
+ for (const accessor of accessors) {
161
+ const ao = accessor(a)
162
+ const bo = accessor(b)
163
+
164
+ if (typeof ao === 'undefined') {
165
+ if (typeof bo === 'undefined') {
166
+ continue
167
+ }
168
+ return 1
169
+ }
170
+
171
+ if (ao === bo) {
172
+ continue
173
+ }
174
+
175
+ return ao > bo ? 1 : -1
176
+ }
177
+
178
+ return ai - bi
179
+ })
180
+ .map(([d]) => d)
181
+ }