@tanstack/router-devtools-core 1.117.0 → 1.119.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.
@@ -1,7 +1,7 @@
1
1
  import { clsx as cx } from 'clsx'
2
2
  import { default as invariant } from 'tiny-invariant'
3
- import { rootRouteId, trimPath } from '@tanstack/router-core'
4
- import { createMemo } from 'solid-js'
3
+ import { interpolatePath, rootRouteId, trimPath } from '@tanstack/router-core'
4
+ import { Show, createMemo } from 'solid-js'
5
5
  import { useDevtoolsOnClose } from './context'
6
6
  import { useStyles } from './useStyles'
7
7
  import useLocalStorage from './useLocalStorage'
@@ -10,6 +10,7 @@ import { getRouteStatusColor, getStatusColor, multiSortBy } from './utils'
10
10
  import { AgeTicker } from './AgeTicker'
11
11
  // import type { DevtoolsPanelOptions } from './TanStackRouterDevtoolsPanel'
12
12
 
13
+ import { NavigateButton } from './NavigateButton'
13
14
  import type {
14
15
  AnyContext,
15
16
  AnyRoute,
@@ -64,6 +65,28 @@ function Logo(props: any) {
64
65
  )
65
66
  }
66
67
 
68
+ function NavigateLink(props: {
69
+ class?: string
70
+ left?: JSX.Element
71
+ children?: JSX.Element
72
+ right?: JSX.Element
73
+ }) {
74
+ return (
75
+ <div
76
+ class={props.class}
77
+ style={{
78
+ display: 'flex',
79
+ 'align-items': 'center',
80
+ width: '100%',
81
+ }}
82
+ >
83
+ {props.left}
84
+ <div style={{ 'flex-grow': 1, 'min-width': 0 }}>{props.children}</div>
85
+ {props.right}
86
+ </div>
87
+ )
88
+ }
89
+
67
90
  function RouteComp({
68
91
  routerState,
69
92
  router,
@@ -126,6 +149,30 @@ function RouteComp({
126
149
  }
127
150
  })
128
151
 
152
+ const navigationTarget = createMemo<string | undefined>(() => {
153
+ if (isRoot) return undefined // rootRouteId has no path
154
+ if (!route.path) return undefined // no path to navigate to
155
+
156
+ // flatten all params in the router state, into a single object
157
+ const allParams = Object.assign({}, ...matches().map((m) => m.params))
158
+
159
+ // interpolatePath is used by router-core to generate the `to`
160
+ // path for the navigate function in the router
161
+ const interpolated = interpolatePath({
162
+ path: route.fullPath,
163
+ params: allParams,
164
+ leaveWildcards: false,
165
+ leaveParams: false,
166
+ decodeCharMap: router().pathParamsDecodeCharMap,
167
+ })
168
+
169
+ // only if `interpolated` is not missing params, return the path since this
170
+ // means that all the params are present for a successful navigation
171
+ return !interpolated.isMissingParams
172
+ ? interpolated.interpolatedPath
173
+ : undefined
174
+ })
175
+
129
176
  return (
130
177
  <div>
131
178
  <div
@@ -145,15 +192,20 @@ function RouteComp({
145
192
  styles().matchIndicator(getRouteStatusColor(matches(), route)),
146
193
  )}
147
194
  />
148
- <div class={cx(styles().routesRow(!!match()))}>
149
- <div>
150
- <code class={styles().code}>
151
- {isRoot ? rootRouteId : route.path || trimPath(route.id)}{' '}
152
- </code>
153
- <code class={styles().routeParamInfo}>{param()}</code>
154
- </div>
155
- <AgeTicker match={match()} router={router} />
156
- </div>
195
+ <NavigateLink
196
+ class={cx(styles().routesRow(!!match()))}
197
+ left={
198
+ <Show when={navigationTarget()}>
199
+ {(navigate) => <NavigateButton to={navigate()} router={router} />}
200
+ </Show>
201
+ }
202
+ right={<AgeTicker match={match()} router={router} />}
203
+ >
204
+ <code class={styles().code}>
205
+ {isRoot ? rootRouteId : route.path || trimPath(route.id)}{' '}
206
+ </code>
207
+ <code class={styles().routeParamInfo}>{param()}</code>
208
+ </NavigateLink>
157
209
  </div>
158
210
  {route.children?.length ? (
159
211
  <div class={styles().nestedRouteRow(!!isRoot)}>
@@ -406,7 +458,7 @@ export const BaseTanStackRouterDevtoolsPanel =
406
458
  {(routerState().pendingMatches?.length
407
459
  ? routerState().pendingMatches
408
460
  : routerState().matches
409
- )?.map((match: any, i: any) => {
461
+ )?.map((match: any, _i: any) => {
410
462
  return (
411
463
  <div
412
464
  role="button"
@@ -421,11 +473,21 @@ export const BaseTanStackRouterDevtoolsPanel =
421
473
  styles().matchIndicator(getStatusColor(match)),
422
474
  )}
423
475
  />
424
-
425
- <code
426
- class={styles().matchID}
427
- >{`${match.routeId === rootRouteId ? rootRouteId : match.pathname}`}</code>
428
- <AgeTicker match={match} router={router} />
476
+ <NavigateLink
477
+ left={
478
+ <NavigateButton
479
+ to={match.pathname}
480
+ params={match.params}
481
+ search={match.search}
482
+ router={router}
483
+ />
484
+ }
485
+ right={<AgeTicker match={match} router={router} />}
486
+ >
487
+ <code class={styles().matchID}>
488
+ {`${match.routeId === rootRouteId ? rootRouteId : match.pathname}`}
489
+ </code>
490
+ </NavigateLink>
429
491
  </div>
430
492
  )
431
493
  })}
@@ -457,10 +519,19 @@ export const BaseTanStackRouterDevtoolsPanel =
457
519
  styles().matchIndicator(getStatusColor(match)),
458
520
  )}
459
521
  />
460
-
461
- <code class={styles().matchID}>{`${match.id}`}</code>
462
-
463
- <AgeTicker match={match} router={router} />
522
+ <NavigateLink
523
+ left={
524
+ <NavigateButton
525
+ to={match.pathname}
526
+ params={match.params}
527
+ search={match.search}
528
+ router={router}
529
+ />
530
+ }
531
+ right={<AgeTicker match={match} router={router} />}
532
+ >
533
+ <code class={styles().matchID}>{`${match.id}`}</code>
534
+ </NavigateLink>
464
535
  </div>
465
536
  )
466
537
  })}
@@ -0,0 +1,25 @@
1
+ import { useStyles } from './useStyles'
2
+ import type { AnyRouter, NavigateOptions } from '@tanstack/router-core'
3
+ import type { Accessor } from 'solid-js'
4
+
5
+ interface Props extends NavigateOptions {
6
+ router: Accessor<AnyRouter>
7
+ }
8
+
9
+ export function NavigateButton({ to, params, search, router }: Props) {
10
+ const styles = useStyles()
11
+
12
+ return (
13
+ <button
14
+ type="button"
15
+ title={`Navigate to ${to}`}
16
+ class={styles().navigateButton}
17
+ onClick={(e) => {
18
+ e.stopPropagation()
19
+ router().navigate({ to, params, search })
20
+ }}
21
+ >
22
+
23
+ </button>
24
+ )
25
+ }
package/src/useStyles.tsx CHANGED
@@ -370,6 +370,12 @@ const stylesFactory = (shadowDOMTarget?: ShadowRoot) => {
370
370
 
371
371
  return classes
372
372
  },
373
+ routesRowInner: css`
374
+ display: 'flex';
375
+ align-items: 'center';
376
+ flex-grow: 1;
377
+ min-width: 0;
378
+ `,
373
379
  routeParamInfo: css`
374
380
  color: ${colors.gray[400]};
375
381
  font-size: ${fontSize.xs};
@@ -385,6 +391,9 @@ const stylesFactory = (shadowDOMTarget?: ShadowRoot) => {
385
391
  code: css`
386
392
  font-size: ${fontSize.xs};
387
393
  line-height: ${lineHeight['xs']};
394
+ white-space: nowrap;
395
+ overflow: hidden;
396
+ text-overflow: ellipsis;
388
397
  `,
389
398
  matchesContainer: css`
390
399
  flex: 1 1 auto;
@@ -579,6 +588,22 @@ const stylesFactory = (shadowDOMTarget?: ShadowRoot) => {
579
588
  width: ${size[2]};
580
589
  height: ${size[2]};
581
590
  `,
591
+ navigateButton: css`
592
+ background: none;
593
+ border: none;
594
+ padding: 0 0 0 4px;
595
+ margin: 0;
596
+ color: ${colors.gray[400]};
597
+ font-size: ${fontSize.md};
598
+ cursor: pointer;
599
+ line-height: 1;
600
+ vertical-align: middle;
601
+ margin-right: 0.5ch;
602
+ flex-shrink: 0;
603
+ &:hover {
604
+ color: ${colors.blue[300]};
605
+ }
606
+ `,
582
607
  }
583
608
  }
584
609