@tanstack/devtools-ui 0.3.0 → 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 (38) 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 +180 -117
  8. package/dist/cjs/components/tree.cjs.map +1 -1
  9. package/dist/cjs/index.cjs +4 -0
  10. package/dist/cjs/index.cjs.map +1 -1
  11. package/dist/cjs/index.d.cts +2 -0
  12. package/dist/cjs/styles/tokens.cjs +143 -7
  13. package/dist/cjs/styles/tokens.cjs.map +1 -1
  14. package/dist/cjs/styles/use-styles.cjs +176 -1
  15. package/dist/cjs/styles/use-styles.cjs.map +1 -1
  16. package/dist/cjs/styles/use-styles.d.cts +15 -0
  17. package/dist/esm/components/button.d.ts +11 -0
  18. package/dist/esm/components/button.js +23 -0
  19. package/dist/esm/components/button.js.map +1 -0
  20. package/dist/esm/components/tag.d.ts +7 -0
  21. package/dist/esm/components/tag.js +40 -0
  22. package/dist/esm/components/tag.js.map +1 -0
  23. package/dist/esm/components/tree.js +182 -119
  24. package/dist/esm/components/tree.js.map +1 -1
  25. package/dist/esm/index.d.ts +2 -0
  26. package/dist/esm/index.js +4 -0
  27. package/dist/esm/index.js.map +1 -1
  28. package/dist/esm/styles/tokens.js +143 -7
  29. package/dist/esm/styles/tokens.js.map +1 -1
  30. package/dist/esm/styles/use-styles.d.ts +15 -0
  31. package/dist/esm/styles/use-styles.js +176 -1
  32. package/dist/esm/styles/use-styles.js.map +1 -1
  33. package/package.json +2 -1
  34. package/src/components/button.tsx +42 -0
  35. package/src/components/tag.tsx +22 -0
  36. package/src/components/tree.tsx +125 -92
  37. package/src/index.ts +2 -0
  38. package/src/styles/use-styles.ts +181 -1
@@ -1,4 +1,5 @@
1
- import { For } from 'solid-js'
1
+ import { For, Show, createSignal } from 'solid-js'
2
+ import clsx from 'clsx'
2
3
  import { useStyles } from '../styles/use-styles'
3
4
 
4
5
  export function JsonTree(props: { value: any }) {
@@ -16,115 +17,37 @@ function JsonValue(props: {
16
17
 
17
18
  return (
18
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
+ )}
19
23
  {(() => {
20
24
  if (typeof value === 'string') {
21
25
  return (
22
- <span>
23
- {keyName && (
24
- <span class={styles().tree.valueKey}>
25
- &quot;{keyName}&quot;:{' '}
26
- </span>
27
- )}
28
- <span class={styles().tree.valueString}>&quot;{value}&quot;</span>
29
- </span>
26
+ <span class={styles().tree.valueString}>&quot;{value}&quot;</span>
30
27
  )
31
28
  }
32
29
  if (typeof value === 'number') {
33
- return (
34
- <span>
35
- {keyName && (
36
- <span class={styles().tree.valueKey}>
37
- &quot;{keyName}&quot;:{' '}
38
- </span>
39
- )}
40
- <span class={styles().tree.valueNumber}>{value}</span>
41
- </span>
42
- )
30
+ return <span class={styles().tree.valueNumber}>{value}</span>
43
31
  }
44
32
  if (typeof value === 'boolean') {
45
- return (
46
- <span>
47
- {keyName && (
48
- <span class={styles().tree.valueKey}>
49
- &quot;{keyName}&quot;:{' '}
50
- </span>
51
- )}
52
- <span class={styles().tree.valueBoolean}>{String(value)}</span>
53
- </span>
54
- )
33
+ return <span class={styles().tree.valueBoolean}>{String(value)}</span>
55
34
  }
56
35
  if (value === null) {
57
- return (
58
- <span>
59
- {keyName && (
60
- <span class={styles().tree.valueKey}>
61
- &quot;{keyName}&quot;:{' '}
62
- </span>
63
- )}
64
- <span class={styles().tree.valueNull}>null</span>
65
- </span>
66
- )
36
+ return <span class={styles().tree.valueNull}>null</span>
67
37
  }
68
38
  if (value === undefined) {
39
+ return <span class={styles().tree.valueNull}>undefined</span>
40
+ }
41
+ if (typeof value === 'function') {
69
42
  return (
70
- <span>
71
- {keyName && (
72
- <span class={styles().tree.valueKey}>
73
- &quot;{keyName}&quot;:{' '}
74
- </span>
75
- )}
76
- <span class={styles().tree.valueNull}>undefined</span>
77
- </span>
43
+ <span class={styles().tree.valueFunction}>{String(value)}</span>
78
44
  )
79
45
  }
80
46
  if (Array.isArray(value)) {
81
- return (
82
- <span>
83
- {keyName && (
84
- <span class={styles().tree.valueKey}>
85
- &quot;{keyName}&quot;:{' '}
86
- </span>
87
- )}
88
- <span class={styles().tree.valueBraces}>[</span>
89
- <For each={value}>
90
- {(item, i) => {
91
- const isLastKey = i() === value.length - 1
92
- return (
93
- <>
94
- <JsonValue value={item} isLastKey={isLastKey} />
95
- </>
96
- )
97
- }}
98
- </For>
99
- <span class={styles().tree.valueBraces}>]</span>
100
- </span>
101
- )
47
+ return <ArrayValue keyName={keyName} value={value} />
102
48
  }
103
49
  if (typeof value === 'object') {
104
- const keys = Object.keys(value)
105
- const lastKeyName = keys[keys.length - 1]
106
- return (
107
- <span>
108
- {keyName && (
109
- <span class={styles().tree.valueKey}>
110
- &quot;{keyName}&quot;:{' '}
111
- </span>
112
- )}
113
- <span class={styles().tree.valueBraces}>{'{'}</span>
114
- <For each={keys}>
115
- {(k) => (
116
- <>
117
- <JsonValue
118
- value={value[k]}
119
- keyName={k}
120
- isLastKey={lastKeyName === k}
121
- />
122
- </>
123
- )}
124
- </For>
125
- <span class={styles().tree.valueBraces}>{'}'}</span>
126
- </span>
127
- )
50
+ return <ObjectValue keyName={keyName} value={value} />
128
51
  }
129
52
  return <span />
130
53
  })()}
@@ -132,3 +55,113 @@ function JsonValue(props: {
132
55
  </span>
133
56
  )
134
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
@@ -3,3 +3,5 @@ export { Input } from './components/input'
3
3
  export { Select } from './components/select'
4
4
  export { TanStackLogo } from './components/logo'
5
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,13 +233,140 @@ 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
+ },
189
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
+ `,
190
370
  valueString: css`
191
371
  color: ${colors.green[400]};
192
372
  `,