@tanstack/react-router-devtools 0.0.1-alpha.1

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 (40) hide show
  1. package/README.md +3 -0
  2. package/build/cjs/_virtual/_rollupPluginBabelHelpers.js +49 -0
  3. package/build/cjs/_virtual/_rollupPluginBabelHelpers.js.map +1 -0
  4. package/build/cjs/packages/react-router-devtools/src/Explorer.js +245 -0
  5. package/build/cjs/packages/react-router-devtools/src/Explorer.js.map +1 -0
  6. package/build/cjs/packages/react-router-devtools/src/Logo.js +73 -0
  7. package/build/cjs/packages/react-router-devtools/src/Logo.js.map +1 -0
  8. package/build/cjs/packages/react-router-devtools/src/devtools.js +654 -0
  9. package/build/cjs/packages/react-router-devtools/src/devtools.js.map +1 -0
  10. package/build/cjs/packages/react-router-devtools/src/index.js +21 -0
  11. package/build/cjs/packages/react-router-devtools/src/index.js.map +1 -0
  12. package/build/cjs/packages/react-router-devtools/src/styledComponents.js +107 -0
  13. package/build/cjs/packages/react-router-devtools/src/styledComponents.js.map +1 -0
  14. package/build/cjs/packages/react-router-devtools/src/theme.js +54 -0
  15. package/build/cjs/packages/react-router-devtools/src/theme.js.map +1 -0
  16. package/build/cjs/packages/react-router-devtools/src/useLocalStorage.js +65 -0
  17. package/build/cjs/packages/react-router-devtools/src/useLocalStorage.js.map +1 -0
  18. package/build/cjs/packages/react-router-devtools/src/useMediaQuery.js +57 -0
  19. package/build/cjs/packages/react-router-devtools/src/useMediaQuery.js.map +1 -0
  20. package/build/cjs/packages/react-router-devtools/src/utils.js +117 -0
  21. package/build/cjs/packages/react-router-devtools/src/utils.js.map +1 -0
  22. package/build/esm/index.js +2013 -0
  23. package/build/esm/index.js.map +1 -0
  24. package/build/stats-html.html +4034 -0
  25. package/build/stats-react.json +9681 -0
  26. package/build/types/index.d.ts +76 -0
  27. package/build/umd/index.development.js +2043 -0
  28. package/build/umd/index.development.js.map +1 -0
  29. package/build/umd/index.production.js +12 -0
  30. package/build/umd/index.production.js.map +1 -0
  31. package/package.json +49 -0
  32. package/src/Explorer.tsx +288 -0
  33. package/src/Logo.tsx +37 -0
  34. package/src/devtools.tsx +960 -0
  35. package/src/index.tsx +1 -0
  36. package/src/styledComponents.ts +106 -0
  37. package/src/theme.tsx +31 -0
  38. package/src/useLocalStorage.ts +52 -0
  39. package/src/useMediaQuery.ts +36 -0
  40. package/src/utils.ts +151 -0
package/src/index.tsx ADDED
@@ -0,0 +1 @@
1
+ export * from './devtools'
@@ -0,0 +1,106 @@
1
+ import { styled } from './utils'
2
+
3
+ export const Panel = styled(
4
+ 'div',
5
+ (_props, theme) => ({
6
+ fontSize: 'clamp(12px, 1.5vw, 14px)',
7
+ fontFamily: `sans-serif`,
8
+ display: 'flex',
9
+ backgroundColor: theme.background,
10
+ color: theme.foreground,
11
+ }),
12
+ {
13
+ '(max-width: 700px)': {
14
+ flexDirection: 'column',
15
+ },
16
+ '(max-width: 600px)': {
17
+ fontSize: '.9em',
18
+ // flexDirection: 'column',
19
+ },
20
+ },
21
+ )
22
+
23
+ export const ActivePanel = styled(
24
+ 'div',
25
+ () => ({
26
+ flex: '1 1 500px',
27
+ display: 'flex',
28
+ flexDirection: 'column',
29
+ overflow: 'auto',
30
+ height: '100%',
31
+ }),
32
+ {
33
+ '(max-width: 700px)': (_props, theme) => ({
34
+ borderTop: `2px solid ${theme.gray}`,
35
+ }),
36
+ },
37
+ )
38
+
39
+ export const Button = styled('button', (props, theme) => ({
40
+ appearance: 'none',
41
+ fontSize: '.9em',
42
+ fontWeight: 'bold',
43
+ background: theme.gray,
44
+ border: '0',
45
+ borderRadius: '.3em',
46
+ color: 'white',
47
+ padding: '.5em',
48
+ opacity: props.disabled ? '.5' : undefined,
49
+ cursor: 'pointer',
50
+ }))
51
+
52
+ // export const QueryKeys = styled('span', {
53
+ // display: 'inline-block',
54
+ // fontSize: '0.9em',
55
+ // })
56
+
57
+ // export const QueryKey = styled('span', {
58
+ // display: 'inline-flex',
59
+ // alignItems: 'center',
60
+ // padding: '.2em .4em',
61
+ // fontWeight: 'bold',
62
+ // textShadow: '0 0 10px black',
63
+ // borderRadius: '.2em',
64
+ // })
65
+
66
+ export const Code = styled('code', {
67
+ fontSize: '.9em',
68
+ })
69
+
70
+ export const Input = styled('input', (_props, theme) => ({
71
+ backgroundColor: theme.inputBackgroundColor,
72
+ border: 0,
73
+ borderRadius: '.2em',
74
+ color: theme.inputTextColor,
75
+ fontSize: '.9em',
76
+ lineHeight: `1.3`,
77
+ padding: '.3em .4em',
78
+ }))
79
+
80
+ export const Select = styled(
81
+ 'select',
82
+ (_props, theme) => ({
83
+ display: `inline-block`,
84
+ fontSize: `.9em`,
85
+ fontFamily: `sans-serif`,
86
+ fontWeight: 'normal',
87
+ lineHeight: `1.3`,
88
+ padding: `.3em 1.5em .3em .5em`,
89
+ height: 'auto',
90
+ border: 0,
91
+ borderRadius: `.2em`,
92
+ appearance: `none`,
93
+ WebkitAppearance: 'none',
94
+ backgroundColor: theme.inputBackgroundColor,
95
+ backgroundImage: `url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23444444'><polygon points='0,25 100,25 50,75'/></svg>")`,
96
+ backgroundRepeat: `no-repeat`,
97
+ backgroundPosition: `right .55em center`,
98
+ backgroundSize: `.65em auto, 100%`,
99
+ color: theme.inputTextColor,
100
+ }),
101
+ {
102
+ '(max-width: 500px)': {
103
+ display: 'none',
104
+ },
105
+ },
106
+ )
package/src/theme.tsx ADDED
@@ -0,0 +1,31 @@
1
+ import React from 'react'
2
+
3
+ export const defaultTheme = {
4
+ background: '#0b1521',
5
+ backgroundAlt: '#132337',
6
+ foreground: 'white',
7
+ gray: '#3f4e60',
8
+ grayAlt: '#222e3e',
9
+ inputBackgroundColor: '#fff',
10
+ inputTextColor: '#000',
11
+ success: '#00ab52',
12
+ danger: '#ff0085',
13
+ active: '#006bff',
14
+ warning: '#ffb200',
15
+ } as const
16
+
17
+ export type Theme = typeof defaultTheme
18
+ interface ProviderProps {
19
+ theme: Theme
20
+ children?: React.ReactNode
21
+ }
22
+
23
+ const ThemeContext = React.createContext(defaultTheme)
24
+
25
+ export function ThemeProvider({ theme, ...rest }: ProviderProps) {
26
+ return <ThemeContext.Provider value={theme} {...rest} />
27
+ }
28
+
29
+ export function useTheme() {
30
+ return React.useContext(ThemeContext)
31
+ }
@@ -0,0 +1,52 @@
1
+ import React from 'react'
2
+
3
+ const getItem = (key: string): unknown => {
4
+ try {
5
+ const itemValue = localStorage.getItem(key)
6
+ if (typeof itemValue === 'string') {
7
+ return JSON.parse(itemValue)
8
+ }
9
+ return undefined
10
+ } catch {
11
+ return undefined
12
+ }
13
+ }
14
+
15
+ export default function useLocalStorage<T>(
16
+ key: string,
17
+ defaultValue: T | undefined
18
+ ): [T | undefined, (newVal: T | ((prevVal: T) => T)) => void] {
19
+ const [value, setValue] = React.useState<T>()
20
+
21
+ React.useEffect(() => {
22
+ const initialValue = getItem(key) as T | undefined
23
+
24
+ if (typeof initialValue === 'undefined' || initialValue === null) {
25
+ setValue(
26
+ typeof defaultValue === 'function' ? defaultValue() : defaultValue
27
+ )
28
+ } else {
29
+ setValue(initialValue)
30
+ }
31
+ }, [defaultValue, key])
32
+
33
+ const setter = React.useCallback(
34
+ updater => {
35
+ setValue(old => {
36
+ let newVal = updater
37
+
38
+ if (typeof updater == 'function') {
39
+ newVal = updater(old)
40
+ }
41
+ try {
42
+ localStorage.setItem(key, JSON.stringify(newVal))
43
+ } catch {}
44
+
45
+ return newVal
46
+ })
47
+ },
48
+ [key]
49
+ )
50
+
51
+ return [value, setter]
52
+ }
@@ -0,0 +1,36 @@
1
+ import React from 'react'
2
+
3
+ export default function useMediaQuery(query: string): boolean | undefined {
4
+ // Keep track of the preference in state, start with the current match
5
+ const [isMatch, setIsMatch] = React.useState(() => {
6
+ if (typeof window !== 'undefined') {
7
+ return window.matchMedia && window.matchMedia(query).matches
8
+ }
9
+ })
10
+
11
+ // Watch for changes
12
+ React.useEffect(() => {
13
+ if (typeof window !== 'undefined') {
14
+ if (!window.matchMedia) {
15
+ return
16
+ }
17
+
18
+ // Create a matcher
19
+ const matcher = window.matchMedia(query)
20
+
21
+ // Create our handler
22
+ const onChange = ({ matches }: { matches: boolean }) =>
23
+ setIsMatch(matches)
24
+
25
+ // Listen for changes
26
+ matcher.addListener(onChange)
27
+
28
+ return () => {
29
+ // Stop listening for changes
30
+ matcher.removeListener(onChange)
31
+ }
32
+ }
33
+ }, [isMatch, query, setIsMatch])
34
+
35
+ return isMatch
36
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,151 @@
1
+ import React from 'react'
2
+ import { RouteMatch } from '@tanstack/react-router'
3
+
4
+ import { Theme, useTheme } from './theme'
5
+ import useMediaQuery from './useMediaQuery'
6
+
7
+ export const isServer = typeof window === 'undefined'
8
+
9
+ type StyledComponent<T> = T extends 'button'
10
+ ? React.DetailedHTMLProps<
11
+ React.ButtonHTMLAttributes<HTMLButtonElement>,
12
+ HTMLButtonElement
13
+ >
14
+ : T extends 'input'
15
+ ? React.DetailedHTMLProps<
16
+ React.InputHTMLAttributes<HTMLInputElement>,
17
+ HTMLInputElement
18
+ >
19
+ : T extends 'select'
20
+ ? React.DetailedHTMLProps<
21
+ React.SelectHTMLAttributes<HTMLSelectElement>,
22
+ HTMLSelectElement
23
+ >
24
+ : T extends keyof HTMLElementTagNameMap
25
+ ? React.HTMLAttributes<HTMLElementTagNameMap[T]>
26
+ : never
27
+
28
+ export function getStatusColor(match: RouteMatch, theme: Theme) {
29
+ return match.isPending
30
+ ? theme.warning
31
+ : match.isFetching
32
+ ? theme.active
33
+ : match.status === 'error'
34
+ ? theme.danger
35
+ : match.status === 'success'
36
+ ? theme.success
37
+ : theme.gray
38
+ }
39
+
40
+ // export function getQueryStatusLabel(query: Query) {
41
+ // return query.state.isFetching
42
+ // ? 'fetching'
43
+ // : !query.getObserversCount()
44
+ // ? 'inactive'
45
+ // : query.isStale()
46
+ // ? 'stale'
47
+ // : 'fresh'
48
+ // }
49
+
50
+ type Styles =
51
+ | React.CSSProperties
52
+ | ((props: Record<string, any>, theme: Theme) => React.CSSProperties)
53
+
54
+ export function styled<T extends keyof HTMLElementTagNameMap>(
55
+ type: T,
56
+ newStyles: Styles,
57
+ queries: Record<string, Styles> = {},
58
+ ) {
59
+ return React.forwardRef<HTMLElementTagNameMap[T], StyledComponent<T>>(
60
+ ({ style, ...rest }, ref) => {
61
+ const theme = useTheme()
62
+
63
+ const mediaStyles = Object.entries(queries).reduce(
64
+ (current, [key, value]) => {
65
+ // eslint-disable-next-line react-hooks/rules-of-hooks
66
+ return useMediaQuery(key)
67
+ ? {
68
+ ...current,
69
+ ...(typeof value === 'function' ? value(rest, theme) : value),
70
+ }
71
+ : current
72
+ },
73
+ {},
74
+ )
75
+
76
+ return React.createElement(type, {
77
+ ...rest,
78
+ style: {
79
+ ...(typeof newStyles === 'function'
80
+ ? newStyles(rest, theme)
81
+ : newStyles),
82
+ ...style,
83
+ ...mediaStyles,
84
+ },
85
+ ref,
86
+ })
87
+ },
88
+ )
89
+ }
90
+
91
+ export function useIsMounted() {
92
+ const mountedRef = React.useRef(false)
93
+ const isMounted = React.useCallback(() => mountedRef.current, [])
94
+
95
+ React[isServer ? 'useEffect' : 'useLayoutEffect'](() => {
96
+ mountedRef.current = true
97
+ return () => {
98
+ mountedRef.current = false
99
+ }
100
+ }, [])
101
+
102
+ return isMounted
103
+ }
104
+
105
+ /**
106
+ * Displays a string regardless the type of the data
107
+ * @param {unknown} value Value to be stringified
108
+ */
109
+ export const displayValue = (value: unknown) => {
110
+ const name = Object.getOwnPropertyNames(Object(value))
111
+ const newValue = typeof value === 'bigint' ? `${value.toString()}n` : value
112
+
113
+ return JSON.stringify(newValue, name)
114
+ }
115
+
116
+ /**
117
+ * This hook is a safe useState version which schedules state updates in microtasks
118
+ * to prevent updating a component state while React is rendering different components
119
+ * or when the component is not mounted anymore.
120
+ */
121
+ export function useSafeState<T>(initialState: T): [T, (value: T) => void] {
122
+ const isMounted = useIsMounted()
123
+ const [state, setState] = React.useState(initialState)
124
+
125
+ const safeSetState = React.useCallback(
126
+ (value: T) => {
127
+ scheduleMicrotask(() => {
128
+ if (isMounted()) {
129
+ setState(value)
130
+ }
131
+ })
132
+ },
133
+ [isMounted],
134
+ )
135
+
136
+ return [state, safeSetState]
137
+ }
138
+
139
+ /**
140
+ * Schedules a microtask.
141
+ * This can be useful to schedule state updates after rendering.
142
+ */
143
+ function scheduleMicrotask(callback: () => void) {
144
+ Promise.resolve()
145
+ .then(callback)
146
+ .catch((error) =>
147
+ setTimeout(() => {
148
+ throw error
149
+ }),
150
+ )
151
+ }