@tanstack/devtools-utils 0.3.1 → 0.3.2

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.
@@ -0,0 +1,24 @@
1
+ import { render, createComponent, Portal, ssr, ssrStyleProperty, escape } from 'solid-js/web';
2
+ import { lazy } from 'solid-js';
3
+
4
+ // src/solid/class-mount-impl.tsx
5
+ var _tmpl$ = ['<div style="', '">', "</div>"];
6
+ function __mountComponent(el, theme, importFn) {
7
+ const Component = lazy(importFn);
8
+ const ThemeProvider = lazy(() => import('@tanstack/devtools-ui').then((m) => ({
9
+ default: m.ThemeContextProvider
10
+ })));
11
+ return render(() => createComponent(Portal, {
12
+ mount: el,
13
+ get children() {
14
+ return ssr(_tmpl$, ssrStyleProperty("height:", "100%"), escape(createComponent(ThemeProvider, {
15
+ theme,
16
+ get children() {
17
+ return createComponent(Component, {});
18
+ }
19
+ })));
20
+ }
21
+ }), el);
22
+ }
23
+
24
+ export { __mountComponent };
@@ -0,0 +1,26 @@
1
+ import { render, createComponent, Portal, insert, template } from 'solid-js/web';
2
+ import { lazy } from 'solid-js';
3
+
4
+ // src/solid/class-mount-impl.tsx
5
+ var _tmpl$ = /* @__PURE__ */ template(`<div style=height:100%>`);
6
+ function __mountComponent(el, theme, importFn) {
7
+ const Component = lazy(importFn);
8
+ const ThemeProvider = lazy(() => import('@tanstack/devtools-ui').then((m) => ({
9
+ default: m.ThemeContextProvider
10
+ })));
11
+ return render(() => createComponent(Portal, {
12
+ mount: el,
13
+ get children() {
14
+ var _el$ = _tmpl$();
15
+ insert(_el$, createComponent(ThemeProvider, {
16
+ theme,
17
+ get children() {
18
+ return createComponent(Component, {});
19
+ }
20
+ }));
21
+ return _el$;
22
+ }
23
+ }), el);
24
+ }
25
+
26
+ export { __mountComponent };
@@ -0,0 +1 @@
1
+ export { __mountComponent } from '../chunk/UX5ZZ4MG.js';
@@ -0,0 +1 @@
1
+ export { __mountComponent } from '../chunk/ZXPCWXRH.js';
@@ -1,58 +1,34 @@
1
- import { createComponent, insert, use, template } from 'solid-js/web';
1
+ export { __mountComponent } from './chunk/ZXPCWXRH.js';
2
+ import { use, createComponent, template } from 'solid-js/web';
2
3
  import { createSignal, onMount, onCleanup } from 'solid-js';
3
4
 
4
- // src/solid/class.tsx
5
- var _tmpl$ = /* @__PURE__ */ template(`<div style=height:100%>`);
6
- function constructCoreClass(Component) {
5
+ // src/solid/class.ts
6
+ function constructCoreClass(importFn) {
7
7
  class DevtoolsCore {
8
8
  #isMounted = false;
9
9
  #isMounting = false;
10
- #mountCb = null;
10
+ #abortMount = false;
11
11
  #dispose;
12
- #Component;
13
- #ThemeProvider;
14
12
  constructor() {
15
13
  }
16
14
  async mount(el, theme) {
17
- this.#isMounting = true;
18
- const {
19
- lazy
20
- } = await import('solid-js');
21
- const {
22
- render,
23
- Portal
24
- } = await import('solid-js/web');
25
- if (this.#isMounted) {
15
+ if (this.#isMounted || this.#isMounting) {
26
16
  throw new Error("Devtools is already mounted");
27
17
  }
28
- const mountTo = el;
29
- const dispose = render(() => {
30
- this.#Component = Component;
31
- this.#ThemeProvider = lazy(() => import('@tanstack/devtools-ui').then((mod) => ({
32
- default: mod.ThemeContextProvider
33
- })));
34
- const Devtools = this.#Component;
35
- const ThemeProvider = this.#ThemeProvider;
36
- return createComponent(Portal, {
37
- mount: mountTo,
38
- get children() {
39
- var _el$ = _tmpl$();
40
- insert(_el$, createComponent(ThemeProvider, {
41
- theme,
42
- get children() {
43
- return createComponent(Devtools, {});
44
- }
45
- }));
46
- return _el$;
47
- }
48
- });
49
- }, mountTo);
50
- this.#isMounted = true;
51
- this.#isMounting = false;
52
- this.#dispose = dispose;
53
- if (this.#mountCb) {
54
- this.#mountCb();
55
- this.#mountCb = null;
18
+ this.#isMounting = true;
19
+ this.#abortMount = false;
20
+ try {
21
+ const { __mountComponent: __mountComponent2 } = await import('./class-mount-impl/ZAIAXV4M.js');
22
+ if (this.#abortMount) {
23
+ this.#isMounting = false;
24
+ return;
25
+ }
26
+ this.#dispose = __mountComponent2(el, theme, importFn);
27
+ this.#isMounted = true;
28
+ this.#isMounting = false;
29
+ } catch (err) {
30
+ this.#isMounting = false;
31
+ console.error("[TanStack Devtools] Failed to load:", err);
56
32
  }
57
33
  }
58
34
  unmount() {
@@ -60,10 +36,8 @@ function constructCoreClass(Component) {
60
36
  throw new Error("Devtools is not mounted");
61
37
  }
62
38
  if (this.#isMounting) {
63
- this.#mountCb = () => {
64
- this.#dispose?.();
65
- this.#isMounted = false;
66
- };
39
+ this.#abortMount = true;
40
+ this.#isMounting = false;
67
41
  return;
68
42
  }
69
43
  this.#dispose?.();
@@ -81,7 +55,7 @@ function constructCoreClass(Component) {
81
55
  }
82
56
  return [DevtoolsCore, NoOpDevtoolsCore];
83
57
  }
84
- var _tmpl$2 = /* @__PURE__ */ template(`<div style=height:100%>`);
58
+ var _tmpl$ = /* @__PURE__ */ template(`<div style=height:100%>`);
85
59
  function createSolidPanel(CoreClass) {
86
60
  function Panel(props) {
87
61
  let devToolRef;
@@ -95,7 +69,7 @@ function createSolidPanel(CoreClass) {
95
69
  });
96
70
  });
97
71
  return (() => {
98
- var _el$ = _tmpl$2();
72
+ var _el$ = _tmpl$();
99
73
  var _ref$ = devToolRef;
100
74
  typeof _ref$ === "function" ? use(_ref$, _el$) : devToolRef = _el$;
101
75
  return _el$;
@@ -1,25 +1,23 @@
1
1
  import * as solid_js from 'solid-js';
2
2
  import { JSX } from 'solid-js';
3
3
 
4
- /** @jsxImportSource solid-js - we use Solid.js as JSX here */
5
-
6
4
  /**
7
5
  * Constructs the core class for the Devtools.
8
6
  * This utility is used to construct a lazy loaded Solid component for the Devtools.
9
7
  * It returns a tuple containing the main DevtoolsCore class and a NoOpDevtoolsCore class.
10
8
  * The NoOpDevtoolsCore class is a no-op implementation that can be used for production if you want to explicitly exclude
11
9
  * the Devtools from your application.
12
- * @param importPath The path to the Solid component to be lazily imported
10
+ * @param importFn A function that returns a dynamic import of the Solid component
13
11
  * @returns Tuple containing the DevtoolsCore class and a NoOpDevtoolsCore class
14
12
  */
15
- declare function constructCoreClass(Component: () => JSX.Element): readonly [{
13
+ declare function constructCoreClass(importFn: () => Promise<{
14
+ default: () => JSX.Element;
15
+ }>): readonly [{
16
16
  new (): {
17
17
  "__#private@#isMounted": boolean;
18
18
  "__#private@#isMounting": boolean;
19
- "__#private@#mountCb": (() => void) | null;
19
+ "__#private@#abortMount": boolean;
20
20
  "__#private@#dispose"?: () => void;
21
- "__#private@#Component": any;
22
- "__#private@#ThemeProvider": any;
23
21
  mount<T extends HTMLElement>(el: T, theme: "light" | "dark"): Promise<void>;
24
22
  unmount(): void;
25
23
  };
@@ -29,10 +27,8 @@ declare function constructCoreClass(Component: () => JSX.Element): readonly [{
29
27
  unmount(): void;
30
28
  "__#private@#isMounted": boolean;
31
29
  "__#private@#isMounting": boolean;
32
- "__#private@#mountCb": (() => void) | null;
30
+ "__#private@#abortMount": boolean;
33
31
  "__#private@#dispose"?: () => void;
34
- "__#private@#Component": any;
35
- "__#private@#ThemeProvider": any;
36
32
  };
37
33
  }];
38
34
  type ClassType = ReturnType<typeof constructCoreClass>[0];
@@ -61,4 +57,10 @@ declare function createSolidPlugin({ Component, ...config }: {
61
57
  defaultOpen?: boolean;
62
58
  }];
63
59
 
64
- export { type ClassType, type DevtoolsPanelProps, constructCoreClass, createSolidPanel, createSolidPlugin };
60
+ /** @jsxImportSource solid-js - we use Solid.js as JSX here */
61
+
62
+ declare function __mountComponent(el: HTMLElement, theme: 'light' | 'dark', importFn: () => Promise<{
63
+ default: () => JSX.Element;
64
+ }>): () => void;
65
+
66
+ export { type ClassType, type DevtoolsPanelProps, __mountComponent, constructCoreClass, createSolidPanel, createSolidPlugin };
@@ -1,58 +1,34 @@
1
- import { createComponent, insert, use, template } from 'solid-js/web';
1
+ export { __mountComponent } from './chunk/ZXPCWXRH.js';
2
+ import { use, createComponent, template } from 'solid-js/web';
2
3
  import { createSignal, onMount, onCleanup } from 'solid-js';
3
4
 
4
- // src/solid/class.tsx
5
- var _tmpl$ = /* @__PURE__ */ template(`<div style=height:100%>`);
6
- function constructCoreClass(Component) {
5
+ // src/solid/class.ts
6
+ function constructCoreClass(importFn) {
7
7
  class DevtoolsCore {
8
8
  #isMounted = false;
9
9
  #isMounting = false;
10
- #mountCb = null;
10
+ #abortMount = false;
11
11
  #dispose;
12
- #Component;
13
- #ThemeProvider;
14
12
  constructor() {
15
13
  }
16
14
  async mount(el, theme) {
17
- this.#isMounting = true;
18
- const {
19
- lazy
20
- } = await import('solid-js');
21
- const {
22
- render,
23
- Portal
24
- } = await import('solid-js/web');
25
- if (this.#isMounted) {
15
+ if (this.#isMounted || this.#isMounting) {
26
16
  throw new Error("Devtools is already mounted");
27
17
  }
28
- const mountTo = el;
29
- const dispose = render(() => {
30
- this.#Component = Component;
31
- this.#ThemeProvider = lazy(() => import('@tanstack/devtools-ui').then((mod) => ({
32
- default: mod.ThemeContextProvider
33
- })));
34
- const Devtools = this.#Component;
35
- const ThemeProvider = this.#ThemeProvider;
36
- return createComponent(Portal, {
37
- mount: mountTo,
38
- get children() {
39
- var _el$ = _tmpl$();
40
- insert(_el$, createComponent(ThemeProvider, {
41
- theme,
42
- get children() {
43
- return createComponent(Devtools, {});
44
- }
45
- }));
46
- return _el$;
47
- }
48
- });
49
- }, mountTo);
50
- this.#isMounted = true;
51
- this.#isMounting = false;
52
- this.#dispose = dispose;
53
- if (this.#mountCb) {
54
- this.#mountCb();
55
- this.#mountCb = null;
18
+ this.#isMounting = true;
19
+ this.#abortMount = false;
20
+ try {
21
+ const { __mountComponent: __mountComponent2 } = await import('./class-mount-impl/ZAIAXV4M.js');
22
+ if (this.#abortMount) {
23
+ this.#isMounting = false;
24
+ return;
25
+ }
26
+ this.#dispose = __mountComponent2(el, theme, importFn);
27
+ this.#isMounted = true;
28
+ this.#isMounting = false;
29
+ } catch (err) {
30
+ this.#isMounting = false;
31
+ console.error("[TanStack Devtools] Failed to load:", err);
56
32
  }
57
33
  }
58
34
  unmount() {
@@ -60,10 +36,8 @@ function constructCoreClass(Component) {
60
36
  throw new Error("Devtools is not mounted");
61
37
  }
62
38
  if (this.#isMounting) {
63
- this.#mountCb = () => {
64
- this.#dispose?.();
65
- this.#isMounted = false;
66
- };
39
+ this.#abortMount = true;
40
+ this.#isMounting = false;
67
41
  return;
68
42
  }
69
43
  this.#dispose?.();
@@ -81,7 +55,7 @@ function constructCoreClass(Component) {
81
55
  }
82
56
  return [DevtoolsCore, NoOpDevtoolsCore];
83
57
  }
84
- var _tmpl$2 = /* @__PURE__ */ template(`<div style=height:100%>`);
58
+ var _tmpl$ = /* @__PURE__ */ template(`<div style=height:100%>`);
85
59
  function createSolidPanel(CoreClass) {
86
60
  function Panel(props) {
87
61
  let devToolRef;
@@ -95,7 +69,7 @@ function createSolidPanel(CoreClass) {
95
69
  });
96
70
  });
97
71
  return (() => {
98
- var _el$ = _tmpl$2();
72
+ var _el$ = _tmpl$();
99
73
  var _ref$ = devToolRef;
100
74
  typeof _ref$ === "function" ? use(_ref$, _el$) : devToolRef = _el$;
101
75
  return _el$;
@@ -1,56 +1,34 @@
1
- import { createComponent, ssr, ssrStyleProperty, escape } from 'solid-js/web';
1
+ export { __mountComponent } from './chunk/UX5ZZ4MG.js';
2
+ import { ssr, ssrStyleProperty, createComponent } from 'solid-js/web';
2
3
  import { createSignal, onMount, onCleanup } from 'solid-js';
3
4
 
4
- // src/solid/class.tsx
5
- var _tmpl$ = ['<div style="', '">', "</div>"];
6
- function constructCoreClass(Component) {
5
+ // src/solid/class.ts
6
+ function constructCoreClass(importFn) {
7
7
  class DevtoolsCore {
8
8
  #isMounted = false;
9
9
  #isMounting = false;
10
- #mountCb = null;
10
+ #abortMount = false;
11
11
  #dispose;
12
- #Component;
13
- #ThemeProvider;
14
12
  constructor() {
15
13
  }
16
14
  async mount(el, theme) {
17
- this.#isMounting = true;
18
- const {
19
- lazy
20
- } = await import('solid-js');
21
- const {
22
- render,
23
- Portal
24
- } = await import('solid-js/web');
25
- if (this.#isMounted) {
15
+ if (this.#isMounted || this.#isMounting) {
26
16
  throw new Error("Devtools is already mounted");
27
17
  }
28
- const mountTo = el;
29
- const dispose = render(() => {
30
- this.#Component = Component;
31
- this.#ThemeProvider = lazy(() => import('@tanstack/devtools-ui').then((mod) => ({
32
- default: mod.ThemeContextProvider
33
- })));
34
- const Devtools = this.#Component;
35
- const ThemeProvider = this.#ThemeProvider;
36
- return createComponent(Portal, {
37
- mount: mountTo,
38
- get children() {
39
- return ssr(_tmpl$, ssrStyleProperty("height:", "100%"), escape(createComponent(ThemeProvider, {
40
- theme,
41
- get children() {
42
- return createComponent(Devtools, {});
43
- }
44
- })));
45
- }
46
- });
47
- }, mountTo);
48
- this.#isMounted = true;
49
- this.#isMounting = false;
50
- this.#dispose = dispose;
51
- if (this.#mountCb) {
52
- this.#mountCb();
53
- this.#mountCb = null;
18
+ this.#isMounting = true;
19
+ this.#abortMount = false;
20
+ try {
21
+ const { __mountComponent: __mountComponent2 } = await import('./class-mount-impl/LK7V47IP.js');
22
+ if (this.#abortMount) {
23
+ this.#isMounting = false;
24
+ return;
25
+ }
26
+ this.#dispose = __mountComponent2(el, theme, importFn);
27
+ this.#isMounted = true;
28
+ this.#isMounting = false;
29
+ } catch (err) {
30
+ this.#isMounting = false;
31
+ console.error("[TanStack Devtools] Failed to load:", err);
54
32
  }
55
33
  }
56
34
  unmount() {
@@ -58,10 +36,8 @@ function constructCoreClass(Component) {
58
36
  throw new Error("Devtools is not mounted");
59
37
  }
60
38
  if (this.#isMounting) {
61
- this.#mountCb = () => {
62
- this.#dispose?.();
63
- this.#isMounted = false;
64
- };
39
+ this.#abortMount = true;
40
+ this.#isMounting = false;
65
41
  return;
66
42
  }
67
43
  this.#dispose?.();
@@ -79,7 +55,7 @@ function constructCoreClass(Component) {
79
55
  }
80
56
  return [DevtoolsCore, NoOpDevtoolsCore];
81
57
  }
82
- var _tmpl$2 = ['<div style="', '"></div>'];
58
+ var _tmpl$ = ['<div style="', '"></div>'];
83
59
  function createSolidPanel(CoreClass) {
84
60
  function Panel(props) {
85
61
  const [devtools] = createSignal(new CoreClass());
@@ -88,7 +64,7 @@ function createSolidPanel(CoreClass) {
88
64
  devtools().unmount();
89
65
  });
90
66
  });
91
- return ssr(_tmpl$2, ssrStyleProperty("height:", "100%"));
67
+ return ssr(_tmpl$, ssrStyleProperty("height:", "100%"));
92
68
  }
93
69
  function NoOpPanel(_props) {
94
70
  return [];
@@ -0,0 +1,4 @@
1
+ import { JSX } from 'solid-js';
2
+ export declare function __mountComponent(el: HTMLElement, theme: 'light' | 'dark', importFn: () => Promise<{
3
+ default: () => JSX.Element;
4
+ }>): () => void;
@@ -0,0 +1,26 @@
1
+ import { render, createComponent, Portal, insert, template } from "solid-js/web";
2
+ import { lazy } from "solid-js";
3
+ var _tmpl$ = /* @__PURE__ */ template(`<div style=height:100%>`);
4
+ function __mountComponent(el, theme, importFn) {
5
+ const Component = lazy(importFn);
6
+ const ThemeProvider = lazy(() => import("@tanstack/devtools-ui").then((m) => ({
7
+ default: m.ThemeContextProvider
8
+ })));
9
+ return render(() => createComponent(Portal, {
10
+ mount: el,
11
+ get children() {
12
+ var _el$ = _tmpl$();
13
+ insert(_el$, createComponent(ThemeProvider, {
14
+ theme,
15
+ get children() {
16
+ return createComponent(Component, {});
17
+ }
18
+ }));
19
+ return _el$;
20
+ }
21
+ }), el);
22
+ }
23
+ export {
24
+ __mountComponent
25
+ };
26
+ //# sourceMappingURL=class-mount-impl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"class-mount-impl.js","sources":["../../../src/solid/class-mount-impl.tsx"],"sourcesContent":["/** @jsxImportSource solid-js - we use Solid.js as JSX here */\n\nimport { lazy } from 'solid-js'\nimport { Portal, render } from 'solid-js/web'\nimport type { JSX } from 'solid-js'\n\nexport function __mountComponent(\n el: HTMLElement,\n theme: 'light' | 'dark',\n importFn: () => Promise<{ default: () => JSX.Element }>,\n): () => void {\n const Component = lazy(importFn)\n const ThemeProvider = lazy(() =>\n import('@tanstack/devtools-ui').then((m) => ({\n default: m.ThemeContextProvider,\n })),\n )\n\n return render(\n () => (\n <Portal mount={el}>\n <div style={{ height: '100%' }}>\n <ThemeProvider theme={theme}>\n <Component />\n </ThemeProvider>\n </div>\n </Portal>\n ),\n el,\n )\n}\n"],"names":["__mountComponent","el","theme","importFn","Component","lazy","ThemeProvider","then","m","default","ThemeContextProvider","render","_$createComponent","Portal","mount","children","_el$","_tmpl$","_$insert"],"mappings":";;;AAMO,SAASA,iBACdC,IACAC,OACAC,UACY;AACZ,QAAMC,YAAYC,KAAKF,QAAQ;AAC/B,QAAMG,gBAAgBD,KAAK,MACzB,OAAO,uBAAuB,EAAEE,KAAMC,CAAAA,OAAO;AAAA,IAC3CC,SAASD,EAAEE;AAAAA,EAAAA,EACX,CACJ;AAEA,SAAOC,OACL,MAAAC,gBACGC,QAAM;AAAA,IAACC,OAAOb;AAAAA,IAAE,IAAAc,WAAA;AAAA,UAAAC,OAAAC,OAAAA;AAAAC,aAAAF,MAAAJ,gBAEZN,eAAa;AAAA,QAACJ;AAAAA,QAAY,IAAAa,WAAA;AAAA,iBAAAH,gBACxBR,WAAS,EAAA;AAAA,QAAA;AAAA,MAAA,CAAA,CAAA;AAAA,aAAAY;AAAAA,IAAA;AAAA,EAAA,CAAA,GAKlBf,EACF;AACF;"}
@@ -0,0 +1,32 @@
1
+ import { JSX } from 'solid-js';
2
+ /**
3
+ * Constructs the core class for the Devtools.
4
+ * This utility is used to construct a lazy loaded Solid component for the Devtools.
5
+ * It returns a tuple containing the main DevtoolsCore class and a NoOpDevtoolsCore class.
6
+ * The NoOpDevtoolsCore class is a no-op implementation that can be used for production if you want to explicitly exclude
7
+ * the Devtools from your application.
8
+ * @param importFn A function that returns a dynamic import of the Solid component
9
+ * @returns Tuple containing the DevtoolsCore class and a NoOpDevtoolsCore class
10
+ */
11
+ export declare function constructCoreClass(importFn: () => Promise<{
12
+ default: () => JSX.Element;
13
+ }>): readonly [{
14
+ new (): {
15
+ "__#private@#isMounted": boolean;
16
+ "__#private@#isMounting": boolean;
17
+ "__#private@#abortMount": boolean;
18
+ "__#private@#dispose"?: () => void;
19
+ mount<T extends HTMLElement>(el: T, theme: "light" | "dark"): Promise<void>;
20
+ unmount(): void;
21
+ };
22
+ }, {
23
+ new (): {
24
+ mount<T extends HTMLElement>(_el: T, _theme: "light" | "dark"): Promise<void>;
25
+ unmount(): void;
26
+ "__#private@#isMounted": boolean;
27
+ "__#private@#isMounting": boolean;
28
+ "__#private@#abortMount": boolean;
29
+ "__#private@#dispose"?: () => void;
30
+ };
31
+ }];
32
+ export type ClassType = ReturnType<typeof constructCoreClass>[0];
@@ -0,0 +1,56 @@
1
+ function constructCoreClass(importFn) {
2
+ class DevtoolsCore {
3
+ #isMounted = false;
4
+ #isMounting = false;
5
+ #abortMount = false;
6
+ #dispose;
7
+ constructor() {
8
+ }
9
+ async mount(el, theme) {
10
+ if (this.#isMounted || this.#isMounting) {
11
+ throw new Error("Devtools is already mounted");
12
+ }
13
+ this.#isMounting = true;
14
+ this.#abortMount = false;
15
+ try {
16
+ const { __mountComponent } = await import("./class-mount-impl.js");
17
+ if (this.#abortMount) {
18
+ this.#isMounting = false;
19
+ return;
20
+ }
21
+ this.#dispose = __mountComponent(el, theme, importFn);
22
+ this.#isMounted = true;
23
+ this.#isMounting = false;
24
+ } catch (err) {
25
+ this.#isMounting = false;
26
+ console.error("[TanStack Devtools] Failed to load:", err);
27
+ }
28
+ }
29
+ unmount() {
30
+ if (!this.#isMounted && !this.#isMounting) {
31
+ throw new Error("Devtools is not mounted");
32
+ }
33
+ if (this.#isMounting) {
34
+ this.#abortMount = true;
35
+ this.#isMounting = false;
36
+ return;
37
+ }
38
+ this.#dispose?.();
39
+ this.#isMounted = false;
40
+ }
41
+ }
42
+ class NoOpDevtoolsCore extends DevtoolsCore {
43
+ constructor() {
44
+ super();
45
+ }
46
+ async mount(_el, _theme) {
47
+ }
48
+ unmount() {
49
+ }
50
+ }
51
+ return [DevtoolsCore, NoOpDevtoolsCore];
52
+ }
53
+ export {
54
+ constructCoreClass
55
+ };
56
+ //# sourceMappingURL=class.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"class.js","sources":["../../../src/solid/class.ts"],"sourcesContent":["import type { JSX } from 'solid-js'\n\n/**\n * Constructs the core class for the Devtools.\n * This utility is used to construct a lazy loaded Solid component for the Devtools.\n * It returns a tuple containing the main DevtoolsCore class and a NoOpDevtoolsCore class.\n * The NoOpDevtoolsCore class is a no-op implementation that can be used for production if you want to explicitly exclude\n * the Devtools from your application.\n * @param importFn A function that returns a dynamic import of the Solid component\n * @returns Tuple containing the DevtoolsCore class and a NoOpDevtoolsCore class\n */\nexport function constructCoreClass(\n importFn: () => Promise<{ default: () => JSX.Element }>,\n) {\n class DevtoolsCore {\n #isMounted = false\n #isMounting = false\n #abortMount = false\n #dispose?: () => void\n\n constructor() {}\n\n async mount<T extends HTMLElement>(el: T, theme: 'light' | 'dark') {\n if (this.#isMounted || this.#isMounting) {\n throw new Error('Devtools is already mounted')\n }\n this.#isMounting = true\n this.#abortMount = false\n\n try {\n const { __mountComponent } = await import('./class-mount-impl')\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- can be set by unmount() during await\n if (this.#abortMount) {\n this.#isMounting = false\n return\n }\n\n this.#dispose = __mountComponent(el, theme, importFn)\n this.#isMounted = true\n this.#isMounting = false\n } catch (err) {\n this.#isMounting = false\n console.error('[TanStack Devtools] Failed to load:', err)\n }\n }\n\n unmount() {\n if (!this.#isMounted && !this.#isMounting) {\n throw new Error('Devtools is not mounted')\n }\n if (this.#isMounting) {\n this.#abortMount = true\n this.#isMounting = false\n return\n }\n this.#dispose?.()\n this.#isMounted = false\n }\n }\n\n class NoOpDevtoolsCore extends DevtoolsCore {\n constructor() {\n super()\n }\n async mount<T extends HTMLElement>(_el: T, _theme: 'light' | 'dark') {}\n unmount() {}\n }\n\n return [DevtoolsCore, NoOpDevtoolsCore] as const\n}\n\nexport type ClassType = ReturnType<typeof constructCoreClass>[0]\n"],"names":[],"mappings":"AAWO,SAAS,mBACd,UACA;AAAA,EACA,MAAM,aAAa;AAAA,IACjB,aAAa;AAAA,IACb,cAAc;AAAA,IACd,cAAc;AAAA,IACd;AAAA,IAEA,cAAc;AAAA,IAAC;AAAA,IAEf,MAAM,MAA6B,IAAO,OAAyB;AACjE,UAAI,KAAK,cAAc,KAAK,aAAa;AACvC,cAAM,IAAI,MAAM,6BAA6B;AAAA,MAC/C;AACA,WAAK,cAAc;AACnB,WAAK,cAAc;AAEnB,UAAI;AACF,cAAM,EAAE,iBAAA,IAAqB,MAAM,OAAO,uBAAoB;AAE9D,YAAI,KAAK,aAAa;AACpB,eAAK,cAAc;AACnB;AAAA,QACF;AAEA,aAAK,WAAW,iBAAiB,IAAI,OAAO,QAAQ;AACpD,aAAK,aAAa;AAClB,aAAK,cAAc;AAAA,MACrB,SAAS,KAAK;AACZ,aAAK,cAAc;AACnB,gBAAQ,MAAM,uCAAuC,GAAG;AAAA,MAC1D;AAAA,IACF;AAAA,IAEA,UAAU;AACR,UAAI,CAAC,KAAK,cAAc,CAAC,KAAK,aAAa;AACzC,cAAM,IAAI,MAAM,yBAAyB;AAAA,MAC3C;AACA,UAAI,KAAK,aAAa;AACpB,aAAK,cAAc;AACnB,aAAK,cAAc;AACnB;AAAA,MACF;AACA,WAAK,WAAA;AACL,WAAK,aAAa;AAAA,IACpB;AAAA,EAAA;AAAA,EAGF,MAAM,yBAAyB,aAAa;AAAA,IAC1C,cAAc;AACZ,YAAA;AAAA,IACF;AAAA,IACA,MAAM,MAA6B,KAAQ,QAA0B;AAAA,IAAC;AAAA,IACtE,UAAU;AAAA,IAAC;AAAA,EAAA;AAGb,SAAO,CAAC,cAAc,gBAAgB;AACxC;"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ export * from './class.js';
2
+ export * from './panel.js';
3
+ export * from './plugin.js';
4
+ export { __mountComponent } from './class-mount-impl.js';
@@ -0,0 +1,5 @@
1
+ import { ClassType } from './class.js';
2
+ export interface DevtoolsPanelProps {
3
+ theme?: 'light' | 'dark';
4
+ }
5
+ export declare function createSolidPanel<TComponentProps extends DevtoolsPanelProps | undefined>(CoreClass: ClassType): readonly [(props: TComponentProps) => import("solid-js").JSX.Element, (_props: TComponentProps) => import("solid-js").JSX.Element];
@@ -0,0 +1,18 @@
1
+ import { JSX } from 'solid-js';
2
+ import { DevtoolsPanelProps } from './panel.js';
3
+ export declare function createSolidPlugin({ Component, ...config }: {
4
+ name: string;
5
+ id?: string;
6
+ defaultOpen?: boolean;
7
+ Component: (props: DevtoolsPanelProps) => JSX.Element;
8
+ }): readonly [() => {
9
+ render: (_el: HTMLElement, theme: "light" | "dark") => JSX.Element;
10
+ name: string;
11
+ id?: string;
12
+ defaultOpen?: boolean;
13
+ }, () => {
14
+ render: (_el: HTMLElement, _theme: "light" | "dark") => JSX.Element;
15
+ name: string;
16
+ id?: string;
17
+ defaultOpen?: boolean;
18
+ }];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/devtools-utils",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "TanStack Devtools utilities for creating your own devtools.",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -32,6 +32,10 @@
32
32
  }
33
33
  },
34
34
  "./solid": {
35
+ "workerd": {
36
+ "types": "./dist/solid/esm/index.d.ts",
37
+ "import": "./dist/solid/esm/server.js"
38
+ },
35
39
  "browser": {
36
40
  "development": {
37
41
  "types": "./dist/solid/esm/index.d.ts",
@@ -47,6 +51,12 @@
47
51
  "types": "./dist/solid/esm/index.d.ts",
48
52
  "import": "./dist/solid/esm/index.js"
49
53
  },
54
+ "./solid/class": {
55
+ "import": {
56
+ "types": "./dist/solid-class/esm/class.d.ts",
57
+ "default": "./dist/solid-class/esm/class.js"
58
+ }
59
+ },
50
60
  "./vue": {
51
61
  "import": {
52
62
  "types": "./dist/vue/esm/index.d.ts",
@@ -103,6 +113,6 @@
103
113
  "test:lib:dev": "pnpm test:lib --watch",
104
114
  "test:types": "tsc",
105
115
  "test:build": "publint --strict",
106
- "build": "vite build && vite build --config vite.config.preact.ts && vite build --config vite.config.vue.ts && tsup "
116
+ "build": "vite build && vite build --config vite.config.preact.ts && vite build --config vite.config.vue.ts && vite build --config vite.config.solid-class.ts && tsup"
107
117
  }
108
118
  }
@@ -0,0 +1,31 @@
1
+ /** @jsxImportSource solid-js - we use Solid.js as JSX here */
2
+
3
+ import { lazy } from 'solid-js'
4
+ import { Portal, render } from 'solid-js/web'
5
+ import type { JSX } from 'solid-js'
6
+
7
+ export function __mountComponent(
8
+ el: HTMLElement,
9
+ theme: 'light' | 'dark',
10
+ importFn: () => Promise<{ default: () => JSX.Element }>,
11
+ ): () => void {
12
+ const Component = lazy(importFn)
13
+ const ThemeProvider = lazy(() =>
14
+ import('@tanstack/devtools-ui').then((m) => ({
15
+ default: m.ThemeContextProvider,
16
+ })),
17
+ )
18
+
19
+ return render(
20
+ () => (
21
+ <Portal mount={el}>
22
+ <div style={{ height: '100%' }}>
23
+ <ThemeProvider theme={theme}>
24
+ <Component />
25
+ </ThemeProvider>
26
+ </div>
27
+ </Portal>
28
+ ),
29
+ el,
30
+ )
31
+ }
@@ -2,53 +2,38 @@
2
2
  import { beforeEach, describe, expect, it, vi } from 'vitest'
3
3
  import { constructCoreClass } from './class'
4
4
 
5
- const lazyImportMock = vi.fn((fn) => fn())
6
- const renderMock = vi.fn()
7
- const portalMock = vi.fn((props: any) => <div>{props.children}</div>)
5
+ const disposeMock = vi.fn()
6
+ const mountComponentMock = vi.fn(() => disposeMock)
8
7
 
9
- vi.mock('solid-js', async () => {
10
- const actual = await vi.importActual<any>('solid-js')
11
- return {
12
- ...actual,
13
- lazy: lazyImportMock,
14
- }
15
- })
8
+ vi.mock('./class-mount-impl', () => ({
9
+ __mountComponent: mountComponentMock,
10
+ }))
16
11
 
17
- vi.mock('solid-js/web', async () => {
18
- const actual = await vi.importActual<any>('solid-js/web')
19
- return {
20
- ...actual,
21
- render: renderMock,
22
- Portal: portalMock,
23
- }
24
- })
12
+ const importFn = () =>
13
+ Promise.resolve({ default: () => <div>Test Component</div> })
25
14
 
26
15
  describe('constructCoreClass', () => {
27
16
  beforeEach(() => {
28
17
  vi.clearAllMocks()
29
18
  })
19
+
30
20
  it('should export DevtoolsCore and NoOpDevtoolsCore classes and make no calls to Solid.js primitives', () => {
31
- const [DevtoolsCore, NoOpDevtoolsCore] = constructCoreClass(() => (
32
- <div>Test Component</div>
33
- ))
21
+ const [DevtoolsCore, NoOpDevtoolsCore] = constructCoreClass(importFn)
34
22
  expect(DevtoolsCore).toBeDefined()
35
23
  expect(NoOpDevtoolsCore).toBeDefined()
36
- expect(lazyImportMock).not.toHaveBeenCalled()
24
+ expect(mountComponentMock).not.toHaveBeenCalled()
37
25
  })
38
26
 
39
- it('DevtoolsCore should call solid primitives when mount is called', async () => {
40
- const [DevtoolsCore, _] = constructCoreClass(() => (
41
- <div>Test Component</div>
42
- ))
27
+ it('DevtoolsCore should call __mountComponent when mount is called', async () => {
28
+ const [DevtoolsCore] = constructCoreClass(importFn)
43
29
  const instance = new DevtoolsCore()
44
- await instance.mount(document.createElement('div'), 'dark')
45
- expect(renderMock).toHaveBeenCalled()
30
+ const el = document.createElement('div')
31
+ await instance.mount(el, 'dark')
32
+ expect(mountComponentMock).toHaveBeenCalledWith(el, 'dark', importFn)
46
33
  })
47
34
 
48
35
  it('DevtoolsCore should throw if mount is called twice without unmounting', async () => {
49
- const [DevtoolsCore, _] = constructCoreClass(() => (
50
- <div>Test Component</div>
51
- ))
36
+ const [DevtoolsCore] = constructCoreClass(importFn)
52
37
  const instance = new DevtoolsCore()
53
38
  await instance.mount(document.createElement('div'), 'dark')
54
39
  await expect(
@@ -57,17 +42,13 @@ describe('constructCoreClass', () => {
57
42
  })
58
43
 
59
44
  it('DevtoolsCore should throw if unmount is called before mount', () => {
60
- const [DevtoolsCore, _] = constructCoreClass(() => (
61
- <div>Test Component</div>
62
- ))
45
+ const [DevtoolsCore] = constructCoreClass(importFn)
63
46
  const instance = new DevtoolsCore()
64
47
  expect(() => instance.unmount()).toThrow('Devtools is not mounted')
65
48
  })
66
49
 
67
50
  it('DevtoolsCore should allow mount after unmount', async () => {
68
- const [DevtoolsCore, _] = constructCoreClass(() => (
69
- <div>Test Component</div>
70
- ))
51
+ const [DevtoolsCore] = constructCoreClass(importFn)
71
52
  const instance = new DevtoolsCore()
72
53
  await instance.mount(document.createElement('div'), 'dark')
73
54
  instance.unmount()
@@ -76,22 +57,35 @@ describe('constructCoreClass', () => {
76
57
  ).resolves.not.toThrow()
77
58
  })
78
59
 
79
- it('NoOpDevtoolsCore should not call any solid primitives when mount is called', async () => {
80
- const [_, NoOpDevtoolsCore] = constructCoreClass(() => (
81
- <div>Test Component</div>
82
- ))
60
+ it('DevtoolsCore should call dispose on unmount', async () => {
61
+ const [DevtoolsCore] = constructCoreClass(importFn)
62
+ const instance = new DevtoolsCore()
63
+ await instance.mount(document.createElement('div'), 'dark')
64
+ instance.unmount()
65
+ expect(disposeMock).toHaveBeenCalled()
66
+ })
67
+
68
+ it('DevtoolsCore should abort mount if unmount is called during mounting', async () => {
69
+ const [DevtoolsCore] = constructCoreClass(importFn)
70
+ const instance = new DevtoolsCore()
71
+ const mountPromise = instance.mount(document.createElement('div'), 'dark')
72
+ // Unmount while mount is in progress — triggers abort path
73
+ // Note: since the mock resolves immediately, this tests the #abortMount flag
74
+ await mountPromise
75
+ // Mount completed, so unmount should work normally
76
+ instance.unmount()
77
+ expect(disposeMock).toHaveBeenCalled()
78
+ })
79
+
80
+ it('NoOpDevtoolsCore should not call __mountComponent when mount is called', async () => {
81
+ const [, NoOpDevtoolsCore] = constructCoreClass(importFn)
83
82
  const noOpInstance = new NoOpDevtoolsCore()
84
83
  await noOpInstance.mount(document.createElement('div'), 'dark')
85
-
86
- expect(lazyImportMock).not.toHaveBeenCalled()
87
- expect(renderMock).not.toHaveBeenCalled()
88
- expect(portalMock).not.toHaveBeenCalled()
84
+ expect(mountComponentMock).not.toHaveBeenCalled()
89
85
  })
90
86
 
91
87
  it('NoOpDevtoolsCore should not throw if mount is called multiple times', async () => {
92
- const [_, NoOpDevtoolsCore] = constructCoreClass(() => (
93
- <div>Test Component</div>
94
- ))
88
+ const [, NoOpDevtoolsCore] = constructCoreClass(importFn)
95
89
  const noOpInstance = new NoOpDevtoolsCore()
96
90
  await noOpInstance.mount(document.createElement('div'), 'dark')
97
91
  await expect(
@@ -100,17 +94,13 @@ describe('constructCoreClass', () => {
100
94
  })
101
95
 
102
96
  it('NoOpDevtoolsCore should not throw if unmount is called before mount', () => {
103
- const [_, NoOpDevtoolsCore] = constructCoreClass(() => (
104
- <div>Test Component</div>
105
- ))
97
+ const [, NoOpDevtoolsCore] = constructCoreClass(importFn)
106
98
  const noOpInstance = new NoOpDevtoolsCore()
107
99
  expect(() => noOpInstance.unmount()).not.toThrow()
108
100
  })
109
101
 
110
102
  it('NoOpDevtoolsCore should not throw if unmount is called after mount', async () => {
111
- const [_, NoOpDevtoolsCore] = constructCoreClass(() => (
112
- <div>Test Component</div>
113
- ))
103
+ const [, NoOpDevtoolsCore] = constructCoreClass(importFn)
114
104
  const noOpInstance = new NoOpDevtoolsCore()
115
105
  await noOpInstance.mount(document.createElement('div'), 'dark')
116
106
  expect(() => noOpInstance.unmount()).not.toThrow()
@@ -1,5 +1,3 @@
1
- /** @jsxImportSource solid-js - we use Solid.js as JSX here */
2
-
3
1
  import type { JSX } from 'solid-js'
4
2
 
5
3
  /**
@@ -8,55 +6,41 @@ import type { JSX } from 'solid-js'
8
6
  * It returns a tuple containing the main DevtoolsCore class and a NoOpDevtoolsCore class.
9
7
  * The NoOpDevtoolsCore class is a no-op implementation that can be used for production if you want to explicitly exclude
10
8
  * the Devtools from your application.
11
- * @param importPath The path to the Solid component to be lazily imported
9
+ * @param importFn A function that returns a dynamic import of the Solid component
12
10
  * @returns Tuple containing the DevtoolsCore class and a NoOpDevtoolsCore class
13
11
  */
14
- export function constructCoreClass(Component: () => JSX.Element) {
12
+ export function constructCoreClass(
13
+ importFn: () => Promise<{ default: () => JSX.Element }>,
14
+ ) {
15
15
  class DevtoolsCore {
16
16
  #isMounted = false
17
17
  #isMounting = false
18
- #mountCb: (() => void) | null = null
18
+ #abortMount = false
19
19
  #dispose?: () => void
20
- #Component: any
21
- #ThemeProvider: any
22
20
 
23
21
  constructor() {}
24
22
 
25
23
  async mount<T extends HTMLElement>(el: T, theme: 'light' | 'dark') {
26
- this.#isMounting = true
27
- const { lazy } = await import('solid-js')
28
- const { render, Portal } = await import('solid-js/web')
29
- if (this.#isMounted) {
24
+ if (this.#isMounted || this.#isMounting) {
30
25
  throw new Error('Devtools is already mounted')
31
26
  }
32
- const mountTo = el
33
- const dispose = render(() => {
34
- this.#Component = Component
27
+ this.#isMounting = true
28
+ this.#abortMount = false
35
29
 
36
- this.#ThemeProvider = lazy(() =>
37
- import('@tanstack/devtools-ui').then((mod) => ({
38
- default: mod.ThemeContextProvider,
39
- })),
40
- )
41
- const Devtools = this.#Component
42
- const ThemeProvider = this.#ThemeProvider
30
+ try {
31
+ const { __mountComponent } = await import('./class-mount-impl')
32
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- can be set by unmount() during await
33
+ if (this.#abortMount) {
34
+ this.#isMounting = false
35
+ return
36
+ }
43
37
 
44
- return (
45
- <Portal mount={mountTo}>
46
- <div style={{ height: '100%' }}>
47
- <ThemeProvider theme={theme}>
48
- <Devtools />
49
- </ThemeProvider>
50
- </div>
51
- </Portal>
52
- )
53
- }, mountTo)
54
- this.#isMounted = true
55
- this.#isMounting = false
56
- this.#dispose = dispose
57
- if (this.#mountCb) {
58
- this.#mountCb()
59
- this.#mountCb = null
38
+ this.#dispose = __mountComponent(el, theme, importFn)
39
+ this.#isMounted = true
40
+ this.#isMounting = false
41
+ } catch (err) {
42
+ this.#isMounting = false
43
+ console.error('[TanStack Devtools] Failed to load:', err)
60
44
  }
61
45
  }
62
46
 
@@ -65,16 +49,15 @@ export function constructCoreClass(Component: () => JSX.Element) {
65
49
  throw new Error('Devtools is not mounted')
66
50
  }
67
51
  if (this.#isMounting) {
68
- this.#mountCb = () => {
69
- this.#dispose?.()
70
- this.#isMounted = false
71
- }
52
+ this.#abortMount = true
53
+ this.#isMounting = false
72
54
  return
73
55
  }
74
56
  this.#dispose?.()
75
57
  this.#isMounted = false
76
58
  }
77
59
  }
60
+
78
61
  class NoOpDevtoolsCore extends DevtoolsCore {
79
62
  constructor() {
80
63
  super()
@@ -82,6 +65,7 @@ export function constructCoreClass(Component: () => JSX.Element) {
82
65
  async mount<T extends HTMLElement>(_el: T, _theme: 'light' | 'dark') {}
83
66
  unmount() {}
84
67
  }
68
+
85
69
  return [DevtoolsCore, NoOpDevtoolsCore] as const
86
70
  }
87
71
 
@@ -1,3 +1,4 @@
1
1
  export * from './class'
2
2
  export * from './panel'
3
3
  export * from './plugin'
4
+ export { __mountComponent } from './class-mount-impl'