@tanstack/devtools-ui 0.2.2 → 0.3.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/dist/cjs/components/button.cjs +23 -0
  2. package/dist/cjs/components/button.cjs.map +1 -0
  3. package/dist/cjs/components/button.d.cts +11 -0
  4. package/dist/cjs/components/tag.cjs +40 -0
  5. package/dist/cjs/components/tag.cjs.map +1 -0
  6. package/dist/cjs/components/tag.d.cts +7 -0
  7. package/dist/cjs/components/tree.cjs +237 -0
  8. package/dist/cjs/components/tree.cjs.map +1 -0
  9. package/dist/cjs/components/tree.d.cts +3 -0
  10. package/dist/cjs/index.cjs +6 -0
  11. package/dist/cjs/index.cjs.map +1 -1
  12. package/dist/cjs/index.d.cts +3 -0
  13. package/dist/cjs/styles/tokens.cjs +151 -3
  14. package/dist/cjs/styles/tokens.cjs.map +1 -1
  15. package/dist/cjs/styles/use-styles.cjs +202 -2
  16. package/dist/cjs/styles/use-styles.cjs.map +1 -1
  17. package/dist/cjs/styles/use-styles.d.cts +24 -0
  18. package/dist/esm/components/button.d.ts +11 -0
  19. package/dist/esm/components/button.js +23 -0
  20. package/dist/esm/components/button.js.map +1 -0
  21. package/dist/esm/components/tag.d.ts +7 -0
  22. package/dist/esm/components/tag.js +40 -0
  23. package/dist/esm/components/tag.js.map +1 -0
  24. package/dist/esm/components/tree.d.ts +3 -0
  25. package/dist/esm/components/tree.js +237 -0
  26. package/dist/esm/components/tree.js.map +1 -0
  27. package/dist/esm/index.d.ts +3 -0
  28. package/dist/esm/index.js +6 -0
  29. package/dist/esm/index.js.map +1 -1
  30. package/dist/esm/styles/tokens.js +151 -3
  31. package/dist/esm/styles/tokens.js.map +1 -1
  32. package/dist/esm/styles/use-styles.d.ts +24 -0
  33. package/dist/esm/styles/use-styles.js +202 -2
  34. package/dist/esm/styles/use-styles.js.map +1 -1
  35. package/package.json +2 -1
  36. package/src/components/button.tsx +42 -0
  37. package/src/components/tag.tsx +22 -0
  38. package/src/components/tree.tsx +167 -0
  39. package/src/index.ts +3 -0
  40. package/src/styles/use-styles.ts +206 -1
@@ -0,0 +1,42 @@
1
+ import { splitProps } from 'solid-js'
2
+ import clsx from 'clsx'
3
+ import { useStyles } from '../styles/use-styles'
4
+ import type { JSX } from 'solid-js'
5
+
6
+ export type ButtonVariant =
7
+ | 'primary'
8
+ | 'secondary'
9
+ | 'danger'
10
+ | 'success'
11
+ | 'info'
12
+ | 'warning'
13
+ type ButtonProps = JSX.ButtonHTMLAttributes<HTMLButtonElement> & {
14
+ variant?: ButtonVariant
15
+ outline?: boolean
16
+ ghost?: boolean
17
+ children?: any
18
+ className?: string
19
+ }
20
+
21
+ export function Button(props: ButtonProps) {
22
+ const styles = useStyles()
23
+ const [local, rest] = splitProps(props, [
24
+ 'variant',
25
+ 'outline',
26
+ 'ghost',
27
+ 'children',
28
+ 'className',
29
+ ])
30
+ const variant = local.variant || 'primary'
31
+ const classes = clsx(
32
+ styles().button.base,
33
+ styles().button.variant(variant, local.outline, local.ghost),
34
+ local.className,
35
+ )
36
+
37
+ return (
38
+ <button {...rest} class={classes}>
39
+ {local.children}
40
+ </button>
41
+ )
42
+ }
@@ -0,0 +1,22 @@
1
+ import { Show } from 'solid-js'
2
+ import { useStyles } from '../styles/use-styles'
3
+ import type { tokens } from '../styles/tokens'
4
+
5
+ export const Tag = (props: {
6
+ color: keyof typeof tokens.colors
7
+ label: string
8
+ count?: number
9
+ disabled?: boolean
10
+ }) => {
11
+ const styles = useStyles()
12
+ return (
13
+ <button disabled={props.disabled} class={styles().tag.base}>
14
+ <span class={styles().tag.dot(props.color)} />
15
+ <span class={styles().tag.label}>{props.label}</span>
16
+
17
+ <Show when={props.count && props.count > 0}>
18
+ <span class={styles().tag.count}>{props.count}</span>
19
+ </Show>
20
+ </button>
21
+ )
22
+ }
@@ -0,0 +1,167 @@
1
+ import { For, Show, createSignal } from 'solid-js'
2
+ import clsx from 'clsx'
3
+ import { useStyles } from '../styles/use-styles'
4
+
5
+ export function JsonTree(props: { value: any }) {
6
+ return <JsonValue isRoot value={props.value} />
7
+ }
8
+
9
+ function JsonValue(props: {
10
+ value: any
11
+ keyName?: string
12
+ isRoot?: boolean
13
+ isLastKey?: boolean
14
+ }) {
15
+ const { value, keyName, isRoot = false, isLastKey } = props
16
+ const styles = useStyles()
17
+
18
+ return (
19
+ <span class={styles().tree.valueContainer(isRoot)}>
20
+ {keyName && typeof value !== 'object' && !Array.isArray(value) && (
21
+ <span class={styles().tree.valueKey}>&quot;{keyName}&quot;: </span>
22
+ )}
23
+ {(() => {
24
+ if (typeof value === 'string') {
25
+ return (
26
+ <span class={styles().tree.valueString}>&quot;{value}&quot;</span>
27
+ )
28
+ }
29
+ if (typeof value === 'number') {
30
+ return <span class={styles().tree.valueNumber}>{value}</span>
31
+ }
32
+ if (typeof value === 'boolean') {
33
+ return <span class={styles().tree.valueBoolean}>{String(value)}</span>
34
+ }
35
+ if (value === null) {
36
+ return <span class={styles().tree.valueNull}>null</span>
37
+ }
38
+ if (value === undefined) {
39
+ return <span class={styles().tree.valueNull}>undefined</span>
40
+ }
41
+ if (typeof value === 'function') {
42
+ return (
43
+ <span class={styles().tree.valueFunction}>{String(value)}</span>
44
+ )
45
+ }
46
+ if (Array.isArray(value)) {
47
+ return <ArrayValue keyName={keyName} value={value} />
48
+ }
49
+ if (typeof value === 'object') {
50
+ return <ObjectValue keyName={keyName} value={value} />
51
+ }
52
+ return <span />
53
+ })()}
54
+ {isLastKey || isRoot ? '' : <span>,</span>}
55
+ </span>
56
+ )
57
+ }
58
+
59
+ const ArrayValue = ({
60
+ value,
61
+ keyName,
62
+ }: {
63
+ value: Array<any>
64
+ keyName?: string
65
+ }) => {
66
+ const styles = useStyles()
67
+ const [expanded, setExpanded] = createSignal(true)
68
+ return (
69
+ <span>
70
+ {keyName && (
71
+ <span
72
+ onclick={(e) => {
73
+ e.stopPropagation()
74
+ e.stopImmediatePropagation()
75
+ setExpanded(!expanded())
76
+ }}
77
+ class={clsx(styles().tree.valueKey, styles().tree.collapsible)}
78
+ >
79
+ &quot;{keyName}&quot;:{' '}
80
+ </span>
81
+ )}
82
+ <span class={styles().tree.valueBraces}>[</span>
83
+ <Show when={expanded()}>
84
+ <For each={value}>
85
+ {(item, i) => {
86
+ const isLastKey = i() === value.length - 1
87
+ return (
88
+ <>
89
+ <JsonValue value={item} isLastKey={isLastKey} />
90
+ </>
91
+ )
92
+ }}
93
+ </For>
94
+ </Show>
95
+ <Show when={!expanded()}>
96
+ <span
97
+ onClick={(e) => {
98
+ e.stopPropagation()
99
+ e.stopImmediatePropagation()
100
+ setExpanded(!expanded())
101
+ }}
102
+ class={clsx(styles().tree.valueKey, styles().tree.collapsible)}
103
+ >
104
+ {`... ${value.length} more`}
105
+ </span>
106
+ </Show>
107
+ <span class={styles().tree.valueBraces}>]</span>
108
+ </span>
109
+ )
110
+ }
111
+
112
+ const ObjectValue = ({
113
+ value,
114
+ keyName,
115
+ }: {
116
+ value: Record<string, any>
117
+ keyName?: string
118
+ }) => {
119
+ const styles = useStyles()
120
+ const [expanded, setExpanded] = createSignal(true)
121
+ const keys = Object.keys(value)
122
+ const lastKeyName = keys[keys.length - 1]
123
+
124
+ return (
125
+ <span>
126
+ {keyName && (
127
+ <span
128
+ onClick={(e) => {
129
+ e.stopPropagation()
130
+ e.stopImmediatePropagation()
131
+ setExpanded(!expanded())
132
+ }}
133
+ class={clsx(styles().tree.valueKey, styles().tree.collapsible)}
134
+ >
135
+ &quot;{keyName}&quot;:{' '}
136
+ </span>
137
+ )}
138
+ <span class={styles().tree.valueBraces}>{'{'}</span>
139
+ <Show when={expanded()}>
140
+ <For each={keys}>
141
+ {(k) => (
142
+ <>
143
+ <JsonValue
144
+ value={value[k]}
145
+ keyName={k}
146
+ isLastKey={lastKeyName === k}
147
+ />
148
+ </>
149
+ )}
150
+ </For>
151
+ </Show>
152
+ <Show when={!expanded()}>
153
+ <span
154
+ onClick={(e) => {
155
+ e.stopPropagation()
156
+ e.stopImmediatePropagation()
157
+ setExpanded(!expanded())
158
+ }}
159
+ class={clsx(styles().tree.valueKey, styles().tree.collapsible)}
160
+ >
161
+ {`... ${keys.length} more`}
162
+ </span>
163
+ </Show>
164
+ <span class={styles().tree.valueBraces}>{'}'}</span>
165
+ </span>
166
+ )
167
+ }
package/src/index.ts CHANGED
@@ -2,3 +2,6 @@ export { Checkbox } from './components/checkbox'
2
2
  export { Input } from './components/input'
3
3
  export { Select } from './components/select'
4
4
  export { TanStackLogo } from './components/logo'
5
+ export { JsonTree } from './components/tree'
6
+ export { Button } from './components/button'
7
+ export { Tag } from './components/tag'
@@ -1,11 +1,60 @@
1
1
  import * as goober from 'goober'
2
2
  import { createSignal } from 'solid-js'
3
3
  import { tokens } from './tokens'
4
+ import type { ButtonVariant } from '../components/button'
4
5
 
5
- const stylesFactory = () => {
6
+ const buttonVariantColors: Record<
7
+ ButtonVariant,
8
+ { bg: string; hover: string; active: string; text: string; border: string }
9
+ > = {
10
+ primary: {
11
+ bg: tokens.colors.purple[500],
12
+ hover: tokens.colors.purple[600],
13
+ active: tokens.colors.purple[700],
14
+ text: '#fff',
15
+ border: tokens.colors.purple[500],
16
+ },
17
+ secondary: {
18
+ bg: tokens.colors.gray[800],
19
+ hover: tokens.colors.gray[700],
20
+ active: tokens.colors.gray[600],
21
+ text: tokens.colors.gray[100],
22
+ border: tokens.colors.gray[700],
23
+ },
24
+ info: {
25
+ bg: tokens.colors.blue[500],
26
+ hover: tokens.colors.blue[600],
27
+ active: tokens.colors.blue[700],
28
+ text: '#fff',
29
+ border: tokens.colors.blue[500],
30
+ },
31
+ warning: {
32
+ bg: tokens.colors.yellow[500],
33
+ hover: tokens.colors.yellow[600],
34
+ active: tokens.colors.yellow[700],
35
+ text: '#fff',
36
+ border: tokens.colors.yellow[500],
37
+ },
38
+ danger: {
39
+ bg: tokens.colors.red[500],
40
+ hover: tokens.colors.red[600],
41
+ active: tokens.colors.red[700],
42
+ text: '#fff',
43
+ border: tokens.colors.red[500],
44
+ },
45
+ success: {
46
+ bg: tokens.colors.green[500],
47
+ hover: tokens.colors.green[600],
48
+ active: tokens.colors.green[700],
49
+ text: '#fff',
50
+ border: tokens.colors.green[500],
51
+ },
52
+ }
53
+ const stylesFactory = (theme: 'light' | 'dark' = 'dark') => {
6
54
  const { colors, font, size, alpha } = tokens
7
55
  const { fontFamily } = font
8
56
  const css = goober.css
57
+ const t = (light: string, dark: string) => (theme === 'light' ? light : dark)
9
58
 
10
59
  return {
11
60
  logo: css`
@@ -38,12 +87,14 @@ const stylesFactory = () => {
38
87
  font-size: 0.875rem;
39
88
  font-weight: 500;
40
89
  color: ${colors.gray[100]};
90
+ text-align: left;
41
91
  `,
42
92
  selectDescription: css`
43
93
  font-size: 0.8rem;
44
94
  color: ${colors.gray[400]};
45
95
  margin: 0;
46
96
  line-height: 1.3;
97
+ text-align: left;
47
98
  `,
48
99
  select: css`
49
100
  appearance: none;
@@ -87,12 +138,14 @@ const stylesFactory = () => {
87
138
  font-size: 0.875rem;
88
139
  font-weight: 500;
89
140
  color: ${colors.gray[100]};
141
+ text-align: left;
90
142
  `,
91
143
  inputDescription: css`
92
144
  font-size: 0.8rem;
93
145
  color: ${colors.gray[400]};
94
146
  margin: 0;
95
147
  line-height: 1.3;
148
+ text-align: left;
96
149
  `,
97
150
  input: css`
98
151
  appearance: none;
@@ -180,12 +233,164 @@ const stylesFactory = () => {
180
233
  font-size: 0.875rem;
181
234
  font-weight: 500;
182
235
  line-height: 1.4;
236
+ text-align: left;
183
237
  `,
184
238
  checkboxDescription: css`
185
239
  color: ${colors.gray[400]};
186
240
  font-size: 0.8rem;
187
241
  line-height: 1.3;
242
+ text-align: left;
188
243
  `,
244
+ button: {
245
+ base: css`
246
+ display: inline-flex;
247
+ align-items: center;
248
+ justify-content: center;
249
+ font-family: ${tokens.font.fontFamily.sans};
250
+ font-size: 0.8rem;
251
+ font-weight: 500;
252
+ border-radius: 0.2rem;
253
+ padding: 0.2rem 0.6rem;
254
+ cursor: pointer;
255
+ transition:
256
+ background 0.2s,
257
+ color 0.2s,
258
+ border 0.2s,
259
+ box-shadow 0.2s;
260
+ outline: none;
261
+ border-width: 1px;
262
+ border-style: solid;
263
+ `,
264
+ variant(variant: ButtonVariant, outline?: boolean, ghost?: boolean) {
265
+ const v = buttonVariantColors[variant]
266
+ if (ghost) {
267
+ return css`
268
+ background: transparent;
269
+ color: ${v.bg};
270
+ border-color: transparent;
271
+ &:hover {
272
+ background: ${tokens.colors.purple[100]};
273
+ }
274
+ &:active {
275
+ background: ${tokens.colors.purple[200]};
276
+ }
277
+ `
278
+ }
279
+ if (outline) {
280
+ return css`
281
+ background: transparent;
282
+ color: ${v.bg};
283
+ border-color: ${v.bg};
284
+ &:hover {
285
+ background: ${tokens.colors.purple[100]};
286
+ border-color: ${v.hover};
287
+ }
288
+ &:active {
289
+ background: ${tokens.colors.purple[200]};
290
+ border-color: ${v.active};
291
+ }
292
+ `
293
+ }
294
+ // Default solid button
295
+ return css`
296
+ background: ${v.bg};
297
+ color: ${v.text};
298
+ border-color: ${v.border};
299
+ &:hover {
300
+ background: ${v.hover};
301
+ border-color: ${v.hover};
302
+ }
303
+ &:active {
304
+ background: ${v.active};
305
+ border-color: ${v.active};
306
+ }
307
+ `
308
+ },
309
+ },
310
+ tag: {
311
+ dot: (color: keyof typeof tokens.colors) => css`
312
+ width: ${tokens.size[1.5]};
313
+ height: ${tokens.size[1.5]};
314
+ border-radius: ${tokens.border.radius.full};
315
+ background-color: ${tokens.colors[color][500]};
316
+ `,
317
+ base: css`
318
+ display: flex;
319
+ gap: ${tokens.size[1.5]};
320
+ box-sizing: border-box;
321
+ height: ${tokens.size[6.5]};
322
+ background: ${t(colors.gray[50], colors.darkGray[500])};
323
+ color: ${t(colors.gray[700], colors.gray[300])};
324
+ border-radius: ${tokens.border.radius.sm};
325
+ font-size: ${font.size.sm};
326
+ padding: ${tokens.size[1]};
327
+ padding-left: ${tokens.size[1.5]};
328
+ align-items: center;
329
+ font-weight: ${font.weight.medium};
330
+ border: ${t('1px solid ' + colors.gray[300], '1px solid transparent')};
331
+ user-select: none;
332
+ position: relative;
333
+ &:focus-visible {
334
+ outline-offset: 2px;
335
+ outline: 2px solid ${colors.blue[800]};
336
+ }
337
+ `,
338
+ label: css`
339
+ font-size: ${font.size.xs};
340
+ `,
341
+ count: css`
342
+ font-size: ${font.size.xs};
343
+ padding: 0 5px;
344
+ display: flex;
345
+ align-items: center;
346
+ justify-content: center;
347
+ color: ${t(colors.gray[500], colors.gray[400])};
348
+ background-color: ${t(colors.gray[200], colors.darkGray[300])};
349
+ border-radius: 2px;
350
+ font-variant-numeric: tabular-nums;
351
+ height: ${tokens.size[4.5]};
352
+ `,
353
+ },
354
+ tree: {
355
+ collapsible: css`
356
+ cursor: pointer;
357
+ transition: all 0.2s ease;
358
+ &:hover {
359
+ background-color: ${colors.darkGray[700]};
360
+ border-radius: ${tokens.border.radius.sm};
361
+ padding: 0 ${tokens.size[1]};
362
+ }
363
+ `,
364
+ valueCollapsed: css`
365
+ color: ${colors.gray[400]};
366
+ `,
367
+ valueFunction: css`
368
+ color: ${colors.cyan[400]};
369
+ `,
370
+ valueString: css`
371
+ color: ${colors.green[400]};
372
+ `,
373
+ valueNumber: css`
374
+ color: ${colors.yellow[400]};
375
+ `,
376
+ valueBoolean: css`
377
+ color: ${colors.pink[400]};
378
+ `,
379
+ valueNull: css`
380
+ color: ${colors.gray[400]};
381
+ font-style: italic;
382
+ `,
383
+ valueKey: css`
384
+ color: ${colors.blue[300]};
385
+ `,
386
+ valueBraces: css`
387
+ color: ${colors.gray[500]};
388
+ `,
389
+ valueContainer: (isRoot: boolean) => css`
390
+ display: block;
391
+ margin-left: ${isRoot ? '0' : '1rem'};
392
+ `,
393
+ },
189
394
  }
190
395
  }
191
396