@tanstack/router-devtools 1.7.0 → 1.8.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 (70) hide show
  1. package/dist/cjs/Explorer.cjs +246 -0
  2. package/dist/cjs/Explorer.cjs.map +1 -0
  3. package/dist/cjs/devtools.cjs +1150 -0
  4. package/dist/cjs/devtools.cjs.map +1 -0
  5. package/dist/cjs/index.cjs +6 -0
  6. package/dist/cjs/index.cjs.map +1 -0
  7. package/dist/cjs/styledComponents.cjs +93 -0
  8. package/dist/cjs/styledComponents.cjs.map +1 -0
  9. package/dist/cjs/theme.cjs +28 -0
  10. package/dist/cjs/theme.cjs.map +1 -0
  11. package/dist/cjs/useLocalStorage.cjs +45 -0
  12. package/dist/cjs/useLocalStorage.cjs.map +1 -0
  13. package/dist/cjs/useMediaQuery.cjs +27 -0
  14. package/dist/cjs/useMediaQuery.cjs.map +1 -0
  15. package/dist/cjs/utils.cjs +110 -0
  16. package/dist/cjs/utils.cjs.map +1 -0
  17. package/dist/esm/Explorer.d.ts +53 -0
  18. package/dist/esm/Explorer.js +229 -0
  19. package/dist/esm/Explorer.js.map +1 -0
  20. package/dist/esm/devtools.d.ts +65 -0
  21. package/dist/esm/devtools.js +1150 -0
  22. package/{build/cjs → dist/esm}/devtools.js.map +1 -1
  23. package/dist/esm/index.d.ts +1 -0
  24. package/dist/esm/index.js +6 -0
  25. package/{build/cjs → dist/esm}/index.js.map +1 -1
  26. package/dist/esm/styledComponents.d.ts +7 -0
  27. package/dist/esm/styledComponents.js +93 -0
  28. package/{build/cjs → dist/esm}/styledComponents.js.map +1 -1
  29. package/dist/esm/theme.d.ts +34 -0
  30. package/dist/esm/theme.js +28 -0
  31. package/dist/esm/theme.js.map +1 -0
  32. package/dist/esm/useLocalStorage.d.ts +1 -0
  33. package/dist/esm/useLocalStorage.js +46 -0
  34. package/dist/esm/useLocalStorage.js.map +1 -0
  35. package/dist/esm/useMediaQuery.d.ts +1 -0
  36. package/dist/esm/useMediaQuery.js +28 -0
  37. package/{build/cjs → dist/esm}/useMediaQuery.js.map +1 -1
  38. package/dist/esm/utils.d.ts +23 -0
  39. package/dist/esm/utils.js +110 -0
  40. package/{build/cjs → dist/esm}/utils.js.map +1 -1
  41. package/package.json +40 -21
  42. package/build/cjs/Explorer.js +0 -218
  43. package/build/cjs/Explorer.js.map +0 -1
  44. package/build/cjs/_virtual/_rollupPluginBabelHelpers.js +0 -29
  45. package/build/cjs/_virtual/_rollupPluginBabelHelpers.js.map +0 -1
  46. package/build/cjs/devtools.js +0 -828
  47. package/build/cjs/index.js +0 -19
  48. package/build/cjs/styledComponents.js +0 -76
  49. package/build/cjs/theme.js +0 -45
  50. package/build/cjs/theme.js.map +0 -1
  51. package/build/cjs/useLocalStorage.js +0 -54
  52. package/build/cjs/useLocalStorage.js.map +0 -1
  53. package/build/cjs/useMediaQuery.js +0 -54
  54. package/build/cjs/utils.js +0 -131
  55. package/build/esm/index.js +0 -1265
  56. package/build/esm/index.js.map +0 -1
  57. package/build/stats-html.html +0 -4838
  58. package/build/stats-react.json +0 -706
  59. package/build/umd/index.development.js +0 -1598
  60. package/build/umd/index.development.js.map +0 -1
  61. package/build/umd/index.production.js +0 -22
  62. package/build/umd/index.production.js.map +0 -1
  63. /package/{build/types/Explorer.d.ts → dist/cjs/Explorer.d.cts} +0 -0
  64. /package/{build/types/devtools.d.ts → dist/cjs/devtools.d.cts} +0 -0
  65. /package/{build/types/index.d.ts → dist/cjs/index.d.cts} +0 -0
  66. /package/{build/types/styledComponents.d.ts → dist/cjs/styledComponents.d.cts} +0 -0
  67. /package/{build/types/theme.d.ts → dist/cjs/theme.d.cts} +0 -0
  68. /package/{build/types/useLocalStorage.d.ts → dist/cjs/useLocalStorage.d.cts} +0 -0
  69. /package/{build/types/useMediaQuery.d.ts → dist/cjs/useMediaQuery.d.cts} +0 -0
  70. /package/{build/types/utils.d.ts → dist/cjs/utils.d.cts} +0 -0
@@ -1,1265 +0,0 @@
1
- /**
2
- * @tanstack/router-devtools/src/index.tsx
3
- *
4
- * Copyright (c) TanStack
5
- *
6
- * This source code is licensed under the MIT license found in the
7
- * LICENSE.md file in the root directory of this source tree.
8
- *
9
- * @license MIT
10
- */
11
- import * as React from 'react';
12
- import React__default from 'react';
13
- import { useRouter, useRouterState, invariant, trimPath } from '@tanstack/react-router';
14
-
15
- function _extends() {
16
- _extends = Object.assign ? Object.assign.bind() : function (target) {
17
- for (var i = 1; i < arguments.length; i++) {
18
- var source = arguments[i];
19
- for (var key in source) {
20
- if (Object.prototype.hasOwnProperty.call(source, key)) {
21
- target[key] = source[key];
22
- }
23
- }
24
- }
25
- return target;
26
- };
27
- return _extends.apply(this, arguments);
28
- }
29
-
30
- const getItem = key => {
31
- try {
32
- const itemValue = localStorage.getItem(key);
33
- if (typeof itemValue === 'string') {
34
- return JSON.parse(itemValue);
35
- }
36
- return undefined;
37
- } catch {
38
- return undefined;
39
- }
40
- };
41
- function useLocalStorage(key, defaultValue) {
42
- const [value, setValue] = React__default.useState();
43
- React__default.useEffect(() => {
44
- const initialValue = getItem(key);
45
- if (typeof initialValue === 'undefined' || initialValue === null) {
46
- setValue(typeof defaultValue === 'function' ? defaultValue() : defaultValue);
47
- } else {
48
- setValue(initialValue);
49
- }
50
- }, [defaultValue, key]);
51
- const setter = React__default.useCallback(updater => {
52
- setValue(old => {
53
- let newVal = updater;
54
- if (typeof updater == 'function') {
55
- newVal = updater(old);
56
- }
57
- try {
58
- localStorage.setItem(key, JSON.stringify(newVal));
59
- } catch {}
60
- return newVal;
61
- });
62
- }, [key]);
63
- return [value, setter];
64
- }
65
-
66
- const defaultTheme = {
67
- background: '#222222',
68
- backgroundAlt: '#292929',
69
- foreground: 'white',
70
- gray: '#444',
71
- grayAlt: '#444',
72
- inputBackgroundColor: '#fff',
73
- inputTextColor: '#000',
74
- success: '#80cb00',
75
- danger: '#ff0085',
76
- active: '#0099ff',
77
- warning: '#ffb200'
78
- };
79
- const ThemeContext = /*#__PURE__*/React__default.createContext(defaultTheme);
80
- function ThemeProvider({
81
- theme,
82
- ...rest
83
- }) {
84
- return /*#__PURE__*/React__default.createElement(ThemeContext.Provider, _extends({
85
- value: theme
86
- }, rest));
87
- }
88
- function useTheme() {
89
- return React__default.useContext(ThemeContext);
90
- }
91
-
92
- function useMediaQuery(query) {
93
- // Keep track of the preference in state, start with the current match
94
- const [isMatch, setIsMatch] = React__default.useState(() => {
95
- if (typeof window !== 'undefined') {
96
- return window.matchMedia && window.matchMedia(query).matches;
97
- }
98
- return;
99
- });
100
-
101
- // Watch for changes
102
- React__default.useEffect(() => {
103
- if (typeof window !== 'undefined') {
104
- if (!window.matchMedia) {
105
- return;
106
- }
107
-
108
- // Create a matcher
109
- const matcher = window.matchMedia(query);
110
-
111
- // Create our handler
112
- const onChange = ({
113
- matches
114
- }) => setIsMatch(matches);
115
-
116
- // Listen for changes
117
- matcher.addListener(onChange);
118
- return () => {
119
- // Stop listening for changes
120
- matcher.removeListener(onChange);
121
- };
122
- }
123
- return;
124
- }, [isMatch, query, setIsMatch]);
125
- return isMatch;
126
- }
127
-
128
- const isServer$1 = typeof window === 'undefined';
129
- function getStatusColor(match, theme) {
130
- return match.status === 'pending' || match.isFetching ? theme.active : match.status === 'error' ? theme.danger : match.status === 'success' ? theme.success : theme.gray;
131
- }
132
- function getRouteStatusColor(matches, route, theme) {
133
- const found = matches.find(d => d.routeId === route.id);
134
- if (!found) return theme.gray;
135
- return getStatusColor(found, theme);
136
- }
137
- function styled(type, newStyles, queries = {}) {
138
- return /*#__PURE__*/React__default.forwardRef(({
139
- style,
140
- ...rest
141
- }, ref) => {
142
- const theme = useTheme();
143
- const mediaStyles = Object.entries(queries).reduce((current, [key, value]) => {
144
- // eslint-disable-next-line react-hooks/rules-of-hooks
145
- return useMediaQuery(key) ? {
146
- ...current,
147
- ...(typeof value === 'function' ? value(rest, theme) : value)
148
- } : current;
149
- }, {});
150
- return /*#__PURE__*/React__default.createElement(type, {
151
- ...rest,
152
- style: {
153
- ...(typeof newStyles === 'function' ? newStyles(rest, theme) : newStyles),
154
- ...style,
155
- ...mediaStyles
156
- },
157
- ref
158
- });
159
- });
160
- }
161
- function useIsMounted() {
162
- const mountedRef = React__default.useRef(false);
163
- const isMounted = React__default.useCallback(() => mountedRef.current, []);
164
- React__default[isServer$1 ? 'useEffect' : 'useLayoutEffect'](() => {
165
- mountedRef.current = true;
166
- return () => {
167
- mountedRef.current = false;
168
- };
169
- }, []);
170
- return isMounted;
171
- }
172
-
173
- /**
174
- * Displays a string regardless the type of the data
175
- * @param {unknown} value Value to be stringified
176
- */
177
- const displayValue = value => {
178
- const name = Object.getOwnPropertyNames(Object(value));
179
- const newValue = typeof value === 'bigint' ? `${value.toString()}n` : value;
180
- try {
181
- return JSON.stringify(newValue, name);
182
- } catch (e) {
183
- return `unable to stringify`;
184
- }
185
- };
186
-
187
- /**
188
- * This hook is a safe useState version which schedules state updates in microtasks
189
- * to prevent updating a component state while React is rendering different components
190
- * or when the component is not mounted anymore.
191
- */
192
- function useSafeState(initialState) {
193
- const isMounted = useIsMounted();
194
- const [state, setState] = React__default.useState(initialState);
195
- const safeSetState = React__default.useCallback(value => {
196
- scheduleMicrotask(() => {
197
- if (isMounted()) {
198
- setState(value);
199
- }
200
- });
201
- }, [isMounted]);
202
- return [state, safeSetState];
203
- }
204
-
205
- /**
206
- * Schedules a microtask.
207
- * This can be useful to schedule state updates after rendering.
208
- */
209
- function scheduleMicrotask(callback) {
210
- Promise.resolve().then(callback).catch(error => setTimeout(() => {
211
- throw error;
212
- }));
213
- }
214
- function multiSortBy(arr, accessors = [d => d]) {
215
- return arr.map((d, i) => [d, i]).sort(([a, ai], [b, bi]) => {
216
- for (const accessor of accessors) {
217
- const ao = accessor(a);
218
- const bo = accessor(b);
219
- if (typeof ao === 'undefined') {
220
- if (typeof bo === 'undefined') {
221
- continue;
222
- }
223
- return 1;
224
- }
225
- if (ao === bo) {
226
- continue;
227
- }
228
- return ao > bo ? 1 : -1;
229
- }
230
- return ai - bi;
231
- }).map(([d]) => d);
232
- }
233
-
234
- const Panel = styled('div', (_props, theme) => ({
235
- fontSize: 'clamp(12px, 1.5vw, 14px)',
236
- fontFamily: `sans-serif`,
237
- display: 'flex',
238
- backgroundColor: theme.background,
239
- color: theme.foreground
240
- }), {
241
- '(max-width: 700px)': {
242
- flexDirection: 'column'
243
- },
244
- '(max-width: 600px)': {
245
- fontSize: '.9em'
246
- // flexDirection: 'column',
247
- }
248
- });
249
- const ActivePanel = styled('div', () => ({
250
- flex: '1 1 500px',
251
- display: 'flex',
252
- flexDirection: 'column',
253
- overflow: 'auto',
254
- height: '100%'
255
- }), {
256
- '(max-width: 700px)': (_props, theme) => ({
257
- borderTop: `2px solid ${theme.gray}`
258
- })
259
- });
260
- const Button = styled('button', (props, theme) => ({
261
- appearance: 'none',
262
- fontSize: '.9em',
263
- fontWeight: 'bold',
264
- background: theme.gray,
265
- border: '0',
266
- borderRadius: '.3em',
267
- color: 'white',
268
- padding: '.5em',
269
- opacity: props.disabled ? '.5' : undefined,
270
- cursor: 'pointer'
271
- }));
272
-
273
- // export const QueryKeys = styled('span', {
274
- // display: 'inline-block',
275
- // fontSize: '0.9em',
276
- // })
277
-
278
- // export const QueryKey = styled('span', {
279
- // display: 'inline-flex',
280
- // alignItems: 'center',
281
- // padding: '.2em .4em',
282
- // fontWeight: 'bold',
283
- // textShadow: '0 0 10px black',
284
- // borderRadius: '.2em',
285
- // })
286
-
287
- const Code = styled('code', {
288
- fontSize: '.9em'
289
- });
290
-
291
- const Entry = styled('div', {
292
- fontFamily: 'Menlo, monospace',
293
- fontSize: '.7rem',
294
- lineHeight: '1.7',
295
- outline: 'none',
296
- wordBreak: 'break-word'
297
- });
298
- const Label = styled('span', {
299
- color: 'white'
300
- });
301
- const LabelButton = styled('button', {
302
- cursor: 'pointer',
303
- color: 'white'
304
- });
305
- const ExpandButton = styled('button', {
306
- cursor: 'pointer',
307
- color: 'inherit',
308
- font: 'inherit',
309
- outline: 'inherit',
310
- background: 'transparent',
311
- border: 'none',
312
- padding: 0
313
- });
314
- const Value = styled('span', (_props, theme) => ({
315
- color: theme.danger
316
- }));
317
- const SubEntries = styled('div', {
318
- marginLeft: '.1em',
319
- paddingLeft: '1em',
320
- borderLeft: '2px solid rgba(0,0,0,.15)'
321
- });
322
- const Info = styled('span', {
323
- color: 'grey',
324
- fontSize: '.7em'
325
- });
326
- const Expander = ({
327
- expanded,
328
- style = {}
329
- }) => /*#__PURE__*/React.createElement("span", {
330
- style: {
331
- display: 'inline-block',
332
- transition: 'all .1s ease',
333
- transform: `rotate(${expanded ? 90 : 0}deg) ${style.transform || ''}`,
334
- ...style
335
- }
336
- }, "\u25B6");
337
- /**
338
- * Chunk elements in the array by size
339
- *
340
- * when the array cannot be chunked evenly by size, the last chunk will be
341
- * filled with the remaining elements
342
- *
343
- * @example
344
- * chunkArray(['a','b', 'c', 'd', 'e'], 2) // returns [['a','b'], ['c', 'd'], ['e']]
345
- */
346
- function chunkArray(array, size) {
347
- if (size < 1) return [];
348
- let i = 0;
349
- const result = [];
350
- while (i < array.length) {
351
- result.push(array.slice(i, i + size));
352
- i = i + size;
353
- }
354
- return result;
355
- }
356
- const DefaultRenderer = ({
357
- handleEntry,
358
- label,
359
- value,
360
- subEntries = [],
361
- subEntryPages = [],
362
- type,
363
- expanded = false,
364
- toggleExpanded,
365
- pageSize,
366
- renderer
367
- }) => {
368
- const [expandedPages, setExpandedPages] = React.useState([]);
369
- const [valueSnapshot, setValueSnapshot] = React.useState(undefined);
370
- const refreshValueSnapshot = () => {
371
- setValueSnapshot(value());
372
- };
373
- return /*#__PURE__*/React.createElement(Entry, null, subEntryPages.length ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ExpandButton, {
374
- onClick: () => toggleExpanded()
375
- }, /*#__PURE__*/React.createElement(Expander, {
376
- expanded: expanded
377
- }), " ", label, ' ', /*#__PURE__*/React.createElement(Info, null, String(type).toLowerCase() === 'iterable' ? '(Iterable) ' : '', subEntries.length, " ", subEntries.length > 1 ? `items` : `item`)), expanded ? subEntryPages.length === 1 ? /*#__PURE__*/React.createElement(SubEntries, null, subEntries.map((entry, index) => handleEntry(entry))) : /*#__PURE__*/React.createElement(SubEntries, null, subEntryPages.map((entries, index) => /*#__PURE__*/React.createElement("div", {
378
- key: index
379
- }, /*#__PURE__*/React.createElement(Entry, null, /*#__PURE__*/React.createElement(LabelButton, {
380
- onClick: () => setExpandedPages(old => old.includes(index) ? old.filter(d => d !== index) : [...old, index])
381
- }, /*#__PURE__*/React.createElement(Expander, {
382
- expanded: expanded
383
- }), " [", index * pageSize, " ...", ' ', index * pageSize + pageSize - 1, "]"), expandedPages.includes(index) ? /*#__PURE__*/React.createElement(SubEntries, null, entries.map(entry => handleEntry(entry))) : null)))) : null) : type === 'function' ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Explorer, {
384
- renderer: renderer,
385
- label: /*#__PURE__*/React.createElement("button", {
386
- onClick: refreshValueSnapshot,
387
- style: {
388
- appearance: 'none',
389
- border: '0',
390
- background: 'transparent'
391
- }
392
- }, /*#__PURE__*/React.createElement(Label, null, label), " \uD83D\uDD04", ' '),
393
- value: valueSnapshot,
394
- defaultExpanded: {}
395
- })) : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Label, null, label, ":"), " ", /*#__PURE__*/React.createElement(Value, null, displayValue(value))));
396
- };
397
- function isIterable(x) {
398
- return Symbol.iterator in x;
399
- }
400
- function Explorer({
401
- value,
402
- defaultExpanded,
403
- renderer = DefaultRenderer,
404
- pageSize = 100,
405
- filterSubEntries,
406
- ...rest
407
- }) {
408
- const [expanded, setExpanded] = React.useState(Boolean(defaultExpanded));
409
- const toggleExpanded = React.useCallback(() => setExpanded(old => !old), []);
410
- let type = typeof value;
411
- let subEntries = [];
412
- const makeProperty = sub => {
413
- const subDefaultExpanded = defaultExpanded === true ? {
414
- [sub.label]: true
415
- } : defaultExpanded?.[sub.label];
416
- return {
417
- ...sub,
418
- defaultExpanded: subDefaultExpanded
419
- };
420
- };
421
- if (Array.isArray(value)) {
422
- type = 'array';
423
- subEntries = value.map((d, i) => makeProperty({
424
- label: i.toString(),
425
- value: d
426
- }));
427
- } else if (value !== null && typeof value === 'object' && isIterable(value) && typeof value[Symbol.iterator] === 'function') {
428
- type = 'Iterable';
429
- subEntries = Array.from(value, (val, i) => makeProperty({
430
- label: i.toString(),
431
- value: val
432
- }));
433
- } else if (typeof value === 'object' && value !== null) {
434
- type = 'object';
435
- subEntries = Object.entries(value).map(([key, val]) => makeProperty({
436
- label: key,
437
- value: val
438
- }));
439
- }
440
- subEntries = filterSubEntries ? filterSubEntries(subEntries) : subEntries;
441
- const subEntryPages = chunkArray(subEntries, pageSize);
442
- return renderer({
443
- handleEntry: entry => /*#__PURE__*/React.createElement(Explorer, _extends({
444
- key: entry.label,
445
- value: value,
446
- renderer: renderer,
447
- filterSubEntries: filterSubEntries
448
- }, rest, entry)),
449
- type,
450
- subEntries,
451
- subEntryPages,
452
- value,
453
- expanded,
454
- toggleExpanded,
455
- pageSize,
456
- ...rest
457
- });
458
- }
459
-
460
- const isServer = typeof window === 'undefined';
461
- function Logo(props) {
462
- return /*#__PURE__*/React__default.createElement("div", _extends({}, props, {
463
- style: {
464
- ...(props.style ?? {}),
465
- display: 'flex',
466
- alignItems: 'center',
467
- flexDirection: 'column',
468
- fontSize: '0.8rem',
469
- fontWeight: 'bolder',
470
- lineHeight: '1'
471
- }
472
- }), /*#__PURE__*/React__default.createElement("div", {
473
- style: {
474
- letterSpacing: '-0.05rem'
475
- }
476
- }, "TANSTACK"), /*#__PURE__*/React__default.createElement("div", {
477
- style: {
478
- backgroundImage: 'linear-gradient(to right, var(--tw-gradient-stops))',
479
- // @ts-ignore
480
- '--tw-gradient-from': '#84cc16',
481
- '--tw-gradient-stops': 'var(--tw-gradient-from), var(--tw-gradient-to)',
482
- '--tw-gradient-to': '#10b981',
483
- WebkitBackgroundClip: 'text',
484
- color: 'transparent',
485
- letterSpacing: '0.1rem',
486
- marginRight: '-0.2rem'
487
- }
488
- }, "ROUTER"));
489
- }
490
- function TanStackRouterDevtools({
491
- initialIsOpen,
492
- panelProps = {},
493
- closeButtonProps = {},
494
- toggleButtonProps = {},
495
- position = 'bottom-left',
496
- containerElement: Container = 'footer',
497
- router
498
- }) {
499
- const rootRef = React__default.useRef(null);
500
- const panelRef = React__default.useRef(null);
501
- const [isOpen, setIsOpen] = useLocalStorage('tanstackRouterDevtoolsOpen', initialIsOpen);
502
- const [devtoolsHeight, setDevtoolsHeight] = useLocalStorage('tanstackRouterDevtoolsHeight', null);
503
- const [isResolvedOpen, setIsResolvedOpen] = useSafeState(false);
504
- const [isResizing, setIsResizing] = useSafeState(false);
505
- const isMounted = useIsMounted();
506
- const handleDragStart = (panelElement, startEvent) => {
507
- if (startEvent.button !== 0) return; // Only allow left click for drag
508
-
509
- setIsResizing(true);
510
- const dragInfo = {
511
- originalHeight: panelElement?.getBoundingClientRect().height ?? 0,
512
- pageY: startEvent.pageY
513
- };
514
- const run = moveEvent => {
515
- const delta = dragInfo.pageY - moveEvent.pageY;
516
- const newHeight = dragInfo?.originalHeight + delta;
517
- setDevtoolsHeight(newHeight);
518
- if (newHeight < 70) {
519
- setIsOpen(false);
520
- } else {
521
- setIsOpen(true);
522
- }
523
- };
524
- const unsub = () => {
525
- setIsResizing(false);
526
- document.removeEventListener('mousemove', run);
527
- document.removeEventListener('mouseUp', unsub);
528
- };
529
- document.addEventListener('mousemove', run);
530
- document.addEventListener('mouseup', unsub);
531
- };
532
- React__default.useEffect(() => {
533
- setIsResolvedOpen(isOpen ?? false);
534
- }, [isOpen, isResolvedOpen, setIsResolvedOpen]);
535
-
536
- // Toggle panel visibility before/after transition (depending on direction).
537
- // Prevents focusing in a closed panel.
538
- React__default.useEffect(() => {
539
- const ref = panelRef.current;
540
- if (ref) {
541
- const handlePanelTransitionStart = () => {
542
- if (ref && isResolvedOpen) {
543
- ref.style.visibility = 'visible';
544
- }
545
- };
546
- const handlePanelTransitionEnd = () => {
547
- if (ref && !isResolvedOpen) {
548
- ref.style.visibility = 'hidden';
549
- }
550
- };
551
- ref.addEventListener('transitionstart', handlePanelTransitionStart);
552
- ref.addEventListener('transitionend', handlePanelTransitionEnd);
553
- return () => {
554
- ref.removeEventListener('transitionstart', handlePanelTransitionStart);
555
- ref.removeEventListener('transitionend', handlePanelTransitionEnd);
556
- };
557
- }
558
- return;
559
- }, [isResolvedOpen]);
560
- React__default[isServer ? 'useEffect' : 'useLayoutEffect'](() => {
561
- if (isResolvedOpen) {
562
- const previousValue = rootRef.current?.parentElement?.style.paddingBottom;
563
- const run = () => {
564
- const containerHeight = panelRef.current?.getBoundingClientRect().height;
565
- if (rootRef.current?.parentElement) {
566
- rootRef.current.parentElement.style.paddingBottom = `${containerHeight}px`;
567
- }
568
- };
569
- run();
570
- if (typeof window !== 'undefined') {
571
- window.addEventListener('resize', run);
572
- return () => {
573
- window.removeEventListener('resize', run);
574
- if (rootRef.current?.parentElement && typeof previousValue === 'string') {
575
- rootRef.current.parentElement.style.paddingBottom = previousValue;
576
- }
577
- };
578
- }
579
- }
580
- return;
581
- }, [isResolvedOpen]);
582
- const {
583
- style: panelStyle = {},
584
- ...otherPanelProps
585
- } = panelProps;
586
- const {
587
- style: closeButtonStyle = {},
588
- onClick: onCloseClick,
589
- ...otherCloseButtonProps
590
- } = closeButtonProps;
591
- const {
592
- style: toggleButtonStyle = {},
593
- onClick: onToggleClick,
594
- ...otherToggleButtonProps
595
- } = toggleButtonProps;
596
-
597
- // Do not render on the server
598
- if (!isMounted()) return null;
599
- return /*#__PURE__*/React__default.createElement(Container, {
600
- ref: rootRef,
601
- className: "TanStackRouterDevtools"
602
- }, /*#__PURE__*/React__default.createElement(ThemeProvider, {
603
- theme: defaultTheme
604
- }, /*#__PURE__*/React__default.createElement(TanStackRouterDevtoolsPanel, _extends({
605
- ref: panelRef
606
- }, otherPanelProps, {
607
- router: router,
608
- style: {
609
- position: 'fixed',
610
- bottom: '0',
611
- right: '0',
612
- zIndex: 99999,
613
- width: '100%',
614
- height: devtoolsHeight ?? 500,
615
- maxHeight: '90%',
616
- boxShadow: '0 0 20px rgba(0,0,0,.3)',
617
- borderTop: `1px solid ${defaultTheme.gray}`,
618
- transformOrigin: 'top',
619
- // visibility will be toggled after transitions, but set initial state here
620
- visibility: isOpen ? 'visible' : 'hidden',
621
- ...panelStyle,
622
- ...(isResizing ? {
623
- transition: `none`
624
- } : {
625
- transition: `all .2s ease`
626
- }),
627
- ...(isResolvedOpen ? {
628
- opacity: 1,
629
- pointerEvents: 'all',
630
- transform: `translateY(0) scale(1)`
631
- } : {
632
- opacity: 0,
633
- pointerEvents: 'none',
634
- transform: `translateY(15px) scale(1.02)`
635
- })
636
- },
637
- isOpen: isResolvedOpen,
638
- setIsOpen: setIsOpen,
639
- handleDragStart: e => handleDragStart(panelRef.current, e)
640
- })), isResolvedOpen ? /*#__PURE__*/React__default.createElement(Button, _extends({
641
- type: "button",
642
- "aria-label": "Close TanStack Router Devtools"
643
- }, otherCloseButtonProps, {
644
- onClick: e => {
645
- setIsOpen(false);
646
- onCloseClick && onCloseClick(e);
647
- },
648
- style: {
649
- position: 'fixed',
650
- zIndex: 99999,
651
- margin: '.5em',
652
- bottom: 0,
653
- ...(position === 'top-right' ? {
654
- right: '0'
655
- } : position === 'top-left' ? {
656
- left: '0'
657
- } : position === 'bottom-right' ? {
658
- right: '0'
659
- } : {
660
- left: '0'
661
- }),
662
- ...closeButtonStyle
663
- }
664
- }), "Close") : null), !isResolvedOpen ? /*#__PURE__*/React__default.createElement("button", _extends({
665
- type: "button"
666
- }, otherToggleButtonProps, {
667
- "aria-label": "Open TanStack Router Devtools",
668
- onClick: e => {
669
- setIsOpen(true);
670
- onToggleClick && onToggleClick(e);
671
- },
672
- style: {
673
- appearance: 'none',
674
- background: 'none',
675
- border: 0,
676
- padding: 0,
677
- position: 'fixed',
678
- zIndex: 99999,
679
- display: 'inline-flex',
680
- fontSize: '1.5em',
681
- margin: '.5em',
682
- cursor: 'pointer',
683
- width: 'fit-content',
684
- ...(position === 'top-right' ? {
685
- top: '0',
686
- right: '0'
687
- } : position === 'top-left' ? {
688
- top: '0',
689
- left: '0'
690
- } : position === 'bottom-right' ? {
691
- bottom: '0',
692
- right: '0'
693
- } : {
694
- bottom: '0',
695
- left: '0'
696
- }),
697
- ...toggleButtonStyle
698
- }
699
- }), /*#__PURE__*/React__default.createElement(Logo, {
700
- "aria-hidden": true
701
- })) : null);
702
- }
703
- function RouteComp({
704
- route,
705
- isRoot,
706
- activeId,
707
- setActiveId
708
- }) {
709
- const routerState = useRouterState();
710
- const matches = routerState.status === 'pending' ? routerState.pendingMatches ?? [] : routerState.matches;
711
- const match = routerState.matches.find(d => d.routeId === route.id);
712
- return /*#__PURE__*/React__default.createElement("div", null, /*#__PURE__*/React__default.createElement("div", {
713
- role: "button",
714
- "aria-label": `Open match details for ${route.id}`,
715
- onClick: () => {
716
- if (match) {
717
- setActiveId(activeId === route.id ? '' : route.id);
718
- }
719
- },
720
- style: {
721
- display: 'flex',
722
- borderBottom: `solid 1px ${defaultTheme.grayAlt}`,
723
- cursor: match ? 'pointer' : 'default',
724
- alignItems: 'center',
725
- background: route.id === activeId ? 'rgba(255,255,255,.1)' : undefined,
726
- padding: '.25rem .5rem',
727
- gap: '.5rem'
728
- }
729
- }, isRoot ? null : /*#__PURE__*/React__default.createElement("div", {
730
- style: {
731
- flex: '0 0 auto',
732
- width: '.7rem',
733
- height: '.7rem',
734
- alignItems: 'center',
735
- justifyContent: 'center',
736
- fontWeight: 'bold',
737
- borderRadius: '100%',
738
- transition: 'all .2s ease-out',
739
- background: getRouteStatusColor(matches, route, defaultTheme),
740
- opacity: match ? 1 : 0.3
741
- }
742
- }), /*#__PURE__*/React__default.createElement("div", {
743
- style: {
744
- flex: '1 0 auto',
745
- display: 'flex',
746
- justifyContent: 'space-between',
747
- alignItems: 'center',
748
- padding: isRoot ? '0 .25rem' : 0,
749
- opacity: match ? 1 : 0.7,
750
- fontSize: '0.7rem'
751
- }
752
- }, /*#__PURE__*/React__default.createElement(Code, null, route.path || trimPath(route.id), " "), /*#__PURE__*/React__default.createElement("div", {
753
- style: {
754
- display: 'flex',
755
- alignItems: 'center',
756
- gap: '.5rem'
757
- }
758
- }, match ? /*#__PURE__*/React__default.createElement(Code, {
759
- style: {
760
- opacity: 0.3
761
- }
762
- }, match.id) : null, /*#__PURE__*/React__default.createElement(AgeTicker, {
763
- match: match
764
- })))), route.children?.length ? /*#__PURE__*/React__default.createElement("div", {
765
- style: {
766
- marginLeft: isRoot ? 0 : '1rem',
767
- borderLeft: isRoot ? '' : `solid 1px ${defaultTheme.grayAlt}`
768
- }
769
- }, [...route.children].sort((a, b) => {
770
- return a.rank - b.rank;
771
- }).map(r => /*#__PURE__*/React__default.createElement(RouteComp, {
772
- key: r.id,
773
- route: r,
774
- activeId: activeId,
775
- setActiveId: setActiveId
776
- }))) : null);
777
- }
778
- const TanStackRouterDevtoolsPanel = /*#__PURE__*/React__default.forwardRef(function TanStackRouterDevtoolsPanel(props, ref) {
779
- const {
780
- isOpen = true,
781
- setIsOpen,
782
- handleDragStart,
783
- router: userRouter,
784
- ...panelProps
785
- } = props;
786
- const router = useRouter();
787
- const routerState = useRouterState();
788
- const matches = [...(routerState.pendingMatches ?? []), ...routerState.matches, ...routerState.cachedMatches];
789
- 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.');
790
-
791
- // useStore(router.__store)
792
-
793
- const [showMatches, setShowMatches] = useLocalStorage('tanstackRouterDevtoolsShowMatches', true);
794
- const [activeId, setActiveId] = useLocalStorage('tanstackRouterDevtoolsActiveRouteId', '');
795
- const activeMatch = React__default.useMemo(() => matches.find(d => d.routeId === activeId || d.id === activeId), [matches, activeId]);
796
- const hasSearch = Object.keys(routerState.location.search || {}).length;
797
- const explorerState = {
798
- ...router,
799
- state: router.state
800
- };
801
- return /*#__PURE__*/React__default.createElement(ThemeProvider, {
802
- theme: defaultTheme
803
- }, /*#__PURE__*/React__default.createElement(Panel, _extends({
804
- ref: ref,
805
- className: "TanStackRouterDevtoolsPanel"
806
- }, panelProps), /*#__PURE__*/React__default.createElement("style", {
807
- dangerouslySetInnerHTML: {
808
- __html: `
809
-
810
- .TanStackRouterDevtoolsPanel * {
811
- scrollbar-color: ${defaultTheme.backgroundAlt} ${defaultTheme.gray};
812
- }
813
-
814
- .TanStackRouterDevtoolsPanel *::-webkit-scrollbar, .TanStackRouterDevtoolsPanel scrollbar {
815
- width: 1em;
816
- height: 1em;
817
- }
818
-
819
- .TanStackRouterDevtoolsPanel *::-webkit-scrollbar-track, .TanStackRouterDevtoolsPanel scrollbar-track {
820
- background: ${defaultTheme.backgroundAlt};
821
- }
822
-
823
- .TanStackRouterDevtoolsPanel *::-webkit-scrollbar-thumb, .TanStackRouterDevtoolsPanel scrollbar-thumb {
824
- background: ${defaultTheme.gray};
825
- border-radius: .5em;
826
- border: 3px solid ${defaultTheme.backgroundAlt};
827
- }
828
-
829
- .TanStackRouterDevtoolsPanel table {
830
- width: 100%;
831
- }
832
-
833
- .TanStackRouterDevtoolsPanel table tr {
834
- border-bottom: 2px dotted rgba(255, 255, 255, .2);
835
- }
836
-
837
- .TanStackRouterDevtoolsPanel table tr:last-child {
838
- border-bottom: none
839
- }
840
-
841
- .TanStackRouterDevtoolsPanel table td {
842
- padding: .25rem .5rem;
843
- border-right: 2px dotted rgba(255, 255, 255, .05);
844
- }
845
-
846
- .TanStackRouterDevtoolsPanel table td:last-child {
847
- border-right: none
848
- }
849
-
850
- `
851
- }
852
- }), /*#__PURE__*/React__default.createElement("div", {
853
- style: {
854
- position: 'absolute',
855
- left: 0,
856
- top: 0,
857
- width: '100%',
858
- height: '4px',
859
- marginBottom: '-4px',
860
- cursor: 'row-resize',
861
- zIndex: 100000
862
- },
863
- onMouseDown: handleDragStart
864
- }), /*#__PURE__*/React__default.createElement("div", {
865
- style: {
866
- flex: '1 1 500px',
867
- minHeight: '40%',
868
- maxHeight: '100%',
869
- overflow: 'auto',
870
- borderRight: `1px solid ${defaultTheme.grayAlt}`,
871
- display: 'flex',
872
- flexDirection: 'column'
873
- }
874
- }, /*#__PURE__*/React__default.createElement("div", {
875
- style: {
876
- display: 'flex',
877
- justifyContent: 'start',
878
- gap: '1rem',
879
- padding: '1rem',
880
- alignItems: 'center',
881
- background: defaultTheme.backgroundAlt
882
- }
883
- }, /*#__PURE__*/React__default.createElement(Logo, {
884
- "aria-hidden": true
885
- }), /*#__PURE__*/React__default.createElement("div", {
886
- style: {
887
- fontSize: 'clamp(.8rem, 2vw, 1.3rem)',
888
- fontWeight: 'bold'
889
- }
890
- }, /*#__PURE__*/React__default.createElement("span", {
891
- style: {
892
- fontWeight: 100
893
- }
894
- }, "Devtools"))), /*#__PURE__*/React__default.createElement("div", {
895
- style: {
896
- overflowY: 'auto',
897
- flex: '1'
898
- }
899
- }, /*#__PURE__*/React__default.createElement("div", {
900
- style: {
901
- padding: '.5em'
902
- }
903
- }, /*#__PURE__*/React__default.createElement(Explorer, {
904
- label: "Router",
905
- value: Object.fromEntries(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]))),
906
- defaultExpanded: {
907
- state: {},
908
- context: {},
909
- options: {}
910
- },
911
- filterSubEntries: subEntries => {
912
- return subEntries.filter(d => typeof d.value !== 'function');
913
- }
914
- })))), /*#__PURE__*/React__default.createElement("div", {
915
- style: {
916
- flex: '1 1 500px',
917
- minHeight: '40%',
918
- maxHeight: '100%',
919
- overflow: 'auto',
920
- borderRight: `1px solid ${defaultTheme.grayAlt}`,
921
- display: 'flex',
922
- flexDirection: 'column'
923
- }
924
- }, /*#__PURE__*/React__default.createElement("div", {
925
- style: {
926
- flex: '1 1 auto',
927
- overflowY: 'auto'
928
- }
929
- }, /*#__PURE__*/React__default.createElement("div", {
930
- style: {
931
- padding: '.5em',
932
- background: defaultTheme.backgroundAlt,
933
- position: 'sticky',
934
- top: 0,
935
- zIndex: 1,
936
- display: 'flex',
937
- alignItems: 'center',
938
- gap: '.5rem',
939
- fontWeight: 'bold'
940
- }
941
- }, "Pathname", ' ', routerState.location.maskedLocation ? /*#__PURE__*/React__default.createElement("div", {
942
- style: {
943
- padding: '.1rem .5rem',
944
- background: defaultTheme.warning,
945
- color: 'black',
946
- borderRadius: '.5rem'
947
- }
948
- }, "Masked") : null), /*#__PURE__*/React__default.createElement("div", {
949
- style: {
950
- padding: '.5rem',
951
- display: 'flex',
952
- gap: '.5rem',
953
- alignItems: 'center'
954
- }
955
- }, /*#__PURE__*/React__default.createElement("code", {
956
- style: {
957
- opacity: 0.6
958
- }
959
- }, routerState.location.pathname), routerState.location.maskedLocation ? /*#__PURE__*/React__default.createElement("code", {
960
- style: {
961
- color: defaultTheme.warning,
962
- fontWeight: 'bold'
963
- }
964
- }, routerState.location.maskedLocation.pathname) : null), /*#__PURE__*/React__default.createElement("div", {
965
- style: {
966
- padding: '.5em',
967
- background: defaultTheme.backgroundAlt,
968
- position: 'sticky',
969
- top: 0,
970
- zIndex: 1,
971
- display: 'flex',
972
- alignItems: 'center',
973
- justifyContent: 'space-between',
974
- gap: '.5rem',
975
- fontWeight: 'bold'
976
- }
977
- }, /*#__PURE__*/React__default.createElement("div", {
978
- style: {
979
- display: 'flex',
980
- alignItems: 'center',
981
- gap: '.5rem'
982
- }
983
- }, /*#__PURE__*/React__default.createElement("button", {
984
- type: "button",
985
- onClick: () => {
986
- setShowMatches(false);
987
- },
988
- disabled: !showMatches,
989
- style: {
990
- appearance: 'none',
991
- opacity: showMatches ? 0.5 : 1,
992
- border: 0,
993
- background: 'transparent',
994
- color: 'inherit',
995
- cursor: 'pointer'
996
- }
997
- }, "Routes"), "/", /*#__PURE__*/React__default.createElement("button", {
998
- type: "button",
999
- onClick: () => {
1000
- setShowMatches(true);
1001
- },
1002
- disabled: showMatches,
1003
- style: {
1004
- appearance: 'none',
1005
- opacity: !showMatches ? 0.5 : 1,
1006
- border: 0,
1007
- background: 'transparent',
1008
- color: 'inherit',
1009
- cursor: 'pointer'
1010
- }
1011
- }, "Matches")), /*#__PURE__*/React__default.createElement("div", {
1012
- style: {
1013
- opacity: 0.3,
1014
- fontSize: '0.7rem',
1015
- fontWeight: 'normal'
1016
- }
1017
- }, "age / staleTime / gcTime")), !showMatches ? /*#__PURE__*/React__default.createElement(RouteComp, {
1018
- route: router.routeTree,
1019
- isRoot: true,
1020
- activeId: activeId,
1021
- setActiveId: setActiveId
1022
- }) : /*#__PURE__*/React__default.createElement("div", null, (routerState.status === 'pending' ? routerState.pendingMatches ?? [] : routerState.matches).map((match, i) => {
1023
- return /*#__PURE__*/React__default.createElement("div", {
1024
- key: match.id || i,
1025
- role: "button",
1026
- "aria-label": `Open match details for ${match.id}`,
1027
- onClick: () => setActiveId(activeId === match.id ? '' : match.id),
1028
- style: {
1029
- display: 'flex',
1030
- borderBottom: `solid 1px ${defaultTheme.grayAlt}`,
1031
- cursor: 'pointer',
1032
- alignItems: 'center',
1033
- background: match === activeMatch ? 'rgba(255,255,255,.1)' : undefined
1034
- }
1035
- }, /*#__PURE__*/React__default.createElement("div", {
1036
- style: {
1037
- flex: '0 0 auto',
1038
- width: '1.3rem',
1039
- height: '1.3rem',
1040
- marginLeft: '.25rem',
1041
- background: getStatusColor(match, defaultTheme),
1042
- alignItems: 'center',
1043
- justifyContent: 'center',
1044
- fontWeight: 'bold',
1045
- borderRadius: '.25rem',
1046
- transition: 'all .2s ease-out'
1047
- }
1048
- }), /*#__PURE__*/React__default.createElement(Code, {
1049
- style: {
1050
- padding: '.5em',
1051
- fontSize: '0.7rem'
1052
- }
1053
- }, `${match.id}`), /*#__PURE__*/React__default.createElement(AgeTicker, {
1054
- match: match
1055
- }));
1056
- }))), routerState.cachedMatches?.length ? /*#__PURE__*/React__default.createElement("div", {
1057
- style: {
1058
- flex: '1 1 auto',
1059
- overflowY: 'auto',
1060
- maxHeight: '50%'
1061
- }
1062
- }, /*#__PURE__*/React__default.createElement("div", {
1063
- style: {
1064
- padding: '.5em',
1065
- background: defaultTheme.backgroundAlt,
1066
- position: 'sticky',
1067
- top: 0,
1068
- zIndex: 1,
1069
- display: 'flex',
1070
- alignItems: 'center',
1071
- justifyContent: 'space-between',
1072
- gap: '.5rem',
1073
- fontWeight: 'bold'
1074
- }
1075
- }, /*#__PURE__*/React__default.createElement("div", null, "Cached Matches"), /*#__PURE__*/React__default.createElement("div", {
1076
- style: {
1077
- opacity: 0.3,
1078
- fontSize: '0.7rem',
1079
- fontWeight: 'normal'
1080
- }
1081
- }, "age / staleTime / gcTime")), /*#__PURE__*/React__default.createElement("div", null, routerState.cachedMatches.map(match => {
1082
- return /*#__PURE__*/React__default.createElement("div", {
1083
- key: match.id,
1084
- role: "button",
1085
- "aria-label": `Open match details for ${match.id}`,
1086
- onClick: () => setActiveId(activeId === match.id ? '' : match.id),
1087
- style: {
1088
- display: 'flex',
1089
- borderBottom: `solid 1px ${defaultTheme.grayAlt}`,
1090
- cursor: 'pointer',
1091
- alignItems: 'center',
1092
- background: match === activeMatch ? 'rgba(255,255,255,.1)' : undefined,
1093
- fontSize: '0.7rem'
1094
- }
1095
- }, /*#__PURE__*/React__default.createElement("div", {
1096
- style: {
1097
- flex: '0 0 auto',
1098
- width: '.75rem',
1099
- height: '.75rem',
1100
- marginLeft: '.25rem',
1101
- background: getStatusColor(match, defaultTheme),
1102
- alignItems: 'center',
1103
- justifyContent: 'center',
1104
- fontWeight: 'bold',
1105
- borderRadius: '100%',
1106
- transition: 'all 1s ease-out'
1107
- }
1108
- }), /*#__PURE__*/React__default.createElement(Code, {
1109
- style: {
1110
- padding: '.5em'
1111
- }
1112
- }, `${match.id}`), /*#__PURE__*/React__default.createElement("div", {
1113
- style: {
1114
- marginLeft: 'auto'
1115
- }
1116
- }, /*#__PURE__*/React__default.createElement(AgeTicker, {
1117
- match: match
1118
- })));
1119
- }))) : null), activeMatch ? /*#__PURE__*/React__default.createElement(ActivePanel, null, /*#__PURE__*/React__default.createElement("div", {
1120
- style: {
1121
- padding: '.5em',
1122
- background: defaultTheme.backgroundAlt,
1123
- position: 'sticky',
1124
- top: 0,
1125
- bottom: 0,
1126
- zIndex: 1
1127
- }
1128
- }, "Match Details"), /*#__PURE__*/React__default.createElement("div", null, /*#__PURE__*/React__default.createElement("table", {
1129
- style: {
1130
- fontSize: '0.8rem'
1131
- }
1132
- }, /*#__PURE__*/React__default.createElement("tbody", null, /*#__PURE__*/React__default.createElement("tr", null, /*#__PURE__*/React__default.createElement("td", {
1133
- style: {
1134
- opacity: '.5'
1135
- }
1136
- }, "ID"), /*#__PURE__*/React__default.createElement("td", null, /*#__PURE__*/React__default.createElement(Code, {
1137
- style: {
1138
- lineHeight: '1.8em'
1139
- }
1140
- }, JSON.stringify(activeMatch.id, null, 2)))), /*#__PURE__*/React__default.createElement("tr", null, /*#__PURE__*/React__default.createElement("td", {
1141
- style: {
1142
- opacity: '.5'
1143
- }
1144
- }, "Status"), /*#__PURE__*/React__default.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__default.createElement("tr", null, /*#__PURE__*/React__default.createElement("td", {
1145
- style: {
1146
- opacity: '.5'
1147
- }
1148
- }, "Last Updated"), /*#__PURE__*/React__default.createElement("td", null, activeMatch.updatedAt ? new Date(activeMatch.updatedAt).toLocaleTimeString() : 'N/A'))))), activeMatch.loaderData ? /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement("div", {
1149
- style: {
1150
- background: defaultTheme.backgroundAlt,
1151
- padding: '.5em',
1152
- position: 'sticky',
1153
- top: 0,
1154
- bottom: 0,
1155
- zIndex: 1
1156
- }
1157
- }, "Loader Data"), /*#__PURE__*/React__default.createElement("div", {
1158
- style: {
1159
- padding: '.5em'
1160
- }
1161
- }, /*#__PURE__*/React__default.createElement(Explorer, {
1162
- label: "loaderData",
1163
- value: activeMatch.loaderData,
1164
- defaultExpanded: {}
1165
- }))) : null, /*#__PURE__*/React__default.createElement("div", {
1166
- style: {
1167
- background: defaultTheme.backgroundAlt,
1168
- padding: '.5em',
1169
- position: 'sticky',
1170
- top: 0,
1171
- bottom: 0,
1172
- zIndex: 1
1173
- }
1174
- }, "Explorer"), /*#__PURE__*/React__default.createElement("div", {
1175
- style: {
1176
- padding: '.5em'
1177
- }
1178
- }, /*#__PURE__*/React__default.createElement(Explorer, {
1179
- label: "Match",
1180
- value: activeMatch,
1181
- defaultExpanded: {}
1182
- }))) : null, hasSearch ? /*#__PURE__*/React__default.createElement("div", {
1183
- style: {
1184
- flex: '1 1 500px',
1185
- minHeight: '40%',
1186
- maxHeight: '100%',
1187
- overflow: 'auto',
1188
- borderRight: `1px solid ${defaultTheme.grayAlt}`,
1189
- display: 'flex',
1190
- flexDirection: 'column'
1191
- }
1192
- }, /*#__PURE__*/React__default.createElement("div", {
1193
- style: {
1194
- padding: '.5em',
1195
- background: defaultTheme.backgroundAlt,
1196
- position: 'sticky',
1197
- top: 0,
1198
- bottom: 0,
1199
- zIndex: 1,
1200
- fontWeight: 'bold'
1201
- }
1202
- }, "Search Params"), /*#__PURE__*/React__default.createElement("div", {
1203
- style: {
1204
- padding: '.5em'
1205
- }
1206
- }, /*#__PURE__*/React__default.createElement(Explorer, {
1207
- value: routerState.location.search || {},
1208
- defaultExpanded: Object.keys(routerState.location.search || {}).reduce((obj, next) => {
1209
- obj[next] = {};
1210
- return obj;
1211
- }, {})
1212
- }))) : null));
1213
- });
1214
- function AgeTicker({
1215
- match
1216
- }) {
1217
- const router = useRouter();
1218
- const rerender = React__default.useReducer(() => ({}), () => ({}))[1];
1219
- React__default.useEffect(() => {
1220
- const interval = setInterval(() => {
1221
- rerender();
1222
- }, 1000);
1223
- return () => {
1224
- clearInterval(interval);
1225
- };
1226
- }, []);
1227
- if (!match) {
1228
- return null;
1229
- }
1230
- const route = router.looseRoutesById[match?.routeId];
1231
- if (!route.options.loader) {
1232
- return null;
1233
- }
1234
- const age = Date.now() - match?.updatedAt;
1235
- const staleTime = route.options.staleTime ?? router.options.defaultStaleTime ?? 0;
1236
- const gcTime = route.options.gcTime ?? router.options.defaultGcTime ?? 30 * 60 * 1000;
1237
- return /*#__PURE__*/React__default.createElement("div", {
1238
- style: {
1239
- display: 'inline-flex',
1240
- alignItems: 'center',
1241
- gap: '.25rem',
1242
- color: age > staleTime ? defaultTheme.warning : undefined
1243
- }
1244
- }, /*#__PURE__*/React__default.createElement("div", {
1245
- style: {}
1246
- }, formatTime(age)), /*#__PURE__*/React__default.createElement("div", null, "/"), /*#__PURE__*/React__default.createElement("div", null, formatTime(staleTime)), /*#__PURE__*/React__default.createElement("div", null, "/"), /*#__PURE__*/React__default.createElement("div", null, formatTime(gcTime)));
1247
- }
1248
- function formatTime(ms) {
1249
- const units = ['s', 'min', 'h', 'd'];
1250
- const values = [ms / 1000, ms / 60000, ms / 3600000, ms / 86400000];
1251
- let chosenUnitIndex = 0;
1252
- for (let i = 1; i < values.length; i++) {
1253
- if (values[i] < 1) break;
1254
- chosenUnitIndex = i;
1255
- }
1256
- const formatter = new Intl.NumberFormat(navigator.language, {
1257
- compactDisplay: 'short',
1258
- notation: 'compact',
1259
- maximumFractionDigits: 0
1260
- });
1261
- return formatter.format(values[chosenUnitIndex]) + units[chosenUnitIndex];
1262
- }
1263
-
1264
- export { TanStackRouterDevtools, TanStackRouterDevtoolsPanel };
1265
- //# sourceMappingURL=index.js.map