Skip to content

Commit b156e6e

Browse files
authored
Merge pull request #3 from TanStack/feat/make-react-api-better
feat: make the plugin API better for react/solid
2 parents 9181ae6 + e743e37 commit b156e6e

File tree

8 files changed

+127
-54
lines changed

8 files changed

+127
-54
lines changed

examples/react/basic/src/setup.tsx

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {
1010
} from '@tanstack/react-router'
1111
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
1212
import { Devtools } from '@tanstack/react-devtools'
13-
import { createRoot } from 'react-dom/client'
1413

1514
const rootRoute = createRootRoute({
1615
component: () => (
@@ -41,13 +40,13 @@ const indexRoute = createRoute({
4140
)
4241
},
4342
})
44-
43+
function About() {
44+
return <div className="p-2">Hello from About!</div>
45+
}
4546
const aboutRoute = createRoute({
4647
getParentRoute: () => rootRoute,
4748
path: '/about',
48-
component: function About() {
49-
return <div className="p-2">Hello from About!</div>
50-
},
49+
component: About,
5150
})
5251

5352
const routeTree = rootRoute.addChildren([indexRoute, aboutRoute])
@@ -62,22 +61,16 @@ export default function DevtoolsExample() {
6261
<Devtools
6362
plugins={[
6463
{
65-
id: 'query',
6664
name: 'Tanstack Query',
67-
render: (el) =>
68-
createRoot(el).render(
69-
<QueryClientProvider client={queryClient}>
70-
<ReactQueryDevtoolsPanel />
71-
</QueryClientProvider>,
72-
),
65+
render: (
66+
<QueryClientProvider client={queryClient}>
67+
<ReactQueryDevtoolsPanel />
68+
</QueryClientProvider>
69+
),
7370
},
7471
{
75-
id: 'router',
7672
name: 'Tanstack Router',
77-
render: (el) =>
78-
createRoot(el).render(
79-
<TanStackRouterDevtoolsPanel router={router} />,
80-
),
73+
render: <TanStackRouterDevtoolsPanel router={router} />,
8174
},
8275
]}
8376
/>

examples/solid/basic/src/setup.tsx

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import {
99
} from '@tanstack/solid-router'
1010
import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools'
1111
import { Devtools } from '@tanstack/solid-devtools'
12-
import { Portal } from 'solid-js/web'
13-
1412
const rootRoute = createRootRoute({
1513
component: () => (
1614
<>
@@ -33,13 +31,13 @@ const indexRoute = createRoute({
3331
)
3432
},
3533
})
36-
34+
function About() {
35+
return <div class="p-2">Hello from About!</div>
36+
}
3737
const aboutRoute = createRoute({
3838
getParentRoute: () => rootRoute,
3939
path: '/about',
40-
component: function About() {
41-
return <div class="p-2">Hello from About!</div>
42-
},
40+
component: About,
4341
})
4442

4543
const routeTree = rootRoute.addChildren([indexRoute, aboutRoute])
@@ -54,25 +52,16 @@ export default function DevtoolsExample() {
5452
<Devtools
5553
plugins={[
5654
{
57-
id: 'query',
5855
name: 'Tanstack Query',
59-
render: (el) => (
60-
<Portal mount={el}>
61-
{' '}
62-
<QueryClientProvider client={queryClient}>
63-
<SolidQueryDevtools />
64-
</QueryClientProvider>{' '}
65-
</Portal>
56+
render: (
57+
<QueryClientProvider client={queryClient}>
58+
<SolidQueryDevtools />
59+
</QueryClientProvider>
6660
),
6761
},
6862
{
69-
id: 'router',
7063
name: 'Tanstack Router',
71-
render: (el) => (
72-
<Portal mount={el}>
73-
<TanStackRouterDevtoolsPanel router={router} />
74-
</Portal>
75-
),
64+
render: <TanStackRouterDevtoolsPanel router={router} />,
7665
},
7766
]}
7867
/>

packages/devtools/src/context/devtools-context.tsx

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,9 @@ import type { JSX } from 'solid-js/jsx-runtime'
1414

1515
export interface DevtoolsPlugin {
1616
name: string | ((el: HTMLHeadingElement) => void)
17-
id: string
17+
id?: string
1818
render: (el: HTMLDivElement) => void
1919
}
20-
2120
export const DevtoolsContext = createContext<{
2221
store: DevtoolsStore
2322
setStore: Setter<DevtoolsStore>
@@ -37,6 +36,19 @@ const getSettings = () => {
3736
}
3837
}
3938

39+
const generatePluginId = (plugin: DevtoolsPlugin, index: number) => {
40+
// if set by user, return the plugin id
41+
if (plugin.id) {
42+
return plugin.id
43+
}
44+
if (typeof plugin.name === 'string') {
45+
// if name is a string, use it to generate an id
46+
return plugin.name.toLowerCase().replace(' ', '-')
47+
}
48+
// Name is JSX? return the index as a string
49+
return index.toString()
50+
}
51+
4052
const getExistingStateFromStorage = (
4153
config?: DevtoolsSettings,
4254
plugins?: Array<DevtoolsPlugin>,
@@ -46,7 +58,14 @@ const getExistingStateFromStorage = (
4658

4759
const state: DevtoolsStore = {
4860
...initialState,
49-
plugins: plugins || [],
61+
plugins:
62+
plugins?.map((plugin, i) => {
63+
const id = generatePluginId(plugin, i)
64+
return {
65+
...plugin,
66+
id,
67+
}
68+
}) || [],
5069
state: {
5170
...initialState.state,
5271
...(existingState ? JSON.parse(existingState) : {}),

packages/devtools/src/context/devtools-store.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export type DevtoolsStore = {
5454
state: {
5555
activeTab: TabName
5656
height: number
57-
activePlugin?: DevtoolsPlugin | undefined
57+
activePlugin?: string | undefined
5858
persistOpen: boolean
5959
}
6060
plugins?: Array<DevtoolsPlugin>

packages/devtools/src/context/use-devtools-context.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { createMemo, useContext } from 'solid-js'
22
import { DevtoolsContext } from './devtools-context.jsx'
3-
import type { DevtoolsPlugin } from './devtools-context.jsx'
43
/* import type { DevtoolsPlugin } from './devtools-context' */
54
import type { DevtoolsStore } from './devtools-store.js'
65

@@ -24,12 +23,12 @@ export const usePlugins = () => {
2423
const plugins = createMemo(() => store.plugins)
2524
const activePlugin = createMemo(() => store.state.activePlugin)
2625

27-
const setActivePlugin = (plugin: DevtoolsPlugin) => {
26+
const setActivePlugin = (pluginId: string) => {
2827
setStore((prev) => ({
2928
...prev,
3029
state: {
3130
...prev.state,
32-
activePlugin: plugin,
31+
activePlugin: pluginId,
3332
},
3433
}))
3534
}

packages/devtools/src/tabs/plugins-tab.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ import { useStyles } from '../styles/use-styles'
66
export const PluginsTab = () => {
77
const { plugins, activePlugin, setActivePlugin } = usePlugins()
88
let activePluginRef: HTMLDivElement | undefined
9+
910
createEffect(() => {
1011
const currentActivePlugin = plugins()?.find(
11-
(plugin) => plugin.id === activePlugin()?.id,
12+
(plugin) => plugin.id === activePlugin(),
1213
)
1314
if (activePluginRef && currentActivePlugin) {
1415
currentActivePlugin.render(activePluginRef)
@@ -30,9 +31,9 @@ export const PluginsTab = () => {
3031
})
3132
return (
3233
<div
33-
onClick={() => setActivePlugin(plugin)}
34+
onClick={() => setActivePlugin(plugin.id!)}
3435
class={clsx(styles().pluginName, {
35-
active: activePlugin()?.id === plugin.id,
36+
active: activePlugin() === plugin.id,
3637
})}
3738
>
3839
<h3 ref={pluginHeading} />

packages/react-devtools/src/devtools.tsx

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,48 @@
11
import React, { useEffect, useRef, useState } from 'react'
22
import { TanStackRouterDevtoolsCore } from '@tanstack/devtools'
3-
import type { DevtoolsOptions } from '@tanstack/devtools'
3+
import { createRoot } from 'react-dom/client'
4+
import type { JSX } from 'react'
5+
import type { DevtoolsOptions, DevtoolsPlugin } from '@tanstack/devtools'
46

5-
export const Devtools = (opts: DevtoolsOptions) => {
7+
type Render = JSX.Element | (() => JSX.Element)
8+
type ReactPlugin = Omit<DevtoolsPlugin, 'render' | 'name'> & {
9+
render: Render
10+
name: string | Render
11+
}
12+
interface DevtoolsProps {
13+
plugins?: Array<ReactPlugin>
14+
options?: DevtoolsOptions['options']
15+
}
16+
17+
const convertRender = (
18+
el: HTMLDivElement | HTMLHeadingElement,
19+
Component: Render,
20+
) => {
21+
const domNode = document.createElement('div')
22+
const root = createRoot(domNode)
23+
root.render(typeof Component === 'function' ? <Component /> : Component)
24+
el.appendChild(domNode)
25+
}
26+
27+
export const Devtools = ({ plugins, options }: DevtoolsProps) => {
628
const devToolRef = useRef<HTMLDivElement>(null)
7-
const [devtools] = useState(() => new TanStackRouterDevtoolsCore(opts))
29+
const [devtools] = useState(
30+
() =>
31+
new TanStackRouterDevtoolsCore({
32+
options,
33+
plugins: plugins?.map((plugin) => {
34+
return {
35+
...plugin,
36+
name:
37+
typeof plugin.name === 'string'
38+
? plugin.name
39+
: // The check above confirms that `plugin.name` is of Render type
40+
(el) => convertRender(el, plugin.name as Render),
41+
render: (el: HTMLDivElement) => convertRender(el, plugin.render),
42+
}
43+
}),
44+
}),
45+
)
846
useEffect(() => {
947
if (devToolRef.current) {
1048
devtools.mount(devToolRef.current)

packages/solid-devtools/src/devtools.tsx

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,46 @@
11
import { TanStackRouterDevtoolsCore } from '@tanstack/devtools'
22
import { createEffect, createSignal, onCleanup, onMount } from 'solid-js'
3-
import type { DevtoolsOptions } from '@tanstack/devtools'
3+
import { Portal } from 'solid-js/web'
4+
import type { JSX } from 'solid-js'
5+
import type { DevtoolsOptions, DevtoolsPlugin } from '@tanstack/devtools'
46

5-
export const Devtools = (opts: DevtoolsOptions) => {
6-
const [devtools] = createSignal(new TanStackRouterDevtoolsCore(opts))
7+
type Render = JSX.Element | (() => JSX.Element)
8+
const convertRender = (
9+
el: HTMLDivElement | HTMLHeadingElement,
10+
Component: Render,
11+
) => (
12+
<Portal mount={el}>
13+
{typeof Component === 'function' ? <Component /> : Component}
14+
</Portal>
15+
)
16+
17+
type SolidPlugin = Omit<DevtoolsPlugin, 'render' | 'name'> & {
18+
render: Render
19+
name: string | Render
20+
}
21+
interface DevtoolsProps {
22+
plugins?: Array<SolidPlugin>
23+
options?: DevtoolsOptions['options']
24+
}
25+
26+
export const Devtools = ({ options, plugins }: DevtoolsProps) => {
27+
const [devtools] = createSignal(
28+
new TanStackRouterDevtoolsCore({
29+
options,
30+
plugins: plugins?.map((plugin) => ({
31+
...plugin,
32+
name:
33+
typeof plugin.name === 'string'
34+
? plugin.name
35+
: // The check above confirms that `plugin.name` is of Render type
36+
(el) => convertRender(el, plugin.name as Render),
37+
render: (el: HTMLDivElement) => convertRender(el, plugin.render),
38+
})),
39+
}),
40+
)
741
let devToolRef: HTMLDivElement | undefined
842
createEffect(() => {
9-
devtools().setOptions(opts)
43+
devtools().setOptions({ options })
1044
})
1145
onMount(() => {
1246
if (devToolRef) {

0 commit comments

Comments
 (0)