@tanstack/router-devtools-core 1.114.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 (100) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +5 -0
  3. package/dist/cjs/AgeTicker.cjs +47 -0
  4. package/dist/cjs/AgeTicker.cjs.map +1 -0
  5. package/dist/cjs/AgeTicker.d.cts +6 -0
  6. package/dist/cjs/BaseTanStackRouterDevtoolsPanel.cjs +505 -0
  7. package/dist/cjs/BaseTanStackRouterDevtoolsPanel.cjs.map +1 -0
  8. package/dist/cjs/BaseTanStackRouterDevtoolsPanel.d.cts +34 -0
  9. package/dist/cjs/Explorer.cjs +307 -0
  10. package/dist/cjs/Explorer.cjs.map +1 -0
  11. package/dist/cjs/Explorer.d.cts +43 -0
  12. package/dist/cjs/FloatingTanStackRouterDevtools.cjs +195 -0
  13. package/dist/cjs/FloatingTanStackRouterDevtools.cjs.map +1 -0
  14. package/dist/cjs/FloatingTanStackRouterDevtools.d.cts +48 -0
  15. package/dist/cjs/TanStackRouterDevtoolsCore.cjs +99 -0
  16. package/dist/cjs/TanStackRouterDevtoolsCore.cjs.map +1 -0
  17. package/dist/cjs/TanStackRouterDevtoolsCore.d.cts +55 -0
  18. package/dist/cjs/TanStackRouterDevtoolsPanelCore.cjs +99 -0
  19. package/dist/cjs/TanStackRouterDevtoolsPanelCore.cjs.map +1 -0
  20. package/dist/cjs/TanStackRouterDevtoolsPanelCore.d.cts +43 -0
  21. package/dist/cjs/context.cjs +20 -0
  22. package/dist/cjs/context.cjs.map +1 -0
  23. package/dist/cjs/context.d.cts +13 -0
  24. package/dist/cjs/index.cjs +7 -0
  25. package/dist/cjs/index.cjs.map +1 -0
  26. package/dist/cjs/index.d.cts +2 -0
  27. package/dist/cjs/logo.cjs +92 -0
  28. package/dist/cjs/logo.cjs.map +1 -0
  29. package/dist/cjs/logo.d.cts +1 -0
  30. package/dist/cjs/theme.d.cts +34 -0
  31. package/dist/cjs/tokens.cjs +201 -0
  32. package/dist/cjs/tokens.cjs.map +1 -0
  33. package/dist/cjs/tokens.d.cts +298 -0
  34. package/dist/cjs/useLocalStorage.cjs +42 -0
  35. package/dist/cjs/useLocalStorage.cjs.map +1 -0
  36. package/dist/cjs/useLocalStorage.d.cts +2 -0
  37. package/dist/cjs/useMediaQuery.d.cts +2 -0
  38. package/dist/cjs/useStyles.cjs +582 -0
  39. package/dist/cjs/useStyles.cjs.map +1 -0
  40. package/dist/cjs/useStyles.d.cts +53 -0
  41. package/dist/cjs/utils.cjs +63 -0
  42. package/dist/cjs/utils.cjs.map +1 -0
  43. package/dist/cjs/utils.d.cts +25 -0
  44. package/dist/esm/AgeTicker.d.ts +6 -0
  45. package/dist/esm/AgeTicker.js +47 -0
  46. package/dist/esm/AgeTicker.js.map +1 -0
  47. package/dist/esm/BaseTanStackRouterDevtoolsPanel.d.ts +34 -0
  48. package/dist/esm/BaseTanStackRouterDevtoolsPanel.js +505 -0
  49. package/dist/esm/BaseTanStackRouterDevtoolsPanel.js.map +1 -0
  50. package/dist/esm/Explorer.d.ts +43 -0
  51. package/dist/esm/Explorer.js +290 -0
  52. package/dist/esm/Explorer.js.map +1 -0
  53. package/dist/esm/FloatingTanStackRouterDevtools.d.ts +48 -0
  54. package/dist/esm/FloatingTanStackRouterDevtools.js +195 -0
  55. package/dist/esm/FloatingTanStackRouterDevtools.js.map +1 -0
  56. package/dist/esm/TanStackRouterDevtoolsCore.d.ts +55 -0
  57. package/dist/esm/TanStackRouterDevtoolsCore.js +99 -0
  58. package/dist/esm/TanStackRouterDevtoolsCore.js.map +1 -0
  59. package/dist/esm/TanStackRouterDevtoolsPanelCore.d.ts +43 -0
  60. package/dist/esm/TanStackRouterDevtoolsPanelCore.js +99 -0
  61. package/dist/esm/TanStackRouterDevtoolsPanelCore.js.map +1 -0
  62. package/dist/esm/context.d.ts +13 -0
  63. package/dist/esm/context.js +20 -0
  64. package/dist/esm/context.js.map +1 -0
  65. package/dist/esm/index.d.ts +2 -0
  66. package/dist/esm/index.js +7 -0
  67. package/dist/esm/index.js.map +1 -0
  68. package/dist/esm/logo.d.ts +1 -0
  69. package/dist/esm/logo.js +92 -0
  70. package/dist/esm/logo.js.map +1 -0
  71. package/dist/esm/theme.d.ts +34 -0
  72. package/dist/esm/tokens.d.ts +298 -0
  73. package/dist/esm/tokens.js +201 -0
  74. package/dist/esm/tokens.js.map +1 -0
  75. package/dist/esm/useLocalStorage.d.ts +2 -0
  76. package/dist/esm/useLocalStorage.js +43 -0
  77. package/dist/esm/useLocalStorage.js.map +1 -0
  78. package/dist/esm/useMediaQuery.d.ts +2 -0
  79. package/dist/esm/useStyles.d.ts +53 -0
  80. package/dist/esm/useStyles.js +565 -0
  81. package/dist/esm/useStyles.js.map +1 -0
  82. package/dist/esm/utils.d.ts +25 -0
  83. package/dist/esm/utils.js +63 -0
  84. package/dist/esm/utils.js.map +1 -0
  85. package/package.json +71 -0
  86. package/src/AgeTicker.tsx +59 -0
  87. package/src/BaseTanStackRouterDevtoolsPanel.tsx +559 -0
  88. package/src/Explorer.tsx +339 -0
  89. package/src/FloatingTanStackRouterDevtools.tsx +280 -0
  90. package/src/TanStackRouterDevtoolsCore.tsx +139 -0
  91. package/src/TanStackRouterDevtoolsPanelCore.tsx +120 -0
  92. package/src/context.ts +24 -0
  93. package/src/index.tsx +2 -0
  94. package/src/logo.tsx +817 -0
  95. package/src/theme.tsx +36 -0
  96. package/src/tokens.ts +305 -0
  97. package/src/useLocalStorage.ts +52 -0
  98. package/src/useMediaQuery.ts +44 -0
  99. package/src/useStyles.tsx +589 -0
  100. package/src/utils.tsx +185 -0
@@ -0,0 +1,559 @@
1
+ import { clsx as cx } from 'clsx'
2
+ import { default as invariant } from 'tiny-invariant'
3
+ import { rootRouteId, trimPath } from '@tanstack/router-core'
4
+ import { createMemo } from 'solid-js'
5
+ import { useDevtoolsOnClose } from './context'
6
+ import { useStyles } from './useStyles'
7
+ import useLocalStorage from './useLocalStorage'
8
+ import { Explorer } from './Explorer'
9
+ import { getRouteStatusColor, getStatusColor, multiSortBy } from './utils'
10
+ import { AgeTicker } from './AgeTicker'
11
+ // import type { DevtoolsPanelOptions } from './TanStackRouterDevtoolsPanel'
12
+
13
+ import type {
14
+ AnyContext,
15
+ AnyRoute,
16
+ AnyRouter,
17
+ FileRouteTypes,
18
+ MakeRouteMatchUnion,
19
+ Route,
20
+ RouterState,
21
+ } from '@tanstack/router-core'
22
+ import type { Accessor, JSX } from 'solid-js'
23
+
24
+ export interface BaseDevtoolsPanelOptions {
25
+ /**
26
+ * The standard React style object used to style a component with inline styles
27
+ */
28
+ style?: Accessor<JSX.CSSProperties>
29
+ /**
30
+ * The standard React class property used to style a component with classes
31
+ */
32
+ className?: Accessor<string>
33
+ /**
34
+ * A boolean variable indicating whether the panel is open or closed
35
+ */
36
+ isOpen?: boolean
37
+ /**
38
+ * A function that toggles the open and close state of the panel
39
+ */
40
+ setIsOpen?: (isOpen: boolean) => void
41
+ /**
42
+ * Handles the opening and closing the devtools panel
43
+ */
44
+ handleDragStart?: (e: any) => void
45
+ /**
46
+ * A boolean variable indicating if the "lite" version of the library is being used
47
+ */
48
+ router: Accessor<AnyRouter>
49
+ routerState: Accessor<any>
50
+ /**
51
+ * Use this to attach the devtool's styles to specific element in the DOM.
52
+ */
53
+ shadowDOMTarget?: ShadowRoot
54
+ }
55
+
56
+ function Logo(props: any) {
57
+ const { className, ...rest } = props
58
+ const styles = useStyles()
59
+ return (
60
+ <button {...rest} class={cx(styles().logo, className ? className() : '')}>
61
+ <div class={styles().tanstackLogo}>TANSTACK</div>
62
+ <div class={styles().routerLogo}>TanStack Router v1</div>
63
+ </button>
64
+ )
65
+ }
66
+
67
+ function RouteComp({
68
+ routerState,
69
+ router,
70
+ route,
71
+ isRoot,
72
+ activeId,
73
+ setActiveId,
74
+ }: {
75
+ routerState: Accessor<
76
+ RouterState<
77
+ Route<
78
+ any,
79
+ '/',
80
+ '/',
81
+ string,
82
+ '__root__',
83
+ undefined,
84
+ {},
85
+ {},
86
+ AnyContext,
87
+ AnyContext,
88
+ {},
89
+ undefined,
90
+ any,
91
+ FileRouteTypes
92
+ >,
93
+ MakeRouteMatchUnion
94
+ >
95
+ >
96
+ router: Accessor<AnyRouter>
97
+ route: AnyRoute
98
+ isRoot?: boolean
99
+ activeId: Accessor<string | undefined>
100
+ setActiveId: (id: string) => void
101
+ }) {
102
+ const styles = useStyles()
103
+ const matches = createMemo(
104
+ () => routerState().pendingMatches || routerState().matches,
105
+ )
106
+ const match = createMemo(() =>
107
+ routerState().matches.find((d) => d.routeId === route.id),
108
+ )
109
+
110
+ const param = createMemo(() => {
111
+ try {
112
+ if (match()?.params) {
113
+ const p = match()?.params
114
+ const r: string = route.path || trimPath(route.id)
115
+ if (r.startsWith('$')) {
116
+ const trimmed = r.slice(1)
117
+
118
+ if (p[trimmed]) {
119
+ return `(${p[trimmed]})`
120
+ }
121
+ }
122
+ }
123
+ return ''
124
+ } catch (error) {
125
+ return ''
126
+ }
127
+ })
128
+
129
+ return (
130
+ <div>
131
+ <div
132
+ role="button"
133
+ aria-label={`Open match details for ${route.id}`}
134
+ onClick={() => {
135
+ if (match()) {
136
+ setActiveId(activeId() === route.id ? '' : route.id)
137
+ }
138
+ }}
139
+ class={cx(
140
+ styles().routesRowContainer(route.id === activeId(), !!match()),
141
+ )}
142
+ >
143
+ <div
144
+ class={cx(
145
+ styles().matchIndicator(getRouteStatusColor(matches(), route)),
146
+ )}
147
+ />
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>
157
+ </div>
158
+ {route.children?.length ? (
159
+ <div class={styles().nestedRouteRow(!!isRoot)}>
160
+ {[...(route.children as Array<AnyRoute>)]
161
+ .sort((a, b) => {
162
+ return a.rank - b.rank
163
+ })
164
+ .map((r) => (
165
+ <RouteComp
166
+ routerState={routerState}
167
+ router={router}
168
+ route={r}
169
+ activeId={activeId}
170
+ setActiveId={setActiveId}
171
+ />
172
+ ))}
173
+ </div>
174
+ ) : null}
175
+ </div>
176
+ )
177
+ }
178
+
179
+ export const BaseTanStackRouterDevtoolsPanel =
180
+ function BaseTanStackRouterDevtoolsPanel({
181
+ ...props
182
+ }: BaseDevtoolsPanelOptions): JSX.Element {
183
+ const {
184
+ isOpen = true,
185
+ setIsOpen,
186
+ handleDragStart,
187
+ router,
188
+ routerState,
189
+ shadowDOMTarget,
190
+ ...panelProps
191
+ } = props
192
+
193
+ const { onCloseClick } = useDevtoolsOnClose()
194
+ const styles = useStyles()
195
+ const { className, style, ...otherPanelProps } = panelProps
196
+
197
+ invariant(
198
+ router,
199
+ '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.',
200
+ )
201
+
202
+ // useStore(router.__store)
203
+
204
+ const [showMatches, setShowMatches] = useLocalStorage(
205
+ 'tanstackRouterDevtoolsShowMatches',
206
+ true,
207
+ )
208
+
209
+ const [activeId, setActiveId] = useLocalStorage(
210
+ 'tanstackRouterDevtoolsActiveRouteId',
211
+ '',
212
+ )
213
+
214
+ const activeMatch = createMemo(() => {
215
+ const matches = [
216
+ ...(routerState().pendingMatches ?? []),
217
+ ...routerState().matches,
218
+ ...routerState().cachedMatches,
219
+ ]
220
+ return matches.find(
221
+ (d) => d.routeId === activeId() || d.id === activeId(),
222
+ )
223
+ })
224
+
225
+ const hasSearch = createMemo(
226
+ () => Object.keys(routerState().location.search).length,
227
+ )
228
+
229
+ const explorerState = createMemo(() => {
230
+ return {
231
+ ...router(),
232
+ state: routerState(),
233
+ }
234
+ })
235
+
236
+ const routerExplorerValue = createMemo(() =>
237
+ Object.fromEntries(
238
+ multiSortBy(
239
+ Object.keys(explorerState()),
240
+ (
241
+ [
242
+ 'state',
243
+ 'routesById',
244
+ 'routesByPath',
245
+ 'flatRoutes',
246
+ 'options',
247
+ 'manifest',
248
+ ] as const
249
+ ).map((d) => (dd) => dd !== d),
250
+ )
251
+ .map((key) => [key, (explorerState() as any)[key]])
252
+ .filter(
253
+ (d) =>
254
+ typeof d[1] !== 'function' &&
255
+ ![
256
+ '__store',
257
+ 'basepath',
258
+ 'injectedHtml',
259
+ 'subscribers',
260
+ 'latestLoadPromise',
261
+ 'navigateTimeout',
262
+ 'resetNextScroll',
263
+ 'tempLocationKey',
264
+ 'latestLocation',
265
+ 'routeTree',
266
+ 'history',
267
+ ].includes(d[0]),
268
+ ),
269
+ ),
270
+ )
271
+ const activeMatchLoaderData = createMemo(() => activeMatch()?.loaderData)
272
+ const activeMatchValue = createMemo(() => activeMatch())
273
+ const locationSearchValue = createMemo(() => routerState().location.search)
274
+
275
+ return (
276
+ <div
277
+ class={cx(
278
+ styles().devtoolsPanel,
279
+ 'TanStackRouterDevtoolsPanel',
280
+ className ? className() : '',
281
+ )}
282
+ style={style ? style() : ''}
283
+ {...otherPanelProps}
284
+ >
285
+ {handleDragStart ? (
286
+ <div class={styles().dragHandle} onMouseDown={handleDragStart}></div>
287
+ ) : null}
288
+ <button
289
+ class={styles().panelCloseBtn}
290
+ onClick={(e: any) => {
291
+ if (setIsOpen) {
292
+ setIsOpen(false)
293
+ }
294
+ onCloseClick(e)
295
+ }}
296
+ >
297
+ <svg
298
+ xmlns="http://www.w3.org/2000/svg"
299
+ width="10"
300
+ height="6"
301
+ fill="none"
302
+ viewBox="0 0 10 6"
303
+ class={styles().panelCloseBtnIcon}
304
+ >
305
+ <path
306
+ stroke="currentColor"
307
+ stroke-linecap="round"
308
+ stroke-linejoin="round"
309
+ stroke-width="1.667"
310
+ d="M1 1l4 4 4-4"
311
+ ></path>
312
+ </svg>
313
+ </button>
314
+ <div class={styles().firstContainer}>
315
+ <div class={styles().row}>
316
+ <Logo
317
+ aria-hidden
318
+ onClick={(e: any) => {
319
+ if (setIsOpen) {
320
+ setIsOpen(false)
321
+ }
322
+ onCloseClick(e)
323
+ }}
324
+ />
325
+ </div>
326
+ <div class={styles().routerExplorerContainer}>
327
+ <div class={styles().routerExplorer}>
328
+ <Explorer
329
+ label="Router"
330
+ value={routerExplorerValue}
331
+ defaultExpanded={{
332
+ state: {} as any,
333
+ context: {} as any,
334
+ options: {} as any,
335
+ }}
336
+ filterSubEntries={(subEntries) => {
337
+ return subEntries.filter(
338
+ (d: any) => typeof d.value() !== 'function',
339
+ )
340
+ }}
341
+ />
342
+ </div>
343
+ </div>
344
+ </div>
345
+ <div class={styles().secondContainer}>
346
+ <div class={styles().matchesContainer}>
347
+ <div class={styles().detailsHeader}>
348
+ <span>Pathname</span>
349
+ {routerState().location.maskedLocation ? (
350
+ <div class={styles().maskedBadgeContainer}>
351
+ <span class={styles().maskedBadge}>masked</span>
352
+ </div>
353
+ ) : null}
354
+ </div>
355
+ <div class={styles().detailsContent}>
356
+ <code>{routerState().location.pathname}</code>
357
+ {routerState().location.maskedLocation ? (
358
+ <code class={styles().maskedLocation}>
359
+ {routerState().location.maskedLocation?.pathname}
360
+ </code>
361
+ ) : null}
362
+ </div>
363
+ <div class={styles().detailsHeader}>
364
+ <div class={styles().routeMatchesToggle}>
365
+ <button
366
+ type="button"
367
+ onClick={() => {
368
+ setShowMatches(false)
369
+ }}
370
+ disabled={!showMatches()}
371
+ class={cx(
372
+ styles().routeMatchesToggleBtn(!showMatches(), true),
373
+ )}
374
+ >
375
+ Routes
376
+ </button>
377
+ <button
378
+ type="button"
379
+ onClick={() => {
380
+ setShowMatches(true)
381
+ }}
382
+ disabled={showMatches()}
383
+ class={cx(
384
+ styles().routeMatchesToggleBtn(!!showMatches(), false),
385
+ )}
386
+ >
387
+ Matches
388
+ </button>
389
+ </div>
390
+ <div class={styles().detailsHeaderInfo}>
391
+ <div>age / staleTime / gcTime</div>
392
+ </div>
393
+ </div>
394
+ <div class={cx(styles().routesContainer)}>
395
+ {!showMatches() ? (
396
+ <RouteComp
397
+ routerState={routerState}
398
+ router={router}
399
+ route={router().routeTree}
400
+ isRoot
401
+ activeId={activeId}
402
+ setActiveId={setActiveId}
403
+ />
404
+ ) : (
405
+ <div>
406
+ {(routerState().pendingMatches?.length
407
+ ? routerState().pendingMatches
408
+ : routerState().matches
409
+ )?.map((match: any, i: any) => {
410
+ return (
411
+ <div
412
+ role="button"
413
+ aria-label={`Open match details for ${match.id}`}
414
+ onClick={() =>
415
+ setActiveId(activeId() === match.id ? '' : match.id)
416
+ }
417
+ class={cx(styles().matchRow(match === activeMatch()))}
418
+ >
419
+ <div
420
+ class={cx(
421
+ styles().matchIndicator(getStatusColor(match)),
422
+ )}
423
+ />
424
+
425
+ <code
426
+ class={styles().matchID}
427
+ >{`${match.routeId === rootRouteId ? rootRouteId : match.pathname}`}</code>
428
+ <AgeTicker match={match} router={router} />
429
+ </div>
430
+ )
431
+ })}
432
+ </div>
433
+ )}
434
+ </div>
435
+ </div>
436
+ {routerState().cachedMatches.length ? (
437
+ <div class={styles().cachedMatchesContainer}>
438
+ <div class={styles().detailsHeader}>
439
+ <div>Cached Matches</div>
440
+ <div class={styles().detailsHeaderInfo}>
441
+ age / staleTime / gcTime
442
+ </div>
443
+ </div>
444
+ <div>
445
+ {routerState().cachedMatches.map((match: any) => {
446
+ return (
447
+ <div
448
+ role="button"
449
+ aria-label={`Open match details for ${match.id}`}
450
+ onClick={() =>
451
+ setActiveId(activeId() === match.id ? '' : match.id)
452
+ }
453
+ class={cx(styles().matchRow(match === activeMatch()))}
454
+ >
455
+ <div
456
+ class={cx(
457
+ styles().matchIndicator(getStatusColor(match)),
458
+ )}
459
+ />
460
+
461
+ <code class={styles().matchID}>{`${match.id}`}</code>
462
+
463
+ <AgeTicker match={match} router={router} />
464
+ </div>
465
+ )
466
+ })}
467
+ </div>
468
+ </div>
469
+ ) : null}
470
+ </div>
471
+ {activeMatch() && activeMatch()?.status ? (
472
+ <div class={styles().thirdContainer}>
473
+ <div class={styles().detailsHeader}>Match Details</div>
474
+ <div>
475
+ <div class={styles().matchDetails}>
476
+ <div
477
+ class={styles().matchStatus(
478
+ activeMatch()?.status,
479
+ activeMatch()?.isFetching,
480
+ )}
481
+ >
482
+ <div>
483
+ {activeMatch()?.status === 'success' &&
484
+ activeMatch()?.isFetching
485
+ ? 'fetching'
486
+ : activeMatch()?.status}
487
+ </div>
488
+ </div>
489
+ <div class={styles().matchDetailsInfoLabel}>
490
+ <div>ID:</div>
491
+ <div class={styles().matchDetailsInfo}>
492
+ <code>{activeMatch()?.id}</code>
493
+ </div>
494
+ </div>
495
+ <div class={styles().matchDetailsInfoLabel}>
496
+ <div>State:</div>
497
+ <div class={styles().matchDetailsInfo}>
498
+ {routerState().pendingMatches?.find(
499
+ (d: any) => d.id === activeMatch()?.id,
500
+ )
501
+ ? 'Pending'
502
+ : routerState().matches.find(
503
+ (d: any) => d.id === activeMatch()?.id,
504
+ )
505
+ ? 'Active'
506
+ : 'Cached'}
507
+ </div>
508
+ </div>
509
+ <div class={styles().matchDetailsInfoLabel}>
510
+ <div>Last Updated:</div>
511
+ <div class={styles().matchDetailsInfo}>
512
+ {activeMatch()?.updatedAt
513
+ ? new Date(activeMatch()?.updatedAt).toLocaleTimeString()
514
+ : 'N/A'}
515
+ </div>
516
+ </div>
517
+ </div>
518
+ </div>
519
+ {activeMatchLoaderData() ? (
520
+ <>
521
+ <div class={styles().detailsHeader}>Loader Data</div>
522
+ <div class={styles().detailsContent}>
523
+ <Explorer
524
+ label="loaderData"
525
+ value={activeMatchLoaderData}
526
+ defaultExpanded={{}}
527
+ />
528
+ </div>
529
+ </>
530
+ ) : null}
531
+ <div class={styles().detailsHeader}>Explorer</div>
532
+ <div class={styles().detailsContent}>
533
+ <Explorer
534
+ label="Match"
535
+ value={activeMatchValue}
536
+ defaultExpanded={{}}
537
+ />
538
+ </div>
539
+ </div>
540
+ ) : null}
541
+ {hasSearch() ? (
542
+ <div class={styles().fourthContainer}>
543
+ <div class={styles().detailsHeader}>Search Params</div>
544
+ <div class={styles().detailsContent}>
545
+ <Explorer
546
+ value={locationSearchValue}
547
+ defaultExpanded={Object.keys(
548
+ routerState().location.search,
549
+ ).reduce((obj: any, next) => {
550
+ obj[next] = {}
551
+ return obj
552
+ }, {})}
553
+ />
554
+ </div>
555
+ </div>
556
+ ) : null}
557
+ </div>
558
+ )
559
+ }