@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.
- package/bin/intent.js +20 -0
- package/dist/preact/esm/index.js +1 -5
- package/dist/preact/esm/panel.d.ts +4 -5
- package/dist/preact/esm/panel.js +48 -28
- package/dist/preact/esm/panel.js.map +1 -1
- package/dist/preact/esm/plugin.d.ts +3 -2
- package/dist/preact/esm/plugin.js +20 -22
- package/dist/preact/esm/plugin.js.map +1 -1
- package/dist/react/esm/index.js +1 -5
- package/dist/react/esm/panel.d.ts +4 -4
- package/dist/react/esm/panel.js +47 -28
- package/dist/react/esm/panel.js.map +1 -1
- package/dist/react/esm/plugin.d.ts +3 -2
- package/dist/react/esm/plugin.js +20 -22
- package/dist/react/esm/plugin.js.map +1 -1
- package/dist/solid/esm/chunk/{ZXPCWXRH.js → 7TSS377A.js} +2 -10
- package/dist/solid/esm/chunk/{UX5ZZ4MG.js → WUD4VD3N.js} +2 -10
- package/dist/solid/esm/class-mount-impl/5TF6RAHJ.js +1 -0
- package/dist/solid/esm/class-mount-impl/VN5QTPB3.js +1 -0
- package/dist/solid/esm/dev.js +9 -11
- package/dist/solid/esm/index.d.ts +10 -10
- package/dist/solid/esm/index.js +9 -11
- package/dist/solid/esm/server.js +8 -10
- package/dist/solid-class/esm/class-mount-impl.d.ts +3 -2
- package/dist/solid-class/esm/class-mount-impl.js +17 -23
- package/dist/solid-class/esm/class-mount-impl.js.map +1 -1
- package/dist/solid-class/esm/class.d.ts +4 -3
- package/dist/solid-class/esm/class.js +57 -54
- package/dist/solid-class/esm/class.js.map +1 -1
- package/dist/solid-class/esm/panel.d.ts +3 -3
- package/dist/solid-class/esm/plugin.d.ts +3 -2
- package/dist/vue/esm/index.js +1 -5
- package/dist/vue/esm/panel.d.ts +3 -3
- package/dist/vue/esm/panel.js +36 -45
- package/dist/vue/esm/panel.js.map +1 -1
- package/dist/vue/esm/plugin.js +20 -19
- package/dist/vue/esm/plugin.js.map +1 -1
- package/package.json +12 -9
- package/skills/devtools-framework-adapters/SKILL.md +263 -0
- package/skills/devtools-framework-adapters/references/preact.md +262 -0
- package/skills/devtools-framework-adapters/references/react.md +241 -0
- package/skills/devtools-framework-adapters/references/solid.md +274 -0
- package/skills/devtools-framework-adapters/references/vue.md +270 -0
- package/src/preact/panel.tsx +6 -7
- package/src/preact/plugin.tsx +4 -3
- package/src/react/panel.tsx +6 -7
- package/src/react/plugin.tsx +4 -3
- package/src/solid/class-mount-impl.tsx +7 -10
- package/src/solid/class.test.tsx +43 -12
- package/src/solid/class.ts +15 -4
- package/src/solid/panel.tsx +6 -7
- package/src/solid/plugin.tsx +4 -3
- package/src/vue/panel.ts +6 -7
- package/dist/preact/esm/index.js.map +0 -1
- package/dist/react/esm/index.js.map +0 -1
- package/dist/solid/esm/class-mount-impl/LK7V47IP.js +0 -1
- package/dist/solid/esm/class-mount-impl/ZAIAXV4M.js +0 -1
- 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.
|
package/src/preact/panel.tsx
CHANGED
|
@@ -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
|
|
26
|
+
TComponentProps extends DevtoolsPanelProps,
|
|
28
27
|
TCoreDevtoolsClass extends {
|
|
29
|
-
mount: (el: HTMLElement,
|
|
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
|
|
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
|
|
49
|
+
}, [props])
|
|
51
50
|
|
|
52
51
|
return <div style={{ height: '100%' }} ref={devToolRef} />
|
|
53
52
|
}
|
package/src/preact/plugin.tsx
CHANGED
|
@@ -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,
|
|
19
|
-
<Component
|
|
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,
|
|
27
|
+
render: (_el: HTMLElement, _props: TanStackDevtoolsPluginProps) => <></>,
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
return [Plugin, NoOpPlugin] as const
|
package/src/react/panel.tsx
CHANGED
|
@@ -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
|
|
24
|
+
TComponentProps extends TanStackDevtoolsPluginProps,
|
|
26
25
|
TCoreDevtoolsClass extends {
|
|
27
|
-
mount: (el: HTMLElement,
|
|
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
|
|
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
|
|
47
|
+
}, [props])
|
|
49
48
|
|
|
50
49
|
return <div style={{ height: '100%' }} ref={devToolRef} />
|
|
51
50
|
}
|
package/src/react/plugin.tsx
CHANGED
|
@@ -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,
|
|
17
|
-
<Component
|
|
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,
|
|
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
|
-
|
|
10
|
-
importFn: () => Promise<{
|
|
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
|
-
<
|
|
24
|
-
<Component />
|
|
25
|
-
</ThemeProvider>
|
|
22
|
+
<Component {...props} />
|
|
26
23
|
</div>
|
|
27
24
|
</Portal>
|
|
28
25
|
),
|
package/src/solid/class.test.tsx
CHANGED
|
@@ -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
|
-
|
|
32
|
-
|
|
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'),
|
|
39
|
+
await instance.mount(document.createElement('div'), {
|
|
40
|
+
theme: 'dark',
|
|
41
|
+
devtoolsOpen: true,
|
|
42
|
+
})
|
|
39
43
|
await expect(
|
|
40
|
-
instance.mount(document.createElement('div'),
|
|
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'),
|
|
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'),
|
|
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'),
|
|
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'),
|
|
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'),
|
|
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'),
|
|
112
|
+
await noOpInstance.mount(document.createElement('div'), {
|
|
113
|
+
theme: 'dark',
|
|
114
|
+
devtoolsOpen: true,
|
|
115
|
+
})
|
|
91
116
|
await expect(
|
|
92
|
-
noOpInstance.mount(document.createElement('div'),
|
|
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'),
|
|
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
|
})
|
package/src/solid/class.ts
CHANGED
|
@@ -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<{
|
|
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>(
|
|
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,
|
|
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>(
|
|
73
|
+
async mount<T extends HTMLElement>(
|
|
74
|
+
_el: T,
|
|
75
|
+
_props: TanStackDevtoolsPluginProps,
|
|
76
|
+
) {}
|
|
66
77
|
unmount() {}
|
|
67
78
|
}
|
|
68
79
|
|
package/src/solid/panel.tsx
CHANGED
|
@@ -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
|
-
|
|
12
|
-
|
|
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
|
|
17
|
+
devtools().mount(devToolRef, props)
|
|
19
18
|
}
|
|
20
19
|
onCleanup(() => {
|
|
21
20
|
devtools().unmount()
|
package/src/solid/plugin.tsx
CHANGED
|
@@ -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,
|
|
19
|
-
return <Component
|
|
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,
|
|
27
|
+
render: (_el: HTMLElement, _props: TanStackDevtoolsPluginProps) => <></>,
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
return [Plugin, NoOpPlugin] as const
|