@tanstack/react-devtools 0.0.0 → 0.1.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.
package/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # @tanstack/react-devtools
2
+
3
+ This package is still under active development and might have breaking changes in the future. Please use it with caution.
4
+
5
+ ## Usage
6
+
7
+ ```tsx
8
+ import { TanstackDevtools } from '@tanstack/react-devtools'
9
+ import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools'
10
+ import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'
11
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
12
+ const queryClient = new QueryClient()
13
+ function App() {
14
+ return (
15
+ <QueryClientProvider client={queryClient}>
16
+ <h1>My App</h1>
17
+ <TanstackDevtools
18
+ plugins={[
19
+ {
20
+ name: 'Tanstack Query',
21
+ render: <ReactQueryDevtoolsPanel />,
22
+ },
23
+ {
24
+ name: 'Tanstack Router',
25
+ render: <TanStackRouterDevtoolsPanel router={router} />,
26
+ },
27
+ ]}
28
+ />
29
+ </QueryClientProvider>
30
+ )
31
+ }
32
+ ```
33
+
34
+ ## Creating plugins
35
+
36
+ In order to create a plugin for TanStack Devtools, you can use the `plugins` prop of the `TanstackDevtools` component. Here's an example of how to create a simple plugin:
37
+
38
+ ```tsx
39
+ import { TanstackDevtools } from '@tanstack/react-devtools'
40
+
41
+ function App() {
42
+ return (
43
+ <div>
44
+ <h1>My App</h1>
45
+ <TanstackDevtools
46
+ plugins={[
47
+ {
48
+ id: 'your-plugin-id',
49
+ name: 'Your Plugin',
50
+ render: <CustomPluginComponent />,
51
+ },
52
+ ]}
53
+ />
54
+ </div>
55
+ )
56
+ }
57
+ ```
@@ -3,9 +3,51 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const jsxRuntime = require("react/jsx-runtime");
4
4
  const react = require("react");
5
5
  const devtools = require("@tanstack/devtools");
6
- const Devtools = (opts) => {
6
+ const reactDom = require("react-dom");
7
+ const convertRender = (Component, setComponent) => {
8
+ setComponent(typeof Component === "function" ? Component() : Component);
9
+ };
10
+ const TanstackDevtools = ({
11
+ plugins,
12
+ config
13
+ }) => {
7
14
  const devToolRef = react.useRef(null);
8
- const [devtools$1] = react.useState(() => new devtools.TanStackRouterDevtoolsCore(opts));
15
+ const [pluginContainer, setPluginContainer] = react.useState(
16
+ null
17
+ );
18
+ const [titleContainer, setTitleContainer] = react.useState(null);
19
+ const [PluginComponent, setPluginComponent] = react.useState(
20
+ null
21
+ );
22
+ const [TitleComponent, setTitleComponent] = react.useState(null);
23
+ const [devtools$1] = react.useState(
24
+ () => new devtools.TanStackDevtoolsCore({
25
+ config,
26
+ plugins: plugins?.map((plugin) => {
27
+ return {
28
+ ...plugin,
29
+ name: typeof plugin.name === "string" ? plugin.name : (
30
+ // The check above confirms that `plugin.name` is of Render type
31
+ () => {
32
+ setTitleContainer(
33
+ document.getElementById(devtools.PLUGIN_TITLE_CONTAINER_ID) || null
34
+ );
35
+ convertRender(
36
+ plugin.name,
37
+ setTitleComponent
38
+ );
39
+ }
40
+ ),
41
+ render: () => {
42
+ setPluginContainer(
43
+ document.getElementById(devtools.PLUGIN_CONTAINER_ID) || null
44
+ );
45
+ convertRender(plugin.render, setPluginComponent);
46
+ }
47
+ };
48
+ })
49
+ })
50
+ );
9
51
  react.useEffect(() => {
10
52
  if (devToolRef.current) {
11
53
  devtools$1.mount(devToolRef.current);
@@ -14,7 +56,11 @@ const Devtools = (opts) => {
14
56
  devtools$1.unmount();
15
57
  };
16
58
  }, [devtools$1]);
17
- return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: devToolRef });
59
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
60
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref: devToolRef }),
61
+ pluginContainer && PluginComponent ? reactDom.createPortal(/* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: PluginComponent }), pluginContainer) : null,
62
+ titleContainer && TitleComponent ? reactDom.createPortal(/* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: TitleComponent }), titleContainer) : null
63
+ ] });
18
64
  };
19
- exports.Devtools = Devtools;
65
+ exports.TanstackDevtools = TanstackDevtools;
20
66
  //# sourceMappingURL=devtools.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"devtools.cjs","sources":["../../src/devtools.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react'\nimport { TanStackRouterDevtoolsCore } from '@tanstack/devtools'\nimport type { DevtoolsOptions } from '@tanstack/devtools'\n\nexport const Devtools = (opts: DevtoolsOptions) => {\n const devToolRef = useRef<HTMLDivElement>(null)\n const [devtools] = useState(() => new TanStackRouterDevtoolsCore(opts))\n useEffect(() => {\n if (devToolRef.current) {\n devtools.mount(devToolRef.current)\n }\n\n return () => {\n devtools.unmount()\n }\n }, [devtools])\n\n return <div ref={devToolRef} />\n}\n"],"names":["useRef","devtools","useState","TanStackRouterDevtoolsCore","useEffect","jsx"],"mappings":";;;;;AAIa,MAAA,WAAW,CAAC,SAA0B;AAC3C,QAAA,aAAaA,aAAuB,IAAI;AACxC,QAAA,CAACC,UAAQ,IAAIC,MAAAA,SAAS,MAAM,IAAIC,SAAAA,2BAA2B,IAAI,CAAC;AACtEC,QAAAA,UAAU,MAAM;AACd,QAAI,WAAW,SAAS;AACbH,iBAAA,MAAM,WAAW,OAAO;AAAA,IAAA;AAGnC,WAAO,MAAM;AACXA,iBAAS,QAAQ;AAAA,IACnB;AAAA,EAAA,GACC,CAACA,UAAQ,CAAC;AAEN,SAAAI,2BAAA,IAAC,OAAI,EAAA,KAAK,WAAY,CAAA;AAC/B;;"}
1
+ {"version":3,"file":"devtools.cjs","sources":["../../src/devtools.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react'\nimport {\n PLUGIN_CONTAINER_ID,\n PLUGIN_TITLE_CONTAINER_ID,\n TanStackDevtoolsCore,\n} from '@tanstack/devtools'\nimport { createPortal } from 'react-dom'\nimport type { JSX } from 'react'\nimport type {\n TanStackDevtoolsConfig,\n TanStackDevtoolsPlugin,\n} from '@tanstack/devtools'\n\ntype PluginRender = JSX.Element | (() => JSX.Element)\n\nexport type TanStackDevtoolsReactPlugin = Omit<\n TanStackDevtoolsPlugin,\n 'render' | 'name'\n> & {\n /**\n * The render function can be a React element or a function that returns a React element.\n * If it's a function, it will be called to render the plugin, otherwise it will be rendered directly.\n *\n * Example:\n * ```jsx\n * {\n * render: () => <CustomPluginComponent />,\n * }\n * ```\n * or\n * ```jsx\n * {\n * render: <CustomPluginComponent />,\n * }\n * ```\n */\n render: PluginRender\n /**\n * Name to be displayed in the devtools UI.\n * If a string, it will be used as the plugin name.\n * If a function, it will be called with the mount element.\n *\n * Example:\n * ```jsx\n * {\n * name: \"Your Plugin\",\n * render: () => <CustomPluginComponent />,\n * }\n * ```\n * or\n * ```jsx\n * {\n * name: <h1>Your Plugin title</h1>,\n * render: () => <CustomPluginComponent />,\n * }\n * ```\n */\n name: string | PluginRender\n}\n\nexport interface TanStackDevtoolsReactInit {\n /**\n * Array of plugins to be used in the devtools.\n * Each plugin should have a `render` function that returns a React element or a function\n *\n * Example:\n * ```jsx\n * <TanstackDevtools\n * plugins={[\n * {\n * id: \"your-plugin-id\",\n * name: \"Your Plugin\",\n * render: <CustomPluginComponent />,\n * }\n * ]}\n * />\n * ```\n */\n plugins?: Array<TanStackDevtoolsReactPlugin>\n /**\n * Configuration for the devtools shell. These configuration options are used to set the\n * initial state of the devtools when it is started for the first time. Afterwards,\n * the settings are persisted in local storage and changed through the settings panel.\n */\n config?: TanStackDevtoolsConfig\n}\n\nconst convertRender = (\n Component: PluginRender,\n setComponent: React.Dispatch<React.SetStateAction<JSX.Element | null>>,\n) => {\n setComponent(typeof Component === 'function' ? Component() : Component)\n}\n\nexport const TanstackDevtools = ({\n plugins,\n config,\n}: TanStackDevtoolsReactInit) => {\n const devToolRef = useRef<HTMLDivElement>(null)\n const [pluginContainer, setPluginContainer] = useState<HTMLElement | null>(\n null,\n )\n const [titleContainer, setTitleContainer] = useState<HTMLElement | null>(null)\n const [PluginComponent, setPluginComponent] = useState<JSX.Element | null>(\n null,\n )\n const [TitleComponent, setTitleComponent] = useState<JSX.Element | null>(null)\n const [devtools] = useState(\n () =>\n new TanStackDevtoolsCore({\n config,\n plugins: plugins?.map((plugin) => {\n return {\n ...plugin,\n name:\n typeof plugin.name === 'string'\n ? plugin.name\n : // The check above confirms that `plugin.name` is of Render type\n () => {\n setTitleContainer(\n document.getElementById(PLUGIN_TITLE_CONTAINER_ID) ||\n null,\n )\n convertRender(\n plugin.name as PluginRender,\n setTitleComponent,\n )\n },\n render: () => {\n setPluginContainer(\n document.getElementById(PLUGIN_CONTAINER_ID) || null,\n )\n convertRender(plugin.render, setPluginComponent)\n },\n }\n }),\n }),\n )\n useEffect(() => {\n if (devToolRef.current) {\n devtools.mount(devToolRef.current)\n }\n\n return () => {\n devtools.unmount()\n }\n }, [devtools])\n\n return (\n <>\n <div ref={devToolRef} />\n {pluginContainer && PluginComponent\n ? createPortal(<>{PluginComponent}</>, pluginContainer)\n : null}\n {titleContainer && TitleComponent\n ? createPortal(<>{TitleComponent}</>, titleContainer)\n : null}\n </>\n )\n}\n"],"names":["useRef","useState","devtools","TanStackDevtoolsCore","PLUGIN_TITLE_CONTAINER_ID","PLUGIN_CONTAINER_ID","useEffect","jsxs","Fragment","jsx","createPortal"],"mappings":";;;;;;AAuFA,MAAM,gBAAgB,CACpB,WACA,iBACG;AACH,eAAa,OAAO,cAAc,aAAa,UAAA,IAAc,SAAS;AACxE;AAEO,MAAM,mBAAmB,CAAC;AAAA,EAC/B;AAAA,EACA;AACF,MAAiC;AAC/B,QAAM,aAAaA,MAAAA,OAAuB,IAAI;AAC9C,QAAM,CAAC,iBAAiB,kBAAkB,IAAIC,MAAAA;AAAAA,IAC5C;AAAA,EAAA;AAEF,QAAM,CAAC,gBAAgB,iBAAiB,IAAIA,MAAAA,SAA6B,IAAI;AAC7E,QAAM,CAAC,iBAAiB,kBAAkB,IAAIA,MAAAA;AAAAA,IAC5C;AAAA,EAAA;AAEF,QAAM,CAAC,gBAAgB,iBAAiB,IAAIA,MAAAA,SAA6B,IAAI;AAC7E,QAAM,CAACC,UAAQ,IAAID,MAAAA;AAAAA,IACjB,MACE,IAAIE,SAAAA,qBAAqB;AAAA,MACvB;AAAA,MACA,SAAS,SAAS,IAAI,CAAC,WAAW;AAChC,eAAO;AAAA,UACL,GAAG;AAAA,UACH,MACE,OAAO,OAAO,SAAS,WACnB,OAAO;AAAA;AAAA,YAEP,MAAM;AACJ;AAAA,gBACE,SAAS,eAAeC,SAAAA,yBAAyB,KAC/C;AAAA,cAAA;AAEJ;AAAA,gBACE,OAAO;AAAA,gBACP;AAAA,cAAA;AAAA,YAEJ;AAAA;AAAA,UACN,QAAQ,MAAM;AACZ;AAAA,cACE,SAAS,eAAeC,SAAAA,mBAAmB,KAAK;AAAA,YAAA;AAElD,0BAAc,OAAO,QAAQ,kBAAkB;AAAA,UACjD;AAAA,QAAA;AAAA,MAEJ,CAAC;AAAA,IAAA,CACF;AAAA,EAAA;AAELC,QAAAA,UAAU,MAAM;AACd,QAAI,WAAW,SAAS;AACtBJ,iBAAS,MAAM,WAAW,OAAO;AAAA,IACnC;AAEA,WAAO,MAAM;AACXA,iBAAS,QAAA;AAAA,IACX;AAAA,EACF,GAAG,CAACA,UAAQ,CAAC;AAEb,SACEK,2BAAAA,KAAAC,qBAAA,EACE,UAAA;AAAA,IAAAC,2BAAAA,IAAC,OAAA,EAAI,KAAK,WAAA,CAAY;AAAA,IACrB,mBAAmB,kBAChBC,4EAAgB,UAAA,gBAAA,CAAgB,GAAK,eAAe,IACpD;AAAA,IACH,kBAAkB,iBACfA,SAAAA,mEAAgB,UAAA,eAAA,CAAe,GAAK,cAAc,IAClD;AAAA,EAAA,GACN;AAEJ;;"}
@@ -1,3 +1,72 @@
1
- import { default as React } from 'react';
2
- import { DevtoolsOptions } from '@tanstack/devtools';
3
- export declare const Devtools: (opts: DevtoolsOptions) => React.JSX.Element;
1
+ import { JSX } from 'react';
2
+ import { TanStackDevtoolsConfig, TanStackDevtoolsPlugin } from '@tanstack/devtools';
3
+ type PluginRender = JSX.Element | (() => JSX.Element);
4
+ export type TanStackDevtoolsReactPlugin = Omit<TanStackDevtoolsPlugin, 'render' | 'name'> & {
5
+ /**
6
+ * The render function can be a React element or a function that returns a React element.
7
+ * If it's a function, it will be called to render the plugin, otherwise it will be rendered directly.
8
+ *
9
+ * Example:
10
+ * ```jsx
11
+ * {
12
+ * render: () => <CustomPluginComponent />,
13
+ * }
14
+ * ```
15
+ * or
16
+ * ```jsx
17
+ * {
18
+ * render: <CustomPluginComponent />,
19
+ * }
20
+ * ```
21
+ */
22
+ render: PluginRender;
23
+ /**
24
+ * Name to be displayed in the devtools UI.
25
+ * If a string, it will be used as the plugin name.
26
+ * If a function, it will be called with the mount element.
27
+ *
28
+ * Example:
29
+ * ```jsx
30
+ * {
31
+ * name: "Your Plugin",
32
+ * render: () => <CustomPluginComponent />,
33
+ * }
34
+ * ```
35
+ * or
36
+ * ```jsx
37
+ * {
38
+ * name: <h1>Your Plugin title</h1>,
39
+ * render: () => <CustomPluginComponent />,
40
+ * }
41
+ * ```
42
+ */
43
+ name: string | PluginRender;
44
+ };
45
+ export interface TanStackDevtoolsReactInit {
46
+ /**
47
+ * Array of plugins to be used in the devtools.
48
+ * Each plugin should have a `render` function that returns a React element or a function
49
+ *
50
+ * Example:
51
+ * ```jsx
52
+ * <TanstackDevtools
53
+ * plugins={[
54
+ * {
55
+ * id: "your-plugin-id",
56
+ * name: "Your Plugin",
57
+ * render: <CustomPluginComponent />,
58
+ * }
59
+ * ]}
60
+ * />
61
+ * ```
62
+ */
63
+ plugins?: Array<TanStackDevtoolsReactPlugin>;
64
+ /**
65
+ * Configuration for the devtools shell. These configuration options are used to set the
66
+ * initial state of the devtools when it is started for the first time. Afterwards,
67
+ * the settings are persisted in local storage and changed through the settings panel.
68
+ */
69
+ config?: TanStackDevtoolsConfig;
70
+ }
71
+ export declare const TanstackDevtools: ({ plugins, config, }: TanStackDevtoolsReactInit) => JSX.Element;
72
+ export {};
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const devtools$1 = require("@tanstack/devtools");
4
4
  const devtools = require("./devtools.cjs");
5
- exports.Devtools = devtools.Devtools;
5
+ exports.TanstackDevtools = devtools.TanstackDevtools;
6
6
  Object.keys(devtools$1).forEach((k) => {
7
7
  if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
8
8
  enumerable: true,
@@ -2,4 +2,5 @@ export * from '@tanstack/devtools';
2
2
  /**
3
3
  * Export every hook individually - DON'T export from barrel files
4
4
  */
5
- export { Devtools } from './devtools.cjs';
5
+ export * from './devtools.cjs';
6
+ export type { TanStackDevtoolsReactPlugin } from './devtools.cjs';
@@ -1,3 +1,72 @@
1
- import { default as React } from 'react';
2
- import { DevtoolsOptions } from '@tanstack/devtools';
3
- export declare const Devtools: (opts: DevtoolsOptions) => React.JSX.Element;
1
+ import { JSX } from 'react';
2
+ import { TanStackDevtoolsConfig, TanStackDevtoolsPlugin } from '@tanstack/devtools';
3
+ type PluginRender = JSX.Element | (() => JSX.Element);
4
+ export type TanStackDevtoolsReactPlugin = Omit<TanStackDevtoolsPlugin, 'render' | 'name'> & {
5
+ /**
6
+ * The render function can be a React element or a function that returns a React element.
7
+ * If it's a function, it will be called to render the plugin, otherwise it will be rendered directly.
8
+ *
9
+ * Example:
10
+ * ```jsx
11
+ * {
12
+ * render: () => <CustomPluginComponent />,
13
+ * }
14
+ * ```
15
+ * or
16
+ * ```jsx
17
+ * {
18
+ * render: <CustomPluginComponent />,
19
+ * }
20
+ * ```
21
+ */
22
+ render: PluginRender;
23
+ /**
24
+ * Name to be displayed in the devtools UI.
25
+ * If a string, it will be used as the plugin name.
26
+ * If a function, it will be called with the mount element.
27
+ *
28
+ * Example:
29
+ * ```jsx
30
+ * {
31
+ * name: "Your Plugin",
32
+ * render: () => <CustomPluginComponent />,
33
+ * }
34
+ * ```
35
+ * or
36
+ * ```jsx
37
+ * {
38
+ * name: <h1>Your Plugin title</h1>,
39
+ * render: () => <CustomPluginComponent />,
40
+ * }
41
+ * ```
42
+ */
43
+ name: string | PluginRender;
44
+ };
45
+ export interface TanStackDevtoolsReactInit {
46
+ /**
47
+ * Array of plugins to be used in the devtools.
48
+ * Each plugin should have a `render` function that returns a React element or a function
49
+ *
50
+ * Example:
51
+ * ```jsx
52
+ * <TanstackDevtools
53
+ * plugins={[
54
+ * {
55
+ * id: "your-plugin-id",
56
+ * name: "Your Plugin",
57
+ * render: <CustomPluginComponent />,
58
+ * }
59
+ * ]}
60
+ * />
61
+ * ```
62
+ */
63
+ plugins?: Array<TanStackDevtoolsReactPlugin>;
64
+ /**
65
+ * Configuration for the devtools shell. These configuration options are used to set the
66
+ * initial state of the devtools when it is started for the first time. Afterwards,
67
+ * the settings are persisted in local storage and changed through the settings panel.
68
+ */
69
+ config?: TanStackDevtoolsConfig;
70
+ }
71
+ export declare const TanstackDevtools: ({ plugins, config, }: TanStackDevtoolsReactInit) => JSX.Element;
72
+ export {};
@@ -1,9 +1,51 @@
1
- import { jsx } from "react/jsx-runtime";
1
+ import { jsxs, Fragment, jsx } from "react/jsx-runtime";
2
2
  import { useRef, useState, useEffect } from "react";
3
- import { TanStackRouterDevtoolsCore } from "@tanstack/devtools";
4
- const Devtools = (opts) => {
3
+ import { TanStackDevtoolsCore, PLUGIN_CONTAINER_ID, PLUGIN_TITLE_CONTAINER_ID } from "@tanstack/devtools";
4
+ import { createPortal } from "react-dom";
5
+ const convertRender = (Component, setComponent) => {
6
+ setComponent(typeof Component === "function" ? Component() : Component);
7
+ };
8
+ const TanstackDevtools = ({
9
+ plugins,
10
+ config
11
+ }) => {
5
12
  const devToolRef = useRef(null);
6
- const [devtools] = useState(() => new TanStackRouterDevtoolsCore(opts));
13
+ const [pluginContainer, setPluginContainer] = useState(
14
+ null
15
+ );
16
+ const [titleContainer, setTitleContainer] = useState(null);
17
+ const [PluginComponent, setPluginComponent] = useState(
18
+ null
19
+ );
20
+ const [TitleComponent, setTitleComponent] = useState(null);
21
+ const [devtools] = useState(
22
+ () => new TanStackDevtoolsCore({
23
+ config,
24
+ plugins: plugins?.map((plugin) => {
25
+ return {
26
+ ...plugin,
27
+ name: typeof plugin.name === "string" ? plugin.name : (
28
+ // The check above confirms that `plugin.name` is of Render type
29
+ () => {
30
+ setTitleContainer(
31
+ document.getElementById(PLUGIN_TITLE_CONTAINER_ID) || null
32
+ );
33
+ convertRender(
34
+ plugin.name,
35
+ setTitleComponent
36
+ );
37
+ }
38
+ ),
39
+ render: () => {
40
+ setPluginContainer(
41
+ document.getElementById(PLUGIN_CONTAINER_ID) || null
42
+ );
43
+ convertRender(plugin.render, setPluginComponent);
44
+ }
45
+ };
46
+ })
47
+ })
48
+ );
7
49
  useEffect(() => {
8
50
  if (devToolRef.current) {
9
51
  devtools.mount(devToolRef.current);
@@ -12,9 +54,13 @@ const Devtools = (opts) => {
12
54
  devtools.unmount();
13
55
  };
14
56
  }, [devtools]);
15
- return /* @__PURE__ */ jsx("div", { ref: devToolRef });
57
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
58
+ /* @__PURE__ */ jsx("div", { ref: devToolRef }),
59
+ pluginContainer && PluginComponent ? createPortal(/* @__PURE__ */ jsx(Fragment, { children: PluginComponent }), pluginContainer) : null,
60
+ titleContainer && TitleComponent ? createPortal(/* @__PURE__ */ jsx(Fragment, { children: TitleComponent }), titleContainer) : null
61
+ ] });
16
62
  };
17
63
  export {
18
- Devtools
64
+ TanstackDevtools
19
65
  };
20
66
  //# sourceMappingURL=devtools.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"devtools.js","sources":["../../src/devtools.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react'\nimport { TanStackRouterDevtoolsCore } from '@tanstack/devtools'\nimport type { DevtoolsOptions } from '@tanstack/devtools'\n\nexport const Devtools = (opts: DevtoolsOptions) => {\n const devToolRef = useRef<HTMLDivElement>(null)\n const [devtools] = useState(() => new TanStackRouterDevtoolsCore(opts))\n useEffect(() => {\n if (devToolRef.current) {\n devtools.mount(devToolRef.current)\n }\n\n return () => {\n devtools.unmount()\n }\n }, [devtools])\n\n return <div ref={devToolRef} />\n}\n"],"names":[],"mappings":";;;AAIa,MAAA,WAAW,CAAC,SAA0B;AAC3C,QAAA,aAAa,OAAuB,IAAI;AACxC,QAAA,CAAC,QAAQ,IAAI,SAAS,MAAM,IAAI,2BAA2B,IAAI,CAAC;AACtE,YAAU,MAAM;AACd,QAAI,WAAW,SAAS;AACb,eAAA,MAAM,WAAW,OAAO;AAAA,IAAA;AAGnC,WAAO,MAAM;AACX,eAAS,QAAQ;AAAA,IACnB;AAAA,EAAA,GACC,CAAC,QAAQ,CAAC;AAEN,SAAA,oBAAC,OAAI,EAAA,KAAK,WAAY,CAAA;AAC/B;"}
1
+ {"version":3,"file":"devtools.js","sources":["../../src/devtools.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react'\nimport {\n PLUGIN_CONTAINER_ID,\n PLUGIN_TITLE_CONTAINER_ID,\n TanStackDevtoolsCore,\n} from '@tanstack/devtools'\nimport { createPortal } from 'react-dom'\nimport type { JSX } from 'react'\nimport type {\n TanStackDevtoolsConfig,\n TanStackDevtoolsPlugin,\n} from '@tanstack/devtools'\n\ntype PluginRender = JSX.Element | (() => JSX.Element)\n\nexport type TanStackDevtoolsReactPlugin = Omit<\n TanStackDevtoolsPlugin,\n 'render' | 'name'\n> & {\n /**\n * The render function can be a React element or a function that returns a React element.\n * If it's a function, it will be called to render the plugin, otherwise it will be rendered directly.\n *\n * Example:\n * ```jsx\n * {\n * render: () => <CustomPluginComponent />,\n * }\n * ```\n * or\n * ```jsx\n * {\n * render: <CustomPluginComponent />,\n * }\n * ```\n */\n render: PluginRender\n /**\n * Name to be displayed in the devtools UI.\n * If a string, it will be used as the plugin name.\n * If a function, it will be called with the mount element.\n *\n * Example:\n * ```jsx\n * {\n * name: \"Your Plugin\",\n * render: () => <CustomPluginComponent />,\n * }\n * ```\n * or\n * ```jsx\n * {\n * name: <h1>Your Plugin title</h1>,\n * render: () => <CustomPluginComponent />,\n * }\n * ```\n */\n name: string | PluginRender\n}\n\nexport interface TanStackDevtoolsReactInit {\n /**\n * Array of plugins to be used in the devtools.\n * Each plugin should have a `render` function that returns a React element or a function\n *\n * Example:\n * ```jsx\n * <TanstackDevtools\n * plugins={[\n * {\n * id: \"your-plugin-id\",\n * name: \"Your Plugin\",\n * render: <CustomPluginComponent />,\n * }\n * ]}\n * />\n * ```\n */\n plugins?: Array<TanStackDevtoolsReactPlugin>\n /**\n * Configuration for the devtools shell. These configuration options are used to set the\n * initial state of the devtools when it is started for the first time. Afterwards,\n * the settings are persisted in local storage and changed through the settings panel.\n */\n config?: TanStackDevtoolsConfig\n}\n\nconst convertRender = (\n Component: PluginRender,\n setComponent: React.Dispatch<React.SetStateAction<JSX.Element | null>>,\n) => {\n setComponent(typeof Component === 'function' ? Component() : Component)\n}\n\nexport const TanstackDevtools = ({\n plugins,\n config,\n}: TanStackDevtoolsReactInit) => {\n const devToolRef = useRef<HTMLDivElement>(null)\n const [pluginContainer, setPluginContainer] = useState<HTMLElement | null>(\n null,\n )\n const [titleContainer, setTitleContainer] = useState<HTMLElement | null>(null)\n const [PluginComponent, setPluginComponent] = useState<JSX.Element | null>(\n null,\n )\n const [TitleComponent, setTitleComponent] = useState<JSX.Element | null>(null)\n const [devtools] = useState(\n () =>\n new TanStackDevtoolsCore({\n config,\n plugins: plugins?.map((plugin) => {\n return {\n ...plugin,\n name:\n typeof plugin.name === 'string'\n ? plugin.name\n : // The check above confirms that `plugin.name` is of Render type\n () => {\n setTitleContainer(\n document.getElementById(PLUGIN_TITLE_CONTAINER_ID) ||\n null,\n )\n convertRender(\n plugin.name as PluginRender,\n setTitleComponent,\n )\n },\n render: () => {\n setPluginContainer(\n document.getElementById(PLUGIN_CONTAINER_ID) || null,\n )\n convertRender(plugin.render, setPluginComponent)\n },\n }\n }),\n }),\n )\n useEffect(() => {\n if (devToolRef.current) {\n devtools.mount(devToolRef.current)\n }\n\n return () => {\n devtools.unmount()\n }\n }, [devtools])\n\n return (\n <>\n <div ref={devToolRef} />\n {pluginContainer && PluginComponent\n ? createPortal(<>{PluginComponent}</>, pluginContainer)\n : null}\n {titleContainer && TitleComponent\n ? createPortal(<>{TitleComponent}</>, titleContainer)\n : null}\n </>\n )\n}\n"],"names":[],"mappings":";;;;AAuFA,MAAM,gBAAgB,CACpB,WACA,iBACG;AACH,eAAa,OAAO,cAAc,aAAa,UAAA,IAAc,SAAS;AACxE;AAEO,MAAM,mBAAmB,CAAC;AAAA,EAC/B;AAAA,EACA;AACF,MAAiC;AAC/B,QAAM,aAAa,OAAuB,IAAI;AAC9C,QAAM,CAAC,iBAAiB,kBAAkB,IAAI;AAAA,IAC5C;AAAA,EAAA;AAEF,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAA6B,IAAI;AAC7E,QAAM,CAAC,iBAAiB,kBAAkB,IAAI;AAAA,IAC5C;AAAA,EAAA;AAEF,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAA6B,IAAI;AAC7E,QAAM,CAAC,QAAQ,IAAI;AAAA,IACjB,MACE,IAAI,qBAAqB;AAAA,MACvB;AAAA,MACA,SAAS,SAAS,IAAI,CAAC,WAAW;AAChC,eAAO;AAAA,UACL,GAAG;AAAA,UACH,MACE,OAAO,OAAO,SAAS,WACnB,OAAO;AAAA;AAAA,YAEP,MAAM;AACJ;AAAA,gBACE,SAAS,eAAe,yBAAyB,KAC/C;AAAA,cAAA;AAEJ;AAAA,gBACE,OAAO;AAAA,gBACP;AAAA,cAAA;AAAA,YAEJ;AAAA;AAAA,UACN,QAAQ,MAAM;AACZ;AAAA,cACE,SAAS,eAAe,mBAAmB,KAAK;AAAA,YAAA;AAElD,0BAAc,OAAO,QAAQ,kBAAkB;AAAA,UACjD;AAAA,QAAA;AAAA,MAEJ,CAAC;AAAA,IAAA,CACF;AAAA,EAAA;AAEL,YAAU,MAAM;AACd,QAAI,WAAW,SAAS;AACtB,eAAS,MAAM,WAAW,OAAO;AAAA,IACnC;AAEA,WAAO,MAAM;AACX,eAAS,QAAA;AAAA,IACX;AAAA,EACF,GAAG,CAAC,QAAQ,CAAC;AAEb,SACE,qBAAA,UAAA,EACE,UAAA;AAAA,IAAA,oBAAC,OAAA,EAAI,KAAK,WAAA,CAAY;AAAA,IACrB,mBAAmB,kBAChB,6CAAgB,UAAA,gBAAA,CAAgB,GAAK,eAAe,IACpD;AAAA,IACH,kBAAkB,iBACf,6CAAgB,UAAA,eAAA,CAAe,GAAK,cAAc,IAClD;AAAA,EAAA,GACN;AAEJ;"}
@@ -2,4 +2,5 @@ export * from '@tanstack/devtools';
2
2
  /**
3
3
  * Export every hook individually - DON'T export from barrel files
4
4
  */
5
- export { Devtools } from './devtools.js';
5
+ export * from './devtools.js';
6
+ export type { TanStackDevtoolsReactPlugin } from './devtools.js';
package/dist/esm/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export * from "@tanstack/devtools";
2
- import { Devtools } from "./devtools.js";
2
+ import { TanstackDevtools } from "./devtools.js";
3
3
  export {
4
- Devtools
4
+ TanstackDevtools
5
5
  };
6
6
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tanstack/react-devtools",
3
- "version": "0.0.0",
4
- "description": "Headless UI for creating advanced custom devtools, autocomplete, and dropdown components in React.",
3
+ "version": "0.1.1",
4
+ "description": "TanStack Devtools is a set of tools for building advanced devtools for your React application.",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -16,12 +16,7 @@
16
16
  },
17
17
  "keywords": [
18
18
  "react",
19
- "devtools",
20
- "autocomplete",
21
- "dropdown",
22
- "menu",
23
- "headless-ui",
24
- "nested"
19
+ "devtools"
25
20
  ],
26
21
  "type": "module",
27
22
  "types": "dist/esm/index.d.ts",
@@ -49,7 +44,7 @@
49
44
  "src"
50
45
  ],
51
46
  "dependencies": {
52
- "@tanstack/devtools": "0.0.0"
47
+ "@tanstack/devtools": "0.1.1"
53
48
  },
54
49
  "devDependencies": {
55
50
  "@eslint-react/eslint-plugin": "^1.48.5",
package/src/devtools.tsx CHANGED
@@ -1,10 +1,141 @@
1
1
  import React, { useEffect, useRef, useState } from 'react'
2
- import { TanStackRouterDevtoolsCore } from '@tanstack/devtools'
3
- import type { DevtoolsOptions } from '@tanstack/devtools'
2
+ import {
3
+ PLUGIN_CONTAINER_ID,
4
+ PLUGIN_TITLE_CONTAINER_ID,
5
+ TanStackDevtoolsCore,
6
+ } from '@tanstack/devtools'
7
+ import { createPortal } from 'react-dom'
8
+ import type { JSX } from 'react'
9
+ import type {
10
+ TanStackDevtoolsConfig,
11
+ TanStackDevtoolsPlugin,
12
+ } from '@tanstack/devtools'
4
13
 
5
- export const Devtools = (opts: DevtoolsOptions) => {
14
+ type PluginRender = JSX.Element | (() => JSX.Element)
15
+
16
+ export type TanStackDevtoolsReactPlugin = Omit<
17
+ TanStackDevtoolsPlugin,
18
+ 'render' | 'name'
19
+ > & {
20
+ /**
21
+ * The render function can be a React element or a function that returns a React element.
22
+ * If it's a function, it will be called to render the plugin, otherwise it will be rendered directly.
23
+ *
24
+ * Example:
25
+ * ```jsx
26
+ * {
27
+ * render: () => <CustomPluginComponent />,
28
+ * }
29
+ * ```
30
+ * or
31
+ * ```jsx
32
+ * {
33
+ * render: <CustomPluginComponent />,
34
+ * }
35
+ * ```
36
+ */
37
+ render: PluginRender
38
+ /**
39
+ * Name to be displayed in the devtools UI.
40
+ * If a string, it will be used as the plugin name.
41
+ * If a function, it will be called with the mount element.
42
+ *
43
+ * Example:
44
+ * ```jsx
45
+ * {
46
+ * name: "Your Plugin",
47
+ * render: () => <CustomPluginComponent />,
48
+ * }
49
+ * ```
50
+ * or
51
+ * ```jsx
52
+ * {
53
+ * name: <h1>Your Plugin title</h1>,
54
+ * render: () => <CustomPluginComponent />,
55
+ * }
56
+ * ```
57
+ */
58
+ name: string | PluginRender
59
+ }
60
+
61
+ export interface TanStackDevtoolsReactInit {
62
+ /**
63
+ * Array of plugins to be used in the devtools.
64
+ * Each plugin should have a `render` function that returns a React element or a function
65
+ *
66
+ * Example:
67
+ * ```jsx
68
+ * <TanstackDevtools
69
+ * plugins={[
70
+ * {
71
+ * id: "your-plugin-id",
72
+ * name: "Your Plugin",
73
+ * render: <CustomPluginComponent />,
74
+ * }
75
+ * ]}
76
+ * />
77
+ * ```
78
+ */
79
+ plugins?: Array<TanStackDevtoolsReactPlugin>
80
+ /**
81
+ * Configuration for the devtools shell. These configuration options are used to set the
82
+ * initial state of the devtools when it is started for the first time. Afterwards,
83
+ * the settings are persisted in local storage and changed through the settings panel.
84
+ */
85
+ config?: TanStackDevtoolsConfig
86
+ }
87
+
88
+ const convertRender = (
89
+ Component: PluginRender,
90
+ setComponent: React.Dispatch<React.SetStateAction<JSX.Element | null>>,
91
+ ) => {
92
+ setComponent(typeof Component === 'function' ? Component() : Component)
93
+ }
94
+
95
+ export const TanstackDevtools = ({
96
+ plugins,
97
+ config,
98
+ }: TanStackDevtoolsReactInit) => {
6
99
  const devToolRef = useRef<HTMLDivElement>(null)
7
- const [devtools] = useState(() => new TanStackRouterDevtoolsCore(opts))
100
+ const [pluginContainer, setPluginContainer] = useState<HTMLElement | null>(
101
+ null,
102
+ )
103
+ const [titleContainer, setTitleContainer] = useState<HTMLElement | null>(null)
104
+ const [PluginComponent, setPluginComponent] = useState<JSX.Element | null>(
105
+ null,
106
+ )
107
+ const [TitleComponent, setTitleComponent] = useState<JSX.Element | null>(null)
108
+ const [devtools] = useState(
109
+ () =>
110
+ new TanStackDevtoolsCore({
111
+ config,
112
+ plugins: plugins?.map((plugin) => {
113
+ return {
114
+ ...plugin,
115
+ name:
116
+ typeof plugin.name === 'string'
117
+ ? plugin.name
118
+ : // The check above confirms that `plugin.name` is of Render type
119
+ () => {
120
+ setTitleContainer(
121
+ document.getElementById(PLUGIN_TITLE_CONTAINER_ID) ||
122
+ null,
123
+ )
124
+ convertRender(
125
+ plugin.name as PluginRender,
126
+ setTitleComponent,
127
+ )
128
+ },
129
+ render: () => {
130
+ setPluginContainer(
131
+ document.getElementById(PLUGIN_CONTAINER_ID) || null,
132
+ )
133
+ convertRender(plugin.render, setPluginComponent)
134
+ },
135
+ }
136
+ }),
137
+ }),
138
+ )
8
139
  useEffect(() => {
9
140
  if (devToolRef.current) {
10
141
  devtools.mount(devToolRef.current)
@@ -15,5 +146,15 @@ export const Devtools = (opts: DevtoolsOptions) => {
15
146
  }
16
147
  }, [devtools])
17
148
 
18
- return <div ref={devToolRef} />
149
+ return (
150
+ <>
151
+ <div ref={devToolRef} />
152
+ {pluginContainer && PluginComponent
153
+ ? createPortal(<>{PluginComponent}</>, pluginContainer)
154
+ : null}
155
+ {titleContainer && TitleComponent
156
+ ? createPortal(<>{TitleComponent}</>, titleContainer)
157
+ : null}
158
+ </>
159
+ )
19
160
  }
package/src/index.ts CHANGED
@@ -4,4 +4,5 @@ export * from '@tanstack/devtools'
4
4
  * Export every hook individually - DON'T export from barrel files
5
5
  */
6
6
 
7
- export { Devtools } from './devtools'
7
+ export * from './devtools'
8
+ export type { TanStackDevtoolsReactPlugin } from './devtools'