@tanstack/devtools-utils 0.3.3 → 0.4.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 (58) hide show
  1. package/bin/intent.js +20 -0
  2. package/dist/preact/esm/index.js +1 -5
  3. package/dist/preact/esm/panel.d.ts +4 -5
  4. package/dist/preact/esm/panel.js +48 -28
  5. package/dist/preact/esm/panel.js.map +1 -1
  6. package/dist/preact/esm/plugin.d.ts +3 -2
  7. package/dist/preact/esm/plugin.js +20 -22
  8. package/dist/preact/esm/plugin.js.map +1 -1
  9. package/dist/react/esm/index.js +1 -5
  10. package/dist/react/esm/panel.d.ts +4 -4
  11. package/dist/react/esm/panel.js +47 -28
  12. package/dist/react/esm/panel.js.map +1 -1
  13. package/dist/react/esm/plugin.d.ts +3 -2
  14. package/dist/react/esm/plugin.js +20 -22
  15. package/dist/react/esm/plugin.js.map +1 -1
  16. package/dist/solid/esm/chunk/{ZXPCWXRH.js → 7TSS377A.js} +2 -10
  17. package/dist/solid/esm/chunk/{UX5ZZ4MG.js → WUD4VD3N.js} +2 -10
  18. package/dist/solid/esm/class-mount-impl/5TF6RAHJ.js +1 -0
  19. package/dist/solid/esm/class-mount-impl/VN5QTPB3.js +1 -0
  20. package/dist/solid/esm/dev.js +9 -11
  21. package/dist/solid/esm/index.d.ts +10 -10
  22. package/dist/solid/esm/index.js +9 -11
  23. package/dist/solid/esm/server.js +8 -10
  24. package/dist/solid-class/esm/class-mount-impl.d.ts +3 -2
  25. package/dist/solid-class/esm/class-mount-impl.js +17 -23
  26. package/dist/solid-class/esm/class-mount-impl.js.map +1 -1
  27. package/dist/solid-class/esm/class.d.ts +4 -3
  28. package/dist/solid-class/esm/class.js +57 -54
  29. package/dist/solid-class/esm/class.js.map +1 -1
  30. package/dist/solid-class/esm/panel.d.ts +3 -3
  31. package/dist/solid-class/esm/plugin.d.ts +3 -2
  32. package/dist/vue/esm/index.js +1 -5
  33. package/dist/vue/esm/panel.d.ts +3 -3
  34. package/dist/vue/esm/panel.js +36 -45
  35. package/dist/vue/esm/panel.js.map +1 -1
  36. package/dist/vue/esm/plugin.js +20 -19
  37. package/dist/vue/esm/plugin.js.map +1 -1
  38. package/package.json +12 -9
  39. package/skills/devtools-framework-adapters/SKILL.md +263 -0
  40. package/skills/devtools-framework-adapters/references/preact.md +262 -0
  41. package/skills/devtools-framework-adapters/references/react.md +241 -0
  42. package/skills/devtools-framework-adapters/references/solid.md +274 -0
  43. package/skills/devtools-framework-adapters/references/vue.md +270 -0
  44. package/src/preact/panel.tsx +6 -7
  45. package/src/preact/plugin.tsx +4 -3
  46. package/src/react/panel.tsx +6 -7
  47. package/src/react/plugin.tsx +4 -3
  48. package/src/solid/class-mount-impl.tsx +7 -10
  49. package/src/solid/class.test.tsx +43 -12
  50. package/src/solid/class.ts +15 -4
  51. package/src/solid/panel.tsx +6 -7
  52. package/src/solid/plugin.tsx +4 -3
  53. package/src/vue/panel.ts +6 -7
  54. package/dist/preact/esm/index.js.map +0 -1
  55. package/dist/react/esm/index.js.map +0 -1
  56. package/dist/solid/esm/class-mount-impl/LK7V47IP.js +0 -1
  57. package/dist/solid/esm/class-mount-impl/ZAIAXV4M.js +0 -1
  58. package/dist/vue/esm/index.js.map +0 -1
@@ -0,0 +1,270 @@
1
+ # Vue Framework Adapter Reference
2
+
3
+ ## Import
4
+
5
+ ```ts
6
+ import { createVuePlugin, createVuePanel } from '@tanstack/devtools-utils/vue'
7
+ import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/vue'
8
+ ```
9
+
10
+ ## DevtoolsPanelProps
11
+
12
+ ```ts
13
+ // NOTE: Vue includes 'system' -- unlike React/Solid/Preact
14
+ interface DevtoolsPanelProps {
15
+ theme?: 'dark' | 'light' | 'system'
16
+ }
17
+ ```
18
+
19
+ ## createVuePlugin
20
+
21
+ Creates a `[Plugin, NoOpPlugin]` tuple from a Vue component.
22
+
23
+ **CRITICAL: Vue uses positional arguments `(name, component)`, NOT an options object.**
24
+
25
+ ### Signature
26
+
27
+ ```ts
28
+ function createVuePlugin<TComponentProps extends Record<string, any>>(
29
+ name: string,
30
+ component: DefineComponent<TComponentProps, {}, unknown>,
31
+ ): readonly [Plugin, NoOpPlugin]
32
+ ```
33
+
34
+ ### Parameters
35
+
36
+ | Parameter | Type | Required | Description |
37
+ | ----------- | ---------------------------------- | -------- | -------------------------------------- |
38
+ | `name` | `string` | Yes | Display name shown in the devtools tab |
39
+ | `component` | `DefineComponent<TComponentProps>` | Yes | Vue component to render in the panel |
40
+
41
+ Note: There is **no** `id` or `defaultOpen` parameter. Vue plugins are simpler.
42
+
43
+ ### Return Value
44
+
45
+ A `readonly [Plugin, NoOpPlugin]` tuple. Both are **functions that accept props**:
46
+
47
+ - **`Plugin(props: TComponentProps)`** -- returns `{ name, component, props }` where `component` is your Vue component.
48
+ - **`NoOpPlugin(props: TComponentProps)`** -- returns `{ name, component: Fragment, props }` where `Fragment` is Vue's built-in fragment (renders nothing visible).
49
+
50
+ **This differs from React/Solid/Preact** where `Plugin()` takes no arguments.
51
+
52
+ ### Source
53
+
54
+ ```ts
55
+ // packages/devtools-utils/src/vue/plugin.ts
56
+ import { Fragment } from 'vue'
57
+ import type { DefineComponent } from 'vue'
58
+
59
+ export function createVuePlugin<TComponentProps extends Record<string, any>>(
60
+ name: string,
61
+ component: DefineComponent<TComponentProps, {}, unknown>,
62
+ ) {
63
+ function Plugin(props: TComponentProps) {
64
+ return {
65
+ name,
66
+ component,
67
+ props,
68
+ }
69
+ }
70
+ function NoOpPlugin(props: TComponentProps) {
71
+ return {
72
+ name,
73
+ component: Fragment,
74
+ props,
75
+ }
76
+ }
77
+ return [Plugin, NoOpPlugin] as const
78
+ }
79
+ ```
80
+
81
+ ### Usage
82
+
83
+ #### Basic
84
+
85
+ ```vue
86
+ <!-- MyStorePanel.vue -->
87
+ <script setup lang="ts">
88
+ import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/vue'
89
+
90
+ const props = defineProps<DevtoolsPanelProps>()
91
+ </script>
92
+
93
+ <template>
94
+ <div :class="props.theme">
95
+ <h2>My Store Devtools</h2>
96
+ </div>
97
+ </template>
98
+ ```
99
+
100
+ ```ts
101
+ import { createVuePlugin } from '@tanstack/devtools-utils/vue'
102
+ import MyStorePanel from './MyStorePanel.vue'
103
+
104
+ const [MyPlugin, NoOpPlugin] = createVuePlugin('My Store', MyStorePanel)
105
+ ```
106
+
107
+ #### Using the Plugin (Vue-specific -- pass props)
108
+
109
+ ```ts
110
+ // Vue plugins are called WITH props
111
+ const plugin = MyPlugin({ theme: 'dark' })
112
+ // Returns: { name: 'My Store', component: MyStorePanel, props: { theme: 'dark' } }
113
+
114
+ const noopPlugin = NoOpPlugin({ theme: 'dark' })
115
+ // Returns: { name: 'My Store', component: Fragment, props: { theme: 'dark' } }
116
+ ```
117
+
118
+ #### Production Tree-Shaking
119
+
120
+ ```ts
121
+ const [MyPlugin, NoOpPlugin] = createVuePlugin('My Store', MyStorePanel)
122
+
123
+ const ActivePlugin = import.meta.env.DEV ? MyPlugin : NoOpPlugin
124
+ ```
125
+
126
+ ## createVuePanel
127
+
128
+ Wraps a class-based devtools core in a Vue `defineComponent`.
129
+
130
+ ### Signature
131
+
132
+ ```ts
133
+ function createVuePanel<
134
+ TComponentProps extends DevtoolsPanelProps,
135
+ TCoreDevtoolsClass extends {
136
+ mount: (el: HTMLElement, theme?: DevtoolsPanelProps['theme']) => void
137
+ unmount: () => void
138
+ },
139
+ >(
140
+ CoreClass: new (props: TComponentProps) => TCoreDevtoolsClass,
141
+ ): readonly [Panel, NoOpPanel]
142
+ ```
143
+
144
+ ### Parameters
145
+
146
+ | Parameter | Type | Required | Description |
147
+ | ----------- | ------------------------------------------------------------------------------ | -------- | ------------------------------------------------------------------------------------------------ |
148
+ | `CoreClass` | `new (props: TComponentProps) => { mount(el, theme?): void; unmount(): void }` | Yes | Class constructor. **Note:** Vue's constructor takes `props`, unlike React's no-arg constructor. |
149
+
150
+ ### Return Value
151
+
152
+ A tuple of two Vue `DefineComponent`s:
153
+
154
+ - **`Panel`** -- Accepts `theme` and `devtoolsProps` as props. On `onMounted`, instantiates `CoreClass(devtoolsProps)` and calls `mount(el, theme)`. On `onUnmounted`, calls `unmount()`. Renders a `<div style="height:100%">`.
155
+ - **`NoOpPanel`** -- Renders `null`.
156
+
157
+ Both components have the type:
158
+
159
+ ```ts
160
+ DefineComponent<{
161
+ theme?: 'dark' | 'light' | 'system'
162
+ devtoolsProps: TComponentProps
163
+ }>
164
+ ```
165
+
166
+ ### Source
167
+
168
+ ```ts
169
+ // packages/devtools-utils/src/vue/panel.ts
170
+ export function createVuePanel<
171
+ TComponentProps extends DevtoolsPanelProps,
172
+ TCoreDevtoolsClass extends {
173
+ mount: (el: HTMLElement, theme?: DevtoolsPanelProps['theme']) => void
174
+ unmount: () => void
175
+ },
176
+ >(CoreClass: new (props: TComponentProps) => TCoreDevtoolsClass) {
177
+ const props = {
178
+ theme: { type: String as () => DevtoolsPanelProps['theme'] },
179
+ devtoolsProps: { type: Object as () => TComponentProps },
180
+ }
181
+
182
+ const Panel = defineComponent({
183
+ props,
184
+ setup(config) {
185
+ const devToolRef = ref<HTMLElement | null>(null)
186
+ const devtools = ref<TCoreDevtoolsClass | null>(null)
187
+ onMounted(() => {
188
+ const instance = new CoreClass(config.devtoolsProps as TComponentProps)
189
+ devtools.value = instance
190
+ if (devToolRef.value) {
191
+ instance.mount(devToolRef.value, config.theme)
192
+ }
193
+ })
194
+ onUnmounted(() => {
195
+ if (devToolRef.value && devtools.value) {
196
+ devtools.value.unmount()
197
+ }
198
+ })
199
+ return () => h('div', { style: { height: '100%' }, ref: devToolRef })
200
+ },
201
+ })
202
+
203
+ const NoOpPanel = defineComponent({
204
+ props,
205
+ setup() {
206
+ return () => null
207
+ },
208
+ })
209
+
210
+ return [Panel, NoOpPanel] as unknown as [
211
+ DefineComponent<{
212
+ theme?: DevtoolsPanelProps['theme']
213
+ devtoolsProps: TComponentProps
214
+ }>,
215
+ DefineComponent<{
216
+ theme?: DevtoolsPanelProps['theme']
217
+ devtoolsProps: TComponentProps
218
+ }>,
219
+ ]
220
+ }
221
+ ```
222
+
223
+ ### Usage
224
+
225
+ ```ts
226
+ import { createVuePanel, createVuePlugin } from '@tanstack/devtools-utils/vue'
227
+
228
+ class MyDevtoolsCore {
229
+ constructor(private props: { theme?: string }) {}
230
+ mount(el: HTMLElement, theme?: 'dark' | 'light' | 'system') {
231
+ // render into el
232
+ }
233
+ unmount() {
234
+ // cleanup
235
+ }
236
+ }
237
+
238
+ // Step 1: Create panel from class
239
+ const [MyPanel, NoOpPanel] = createVuePanel(MyDevtoolsCore)
240
+
241
+ // Step 2: Create plugin from panel
242
+ const [MyPlugin, NoOpPlugin] = createVuePlugin('My Store', MyPanel)
243
+ ```
244
+
245
+ #### Using the Panel Directly in a Template
246
+
247
+ ```vue
248
+ <template>
249
+ <MyPanel
250
+ theme="dark"
251
+ :devtools-props="{
252
+ /* ... */
253
+ }"
254
+ />
255
+ </template>
256
+ ```
257
+
258
+ ## Vue-Specific Gotchas
259
+
260
+ 1. **Positional arguments, not options object.** This is the most common mistake. `createVuePlugin('name', Component)`, not `createVuePlugin({ name, Component })`.
261
+
262
+ 2. **Plugin functions accept props.** `MyPlugin(props)` returns `{ name, component, props }`. This differs from React/Solid/Preact where `Plugin()` takes no arguments.
263
+
264
+ 3. **Theme includes `'system'`.** Vue's `DevtoolsPanelProps` accepts `'dark' | 'light' | 'system'`, while all other frameworks only accept `'light' | 'dark'`.
265
+
266
+ 4. **No `id` or `defaultOpen`.** The Vue `createVuePlugin` API only takes `name` and `component`. There is no `id` or `defaultOpen` parameter.
267
+
268
+ 5. **Panel constructor takes props.** `createVuePanel`'s `CoreClass` constructor receives props: `new CoreClass(devtoolsProps)`. React/Preact/Solid constructors take no arguments.
269
+
270
+ 6. **`devtoolsProps` prop on panel.** The Vue panel component has a separate `devtoolsProps` prop for forwarding data to the core class, in addition to the `theme` prop.
@@ -1,10 +1,9 @@
1
1
  /** @jsxImportSource preact */
2
2
 
3
3
  import { useEffect, useRef } from 'preact/hooks'
4
+ import type { TanStackDevtoolsPluginProps } from '@tanstack/devtools'
4
5
 
5
- export interface DevtoolsPanelProps {
6
- theme?: 'light' | 'dark'
7
- }
6
+ export interface DevtoolsPanelProps extends TanStackDevtoolsPluginProps {}
8
7
 
9
8
  /**
10
9
  * Creates a Preact component that dynamically imports and mounts a devtools panel. SSR friendly.
@@ -24,9 +23,9 @@ export interface DevtoolsPanelProps {
24
23
  * ```
25
24
  */
26
25
  export function createPreactPanel<
27
- TComponentProps extends DevtoolsPanelProps | undefined,
26
+ TComponentProps extends DevtoolsPanelProps,
28
27
  TCoreDevtoolsClass extends {
29
- mount: (el: HTMLElement, theme: 'light' | 'dark') => void
28
+ mount: (el: HTMLElement, props: TanStackDevtoolsPluginProps) => void
30
29
  unmount: () => void
31
30
  },
32
31
  >(CoreClass: new () => TCoreDevtoolsClass) {
@@ -38,7 +37,7 @@ export function createPreactPanel<
38
37
  devtools.current = new CoreClass()
39
38
 
40
39
  if (devToolRef.current) {
41
- devtools.current.mount(devToolRef.current, props?.theme ?? 'dark')
40
+ devtools.current.mount(devToolRef.current, props)
42
41
  }
43
42
 
44
43
  return () => {
@@ -47,7 +46,7 @@ export function createPreactPanel<
47
46
  devtools.current = null
48
47
  }
49
48
  }
50
- }, [props?.theme])
49
+ }, [props])
51
50
 
52
51
  return <div style={{ height: '100%' }} ref={devToolRef} />
53
52
  }
@@ -2,6 +2,7 @@
2
2
 
3
3
  import type { JSX } from 'preact'
4
4
  import type { DevtoolsPanelProps } from './panel'
5
+ import type { TanStackDevtoolsPluginProps } from '@tanstack/devtools'
5
6
 
6
7
  export function createPreactPlugin({
7
8
  Component,
@@ -15,15 +16,15 @@ export function createPreactPlugin({
15
16
  function Plugin() {
16
17
  return {
17
18
  ...config,
18
- render: (_el: HTMLElement, theme: 'light' | 'dark') => (
19
- <Component theme={theme} />
19
+ render: (_el: HTMLElement, props: TanStackDevtoolsPluginProps) => (
20
+ <Component {...props} />
20
21
  ),
21
22
  }
22
23
  }
23
24
  function NoOpPlugin() {
24
25
  return {
25
26
  ...config,
26
- render: (_el: HTMLElement, _theme: 'light' | 'dark') => <></>,
27
+ render: (_el: HTMLElement, _props: TanStackDevtoolsPluginProps) => <></>,
27
28
  }
28
29
  }
29
30
  return [Plugin, NoOpPlugin] as const
@@ -1,8 +1,7 @@
1
1
  import { useEffect, useRef } from 'react'
2
+ import type { TanStackDevtoolsPluginProps } from '@tanstack/devtools'
2
3
 
3
- export interface DevtoolsPanelProps {
4
- theme?: 'light' | 'dark'
5
- }
4
+ export interface DevtoolsPanelProps extends TanStackDevtoolsPluginProps {}
6
5
 
7
6
  /**
8
7
  * Creates a React component that dynamically imports and mounts a devtools panel. SSR friendly.
@@ -22,9 +21,9 @@ export interface DevtoolsPanelProps {
22
21
  * ```
23
22
  */
24
23
  export function createReactPanel<
25
- TComponentProps extends DevtoolsPanelProps | undefined,
24
+ TComponentProps extends TanStackDevtoolsPluginProps,
26
25
  TCoreDevtoolsClass extends {
27
- mount: (el: HTMLElement, theme: 'light' | 'dark') => void
26
+ mount: (el: HTMLElement, props: TanStackDevtoolsPluginProps) => void
28
27
  unmount: () => void
29
28
  },
30
29
  >(CoreClass: new () => TCoreDevtoolsClass) {
@@ -36,7 +35,7 @@ export function createReactPanel<
36
35
  devtools.current = new CoreClass()
37
36
 
38
37
  if (devToolRef.current) {
39
- devtools.current.mount(devToolRef.current, props?.theme ?? 'dark')
38
+ devtools.current.mount(devToolRef.current, props)
40
39
  }
41
40
 
42
41
  return () => {
@@ -45,7 +44,7 @@ export function createReactPanel<
45
44
  devtools.current = null
46
45
  }
47
46
  }
48
- }, [props?.theme])
47
+ }, [props])
49
48
 
50
49
  return <div style={{ height: '100%' }} ref={devToolRef} />
51
50
  }
@@ -1,5 +1,6 @@
1
1
  import type { JSX } from 'react'
2
2
  import type { DevtoolsPanelProps } from './panel'
3
+ import type { TanStackDevtoolsPluginProps } from '@tanstack/devtools'
3
4
 
4
5
  export function createReactPlugin({
5
6
  Component,
@@ -13,15 +14,15 @@ export function createReactPlugin({
13
14
  function Plugin() {
14
15
  return {
15
16
  ...config,
16
- render: (_el: HTMLElement, theme: 'light' | 'dark') => (
17
- <Component theme={theme} />
17
+ render: (_el: HTMLElement, props: TanStackDevtoolsPluginProps) => (
18
+ <Component {...props} />
18
19
  ),
19
20
  }
20
21
  }
21
22
  function NoOpPlugin() {
22
23
  return {
23
24
  ...config,
24
- render: (_el: HTMLElement, _theme: 'light' | 'dark') => <></>,
25
+ render: (_el: HTMLElement, _props: TanStackDevtoolsPluginProps) => <></>,
25
26
  }
26
27
  }
27
28
  return [Plugin, NoOpPlugin] as const
@@ -2,27 +2,24 @@
2
2
 
3
3
  import { lazy } from 'solid-js'
4
4
  import { Portal, render } from 'solid-js/web'
5
+
5
6
  import type { JSX } from 'solid-js'
7
+ import type { TanStackDevtoolsPluginProps } from '@tanstack/devtools'
6
8
 
7
9
  export function __mountComponent(
8
10
  el: HTMLElement,
9
- theme: 'light' | 'dark',
10
- importFn: () => Promise<{ default: () => JSX.Element }>,
11
+ props: TanStackDevtoolsPluginProps,
12
+ importFn: () => Promise<{
13
+ default: (props: TanStackDevtoolsPluginProps) => JSX.Element
14
+ }>,
11
15
  ): () => void {
12
16
  const Component = lazy(importFn)
13
- const ThemeProvider = lazy(() =>
14
- import('@tanstack/devtools-ui').then((m) => ({
15
- default: m.ThemeContextProvider,
16
- })),
17
- )
18
17
 
19
18
  return render(
20
19
  () => (
21
20
  <Portal mount={el}>
22
21
  <div style={{ height: '100%' }}>
23
- <ThemeProvider theme={theme}>
24
- <Component />
25
- </ThemeProvider>
22
+ <Component {...props} />
26
23
  </div>
27
24
  </Portal>
28
25
  ),
@@ -28,16 +28,23 @@ describe('constructCoreClass', () => {
28
28
  const [DevtoolsCore] = constructCoreClass(importFn)
29
29
  const instance = new DevtoolsCore()
30
30
  const el = document.createElement('div')
31
- await instance.mount(el, 'dark')
32
- expect(mountComponentMock).toHaveBeenCalledWith(el, 'dark', importFn)
31
+ const props = { theme: 'dark' as const, devtoolsOpen: true }
32
+ await instance.mount(el, props)
33
+ expect(mountComponentMock).toHaveBeenCalledWith(el, props, importFn)
33
34
  })
34
35
 
35
36
  it('DevtoolsCore should throw if mount is called twice without unmounting', async () => {
36
37
  const [DevtoolsCore] = constructCoreClass(importFn)
37
38
  const instance = new DevtoolsCore()
38
- await instance.mount(document.createElement('div'), 'dark')
39
+ await instance.mount(document.createElement('div'), {
40
+ theme: 'dark',
41
+ devtoolsOpen: true,
42
+ })
39
43
  await expect(
40
- instance.mount(document.createElement('div'), 'dark'),
44
+ instance.mount(document.createElement('div'), {
45
+ theme: 'dark',
46
+ devtoolsOpen: true,
47
+ }),
41
48
  ).rejects.toThrow('Devtools is already mounted')
42
49
  })
43
50
 
@@ -50,17 +57,26 @@ describe('constructCoreClass', () => {
50
57
  it('DevtoolsCore should allow mount after unmount', async () => {
51
58
  const [DevtoolsCore] = constructCoreClass(importFn)
52
59
  const instance = new DevtoolsCore()
53
- await instance.mount(document.createElement('div'), 'dark')
60
+ await instance.mount(document.createElement('div'), {
61
+ theme: 'dark',
62
+ devtoolsOpen: true,
63
+ })
54
64
  instance.unmount()
55
65
  await expect(
56
- instance.mount(document.createElement('div'), 'dark'),
66
+ instance.mount(document.createElement('div'), {
67
+ theme: 'dark',
68
+ devtoolsOpen: true,
69
+ }),
57
70
  ).resolves.not.toThrow()
58
71
  })
59
72
 
60
73
  it('DevtoolsCore should call dispose on unmount', async () => {
61
74
  const [DevtoolsCore] = constructCoreClass(importFn)
62
75
  const instance = new DevtoolsCore()
63
- await instance.mount(document.createElement('div'), 'dark')
76
+ await instance.mount(document.createElement('div'), {
77
+ theme: 'dark',
78
+ devtoolsOpen: true,
79
+ })
64
80
  instance.unmount()
65
81
  expect(disposeMock).toHaveBeenCalled()
66
82
  })
@@ -68,7 +84,10 @@ describe('constructCoreClass', () => {
68
84
  it('DevtoolsCore should abort mount if unmount is called during mounting', async () => {
69
85
  const [DevtoolsCore] = constructCoreClass(importFn)
70
86
  const instance = new DevtoolsCore()
71
- const mountPromise = instance.mount(document.createElement('div'), 'dark')
87
+ const mountPromise = instance.mount(document.createElement('div'), {
88
+ theme: 'dark',
89
+ devtoolsOpen: true,
90
+ })
72
91
  // Unmount while mount is in progress — triggers abort path
73
92
  // Note: since the mock resolves immediately, this tests the #abortMount flag
74
93
  await mountPromise
@@ -80,16 +99,25 @@ describe('constructCoreClass', () => {
80
99
  it('NoOpDevtoolsCore should not call __mountComponent when mount is called', async () => {
81
100
  const [, NoOpDevtoolsCore] = constructCoreClass(importFn)
82
101
  const noOpInstance = new NoOpDevtoolsCore()
83
- await noOpInstance.mount(document.createElement('div'), 'dark')
102
+ await noOpInstance.mount(document.createElement('div'), {
103
+ theme: 'dark',
104
+ devtoolsOpen: true,
105
+ })
84
106
  expect(mountComponentMock).not.toHaveBeenCalled()
85
107
  })
86
108
 
87
109
  it('NoOpDevtoolsCore should not throw if mount is called multiple times', async () => {
88
110
  const [, NoOpDevtoolsCore] = constructCoreClass(importFn)
89
111
  const noOpInstance = new NoOpDevtoolsCore()
90
- await noOpInstance.mount(document.createElement('div'), 'dark')
112
+ await noOpInstance.mount(document.createElement('div'), {
113
+ theme: 'dark',
114
+ devtoolsOpen: true,
115
+ })
91
116
  await expect(
92
- noOpInstance.mount(document.createElement('div'), 'dark'),
117
+ noOpInstance.mount(document.createElement('div'), {
118
+ theme: 'dark',
119
+ devtoolsOpen: true,
120
+ }),
93
121
  ).resolves.not.toThrow()
94
122
  })
95
123
 
@@ -102,7 +130,10 @@ describe('constructCoreClass', () => {
102
130
  it('NoOpDevtoolsCore should not throw if unmount is called after mount', async () => {
103
131
  const [, NoOpDevtoolsCore] = constructCoreClass(importFn)
104
132
  const noOpInstance = new NoOpDevtoolsCore()
105
- await noOpInstance.mount(document.createElement('div'), 'dark')
133
+ await noOpInstance.mount(document.createElement('div'), {
134
+ theme: 'dark',
135
+ devtoolsOpen: true,
136
+ })
106
137
  expect(() => noOpInstance.unmount()).not.toThrow()
107
138
  })
108
139
  })
@@ -1,3 +1,4 @@
1
+ import type { TanStackDevtoolsPluginProps } from '@tanstack/devtools'
1
2
  import type { JSX } from 'solid-js'
2
3
 
3
4
  /**
@@ -10,7 +11,9 @@ import type { JSX } from 'solid-js'
10
11
  * @returns Tuple containing the DevtoolsCore class and a NoOpDevtoolsCore class
11
12
  */
12
13
  export function constructCoreClass(
13
- importFn: () => Promise<{ default: () => JSX.Element }>,
14
+ importFn: () => Promise<{
15
+ default: (props: TanStackDevtoolsPluginProps) => JSX.Element
16
+ }>,
14
17
  ) {
15
18
  class DevtoolsCore {
16
19
  #isMounted = false
@@ -20,7 +23,10 @@ export function constructCoreClass(
20
23
 
21
24
  constructor() {}
22
25
 
23
- async mount<T extends HTMLElement>(el: T, theme: 'light' | 'dark') {
26
+ async mount<T extends HTMLElement>(
27
+ el: T,
28
+ props: TanStackDevtoolsPluginProps,
29
+ ) {
24
30
  if (this.#isMounted || this.#isMounting) {
25
31
  throw new Error('Devtools is already mounted')
26
32
  }
@@ -35,7 +41,7 @@ export function constructCoreClass(
35
41
  return
36
42
  }
37
43
 
38
- this.#dispose = __mountComponent(el, theme, importFn)
44
+ this.#dispose = __mountComponent(el, props, importFn)
39
45
  this.#isMounted = true
40
46
  this.#isMounting = false
41
47
  } catch (err) {
@@ -48,11 +54,13 @@ export function constructCoreClass(
48
54
  if (!this.#isMounted && !this.#isMounting) {
49
55
  throw new Error('Devtools is not mounted')
50
56
  }
57
+
51
58
  if (this.#isMounting) {
52
59
  this.#abortMount = true
53
60
  this.#isMounting = false
54
61
  return
55
62
  }
63
+
56
64
  this.#dispose?.()
57
65
  this.#isMounted = false
58
66
  }
@@ -62,7 +70,10 @@ export function constructCoreClass(
62
70
  constructor() {
63
71
  super()
64
72
  }
65
- async mount<T extends HTMLElement>(_el: T, _theme: 'light' | 'dark') {}
73
+ async mount<T extends HTMLElement>(
74
+ _el: T,
75
+ _props: TanStackDevtoolsPluginProps,
76
+ ) {}
66
77
  unmount() {}
67
78
  }
68
79
 
@@ -2,20 +2,19 @@
2
2
 
3
3
  import { createSignal, onCleanup, onMount } from 'solid-js'
4
4
  import type { ClassType } from './class'
5
+ import type { TanStackDevtoolsPluginProps } from '@tanstack/devtools'
5
6
 
6
- export interface DevtoolsPanelProps {
7
- theme?: 'light' | 'dark'
8
- }
7
+ export interface DevtoolsPanelProps extends TanStackDevtoolsPluginProps {}
9
8
 
10
- export function createSolidPanel<
11
- TComponentProps extends DevtoolsPanelProps | undefined,
12
- >(CoreClass: ClassType) {
9
+ export function createSolidPanel<TComponentProps extends DevtoolsPanelProps>(
10
+ CoreClass: ClassType,
11
+ ) {
13
12
  function Panel(props: TComponentProps) {
14
13
  let devToolRef: HTMLDivElement | undefined
15
14
  const [devtools] = createSignal(new CoreClass())
16
15
  onMount(() => {
17
16
  if (devToolRef) {
18
- devtools().mount(devToolRef, props?.theme ?? 'dark')
17
+ devtools().mount(devToolRef, props)
19
18
  }
20
19
  onCleanup(() => {
21
20
  devtools().unmount()
@@ -2,6 +2,7 @@
2
2
 
3
3
  import type { JSX } from 'solid-js'
4
4
  import type { DevtoolsPanelProps } from './panel'
5
+ import type { TanStackDevtoolsPluginProps } from '@tanstack/devtools'
5
6
 
6
7
  export function createSolidPlugin({
7
8
  Component,
@@ -15,15 +16,15 @@ export function createSolidPlugin({
15
16
  function Plugin() {
16
17
  return {
17
18
  ...config,
18
- render: (_el: HTMLElement, theme: 'light' | 'dark') => {
19
- return <Component theme={theme} />
19
+ render: (_el: HTMLElement, props: TanStackDevtoolsPluginProps) => {
20
+ return <Component {...props} />
20
21
  },
21
22
  }
22
23
  }
23
24
  function NoOpPlugin() {
24
25
  return {
25
26
  ...config,
26
- render: (_el: HTMLElement, _theme: 'light' | 'dark') => <></>,
27
+ render: (_el: HTMLElement, _props: TanStackDevtoolsPluginProps) => <></>,
27
28
  }
28
29
  }
29
30
  return [Plugin, NoOpPlugin] as const