@tanstack/devtools-utils
Advanced tools
| import { JSX } from 'solid-js'; | ||
| export declare function __mountComponent(el: HTMLElement, theme: 'light' | 'dark', importFn: () => Promise<{ | ||
| default: () => JSX.Element; | ||
| }>): () => void; |
| import { render, createComponent, Portal, insert, template } from "solid-js/web"; | ||
| import { lazy } from "solid-js"; | ||
| var _tmpl$ = /* @__PURE__ */ template(`<div style=height:100%>`); | ||
| function __mountComponent(el, theme, importFn) { | ||
| const Component = lazy(importFn); | ||
| const ThemeProvider = lazy(() => import("@tanstack/devtools-ui").then((m) => ({ | ||
| default: m.ThemeContextProvider | ||
| }))); | ||
| return render(() => createComponent(Portal, { | ||
| mount: el, | ||
| get children() { | ||
| var _el$ = _tmpl$(); | ||
| insert(_el$, createComponent(ThemeProvider, { | ||
| theme, | ||
| get children() { | ||
| return createComponent(Component, {}); | ||
| } | ||
| })); | ||
| return _el$; | ||
| } | ||
| }), el); | ||
| } | ||
| export { | ||
| __mountComponent | ||
| }; | ||
| //# sourceMappingURL=class-mount-impl.js.map |
| {"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;"} |
| import { JSX } from 'solid-js'; | ||
| /** | ||
| * Constructs the core class for the Devtools. | ||
| * This utility is used to construct a lazy loaded Solid component for the Devtools. | ||
| * It returns a tuple containing the main DevtoolsCore class and a NoOpDevtoolsCore class. | ||
| * The NoOpDevtoolsCore class is a no-op implementation that can be used for production if you want to explicitly exclude | ||
| * the Devtools from your application. | ||
| * @param importFn A function that returns a dynamic import of the Solid component | ||
| * @returns Tuple containing the DevtoolsCore class and a NoOpDevtoolsCore class | ||
| */ | ||
| export declare function constructCoreClass(importFn: () => Promise<{ | ||
| default: () => JSX.Element; | ||
| }>): readonly [{ | ||
| new (): { | ||
| "__#private@#isMounted": boolean; | ||
| "__#private@#isMounting": boolean; | ||
| "__#private@#abortMount": boolean; | ||
| "__#private@#dispose"?: () => void; | ||
| mount<T extends HTMLElement>(el: T, theme: "light" | "dark"): Promise<void>; | ||
| unmount(): void; | ||
| }; | ||
| }, { | ||
| new (): { | ||
| mount<T extends HTMLElement>(_el: T, _theme: "light" | "dark"): Promise<void>; | ||
| unmount(): void; | ||
| "__#private@#isMounted": boolean; | ||
| "__#private@#isMounting": boolean; | ||
| "__#private@#abortMount": boolean; | ||
| "__#private@#dispose"?: () => void; | ||
| }; | ||
| }]; | ||
| export type ClassType = ReturnType<typeof constructCoreClass>[0]; |
| function constructCoreClass(importFn) { | ||
| class DevtoolsCore { | ||
| #isMounted = false; | ||
| #isMounting = false; | ||
| #abortMount = false; | ||
| #dispose; | ||
| constructor() { | ||
| } | ||
| async mount(el, theme) { | ||
| if (this.#isMounted || this.#isMounting) { | ||
| throw new Error("Devtools is already mounted"); | ||
| } | ||
| this.#isMounting = true; | ||
| this.#abortMount = false; | ||
| try { | ||
| const { __mountComponent } = await import("./class-mount-impl.js"); | ||
| if (this.#abortMount) { | ||
| this.#isMounting = false; | ||
| return; | ||
| } | ||
| this.#dispose = __mountComponent(el, theme, importFn); | ||
| this.#isMounted = true; | ||
| this.#isMounting = false; | ||
| } catch (err) { | ||
| this.#isMounting = false; | ||
| console.error("[TanStack Devtools] Failed to load:", err); | ||
| } | ||
| } | ||
| unmount() { | ||
| if (!this.#isMounted && !this.#isMounting) { | ||
| throw new Error("Devtools is not mounted"); | ||
| } | ||
| if (this.#isMounting) { | ||
| this.#abortMount = true; | ||
| this.#isMounting = false; | ||
| return; | ||
| } | ||
| this.#dispose?.(); | ||
| this.#isMounted = false; | ||
| } | ||
| } | ||
| class NoOpDevtoolsCore extends DevtoolsCore { | ||
| constructor() { | ||
| super(); | ||
| } | ||
| async mount(_el, _theme) { | ||
| } | ||
| unmount() { | ||
| } | ||
| } | ||
| return [DevtoolsCore, NoOpDevtoolsCore]; | ||
| } | ||
| export { | ||
| constructCoreClass | ||
| }; | ||
| //# sourceMappingURL=class.js.map |
| {"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;"} |
| export {}; |
| export * from './class.js'; | ||
| export * from './panel.js'; | ||
| export * from './plugin.js'; | ||
| export { __mountComponent } from './class-mount-impl.js'; |
| import { ClassType } from './class.js'; | ||
| export interface DevtoolsPanelProps { | ||
| theme?: 'light' | 'dark'; | ||
| } | ||
| 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]; |
| import { JSX } from 'solid-js'; | ||
| import { DevtoolsPanelProps } from './panel.js'; | ||
| export declare function createSolidPlugin({ Component, ...config }: { | ||
| name: string; | ||
| id?: string; | ||
| defaultOpen?: boolean; | ||
| Component: (props: DevtoolsPanelProps) => JSX.Element; | ||
| }): readonly [() => { | ||
| render: (_el: HTMLElement, theme: "light" | "dark") => JSX.Element; | ||
| name: string; | ||
| id?: string; | ||
| defaultOpen?: boolean; | ||
| }, () => { | ||
| render: (_el: HTMLElement, _theme: "light" | "dark") => JSX.Element; | ||
| name: string; | ||
| id?: string; | ||
| defaultOpen?: boolean; | ||
| }]; |
| import { render, createComponent, Portal, ssr, ssrStyleProperty, escape } from 'solid-js/web'; | ||
| import { lazy } from 'solid-js'; | ||
| // src/solid/class-mount-impl.tsx | ||
| var _tmpl$ = ['<div style="', '">', "</div>"]; | ||
| function __mountComponent(el, theme, importFn) { | ||
| const Component = lazy(importFn); | ||
| const ThemeProvider = lazy(() => import('@tanstack/devtools-ui').then((m) => ({ | ||
| default: m.ThemeContextProvider | ||
| }))); | ||
| return render(() => createComponent(Portal, { | ||
| mount: el, | ||
| get children() { | ||
| return ssr(_tmpl$, ssrStyleProperty("height:", "100%"), escape(createComponent(ThemeProvider, { | ||
| theme, | ||
| get children() { | ||
| return createComponent(Component, {}); | ||
| } | ||
| }))); | ||
| } | ||
| }), el); | ||
| } | ||
| export { __mountComponent }; |
| import { render, createComponent, Portal, insert, template } from 'solid-js/web'; | ||
| import { lazy } from 'solid-js'; | ||
| // src/solid/class-mount-impl.tsx | ||
| var _tmpl$ = /* @__PURE__ */ template(`<div style=height:100%>`); | ||
| function __mountComponent(el, theme, importFn) { | ||
| const Component = lazy(importFn); | ||
| const ThemeProvider = lazy(() => import('@tanstack/devtools-ui').then((m) => ({ | ||
| default: m.ThemeContextProvider | ||
| }))); | ||
| return render(() => createComponent(Portal, { | ||
| mount: el, | ||
| get children() { | ||
| var _el$ = _tmpl$(); | ||
| insert(_el$, createComponent(ThemeProvider, { | ||
| theme, | ||
| get children() { | ||
| return createComponent(Component, {}); | ||
| } | ||
| })); | ||
| return _el$; | ||
| } | ||
| }), el); | ||
| } | ||
| export { __mountComponent }; |
| export { __mountComponent } from '../chunk/UX5ZZ4MG.js'; |
| export { __mountComponent } from '../chunk/ZXPCWXRH.js'; |
| /** @jsxImportSource solid-js - we use Solid.js as JSX here */ | ||
| import { lazy } from 'solid-js' | ||
| import { Portal, render } from 'solid-js/web' | ||
| import type { JSX } from 'solid-js' | ||
| export function __mountComponent( | ||
| el: HTMLElement, | ||
| theme: 'light' | 'dark', | ||
| importFn: () => Promise<{ default: () => JSX.Element }>, | ||
| ): () => void { | ||
| const Component = lazy(importFn) | ||
| const ThemeProvider = lazy(() => | ||
| import('@tanstack/devtools-ui').then((m) => ({ | ||
| default: m.ThemeContextProvider, | ||
| })), | ||
| ) | ||
| return render( | ||
| () => ( | ||
| <Portal mount={el}> | ||
| <div style={{ height: '100%' }}> | ||
| <ThemeProvider theme={theme}> | ||
| <Component /> | ||
| </ThemeProvider> | ||
| </div> | ||
| </Portal> | ||
| ), | ||
| el, | ||
| ) | ||
| } |
| import type { JSX } from 'solid-js' | ||
| /** | ||
| * Constructs the core class for the Devtools. | ||
| * This utility is used to construct a lazy loaded Solid component for the Devtools. | ||
| * It returns a tuple containing the main DevtoolsCore class and a NoOpDevtoolsCore class. | ||
| * The NoOpDevtoolsCore class is a no-op implementation that can be used for production if you want to explicitly exclude | ||
| * the Devtools from your application. | ||
| * @param importFn A function that returns a dynamic import of the Solid component | ||
| * @returns Tuple containing the DevtoolsCore class and a NoOpDevtoolsCore class | ||
| */ | ||
| export function constructCoreClass( | ||
| importFn: () => Promise<{ default: () => JSX.Element }>, | ||
| ) { | ||
| class DevtoolsCore { | ||
| #isMounted = false | ||
| #isMounting = false | ||
| #abortMount = false | ||
| #dispose?: () => void | ||
| constructor() {} | ||
| async mount<T extends HTMLElement>(el: T, theme: 'light' | 'dark') { | ||
| if (this.#isMounted || this.#isMounting) { | ||
| throw new Error('Devtools is already mounted') | ||
| } | ||
| this.#isMounting = true | ||
| this.#abortMount = false | ||
| try { | ||
| const { __mountComponent } = await import('./class-mount-impl') | ||
| // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- can be set by unmount() during await | ||
| if (this.#abortMount) { | ||
| this.#isMounting = false | ||
| return | ||
| } | ||
| this.#dispose = __mountComponent(el, theme, importFn) | ||
| this.#isMounted = true | ||
| this.#isMounting = false | ||
| } catch (err) { | ||
| this.#isMounting = false | ||
| console.error('[TanStack Devtools] Failed to load:', err) | ||
| } | ||
| } | ||
| unmount() { | ||
| if (!this.#isMounted && !this.#isMounting) { | ||
| throw new Error('Devtools is not mounted') | ||
| } | ||
| if (this.#isMounting) { | ||
| this.#abortMount = true | ||
| this.#isMounting = false | ||
| return | ||
| } | ||
| this.#dispose?.() | ||
| this.#isMounted = false | ||
| } | ||
| } | ||
| class NoOpDevtoolsCore extends DevtoolsCore { | ||
| constructor() { | ||
| super() | ||
| } | ||
| async mount<T extends HTMLElement>(_el: T, _theme: 'light' | 'dark') {} | ||
| unmount() {} | ||
| } | ||
| return [DevtoolsCore, NoOpDevtoolsCore] as const | ||
| } | ||
| export type ClassType = ReturnType<typeof constructCoreClass>[0] |
+24
-50
@@ -1,56 +0,32 @@ | ||
| import { createComponent, insert, use, template } from 'solid-js/web'; | ||
| export { __mountComponent } from './chunk/ZXPCWXRH.js'; | ||
| import { use, createComponent, template } from 'solid-js/web'; | ||
| import { createSignal, onMount, onCleanup } from 'solid-js'; | ||
| // src/solid/class.tsx | ||
| var _tmpl$ = /* @__PURE__ */ template(`<div style=height:100%>`); | ||
| function constructCoreClass(Component) { | ||
| // src/solid/class.ts | ||
| function constructCoreClass(importFn) { | ||
| class DevtoolsCore { | ||
| #isMounted = false; | ||
| #isMounting = false; | ||
| #mountCb = null; | ||
| #abortMount = false; | ||
| #dispose; | ||
| #Component; | ||
| #ThemeProvider; | ||
| constructor() { | ||
| } | ||
| async mount(el, theme) { | ||
| this.#isMounting = true; | ||
| const { | ||
| lazy | ||
| } = await import('solid-js'); | ||
| const { | ||
| render, | ||
| Portal | ||
| } = await import('solid-js/web'); | ||
| if (this.#isMounted) { | ||
| if (this.#isMounted || this.#isMounting) { | ||
| throw new Error("Devtools is already mounted"); | ||
| } | ||
| const mountTo = el; | ||
| const dispose = render(() => { | ||
| this.#Component = Component; | ||
| this.#ThemeProvider = lazy(() => import('@tanstack/devtools-ui').then((mod) => ({ | ||
| default: mod.ThemeContextProvider | ||
| }))); | ||
| const Devtools = this.#Component; | ||
| const ThemeProvider = this.#ThemeProvider; | ||
| return createComponent(Portal, { | ||
| mount: mountTo, | ||
| get children() { | ||
| var _el$ = _tmpl$(); | ||
| insert(_el$, createComponent(ThemeProvider, { | ||
| theme, | ||
| get children() { | ||
| return createComponent(Devtools, {}); | ||
| } | ||
| })); | ||
| return _el$; | ||
| } | ||
| }); | ||
| }, mountTo); | ||
| this.#isMounted = true; | ||
| this.#isMounting = false; | ||
| this.#dispose = dispose; | ||
| if (this.#mountCb) { | ||
| this.#mountCb(); | ||
| this.#mountCb = null; | ||
| this.#isMounting = true; | ||
| this.#abortMount = false; | ||
| try { | ||
| const { __mountComponent: __mountComponent2 } = await import('./class-mount-impl/ZAIAXV4M.js'); | ||
| if (this.#abortMount) { | ||
| this.#isMounting = false; | ||
| return; | ||
| } | ||
| this.#dispose = __mountComponent2(el, theme, importFn); | ||
| this.#isMounted = true; | ||
| this.#isMounting = false; | ||
| } catch (err) { | ||
| this.#isMounting = false; | ||
| console.error("[TanStack Devtools] Failed to load:", err); | ||
| } | ||
@@ -63,6 +39,4 @@ } | ||
| if (this.#isMounting) { | ||
| this.#mountCb = () => { | ||
| this.#dispose?.(); | ||
| this.#isMounted = false; | ||
| }; | ||
| this.#abortMount = true; | ||
| this.#isMounting = false; | ||
| return; | ||
@@ -85,3 +59,3 @@ } | ||
| } | ||
| var _tmpl$2 = /* @__PURE__ */ template(`<div style=height:100%>`); | ||
| var _tmpl$ = /* @__PURE__ */ template(`<div style=height:100%>`); | ||
| function createSolidPanel(CoreClass) { | ||
@@ -100,3 +74,3 @@ function Panel(props) { | ||
| return (() => { | ||
| var _el$ = _tmpl$2(); | ||
| var _el$ = _tmpl$(); | ||
| var _ref$ = devToolRef; | ||
@@ -103,0 +77,0 @@ typeof _ref$ === "function" ? use(_ref$, _el$) : devToolRef = _el$; |
| import * as solid_js from 'solid-js'; | ||
| import { JSX } from 'solid-js'; | ||
| /** @jsxImportSource solid-js - we use Solid.js as JSX here */ | ||
| /** | ||
@@ -12,13 +10,13 @@ * Constructs the core class for the Devtools. | ||
| * the Devtools from your application. | ||
| * @param importPath The path to the Solid component to be lazily imported | ||
| * @param importFn A function that returns a dynamic import of the Solid component | ||
| * @returns Tuple containing the DevtoolsCore class and a NoOpDevtoolsCore class | ||
| */ | ||
| declare function constructCoreClass(Component: () => JSX.Element): readonly [{ | ||
| declare function constructCoreClass(importFn: () => Promise<{ | ||
| default: () => JSX.Element; | ||
| }>): readonly [{ | ||
| new (): { | ||
| "__#private@#isMounted": boolean; | ||
| "__#private@#isMounting": boolean; | ||
| "__#private@#mountCb": (() => void) | null; | ||
| "__#private@#abortMount": boolean; | ||
| "__#private@#dispose"?: () => void; | ||
| "__#private@#Component": any; | ||
| "__#private@#ThemeProvider": any; | ||
| mount<T extends HTMLElement>(el: T, theme: "light" | "dark"): Promise<void>; | ||
@@ -33,6 +31,4 @@ unmount(): void; | ||
| "__#private@#isMounting": boolean; | ||
| "__#private@#mountCb": (() => void) | null; | ||
| "__#private@#abortMount": boolean; | ||
| "__#private@#dispose"?: () => void; | ||
| "__#private@#Component": any; | ||
| "__#private@#ThemeProvider": any; | ||
| }; | ||
@@ -66,2 +62,8 @@ }]; | ||
| export { type ClassType, type DevtoolsPanelProps, constructCoreClass, createSolidPanel, createSolidPlugin }; | ||
| /** @jsxImportSource solid-js - we use Solid.js as JSX here */ | ||
| declare function __mountComponent(el: HTMLElement, theme: 'light' | 'dark', importFn: () => Promise<{ | ||
| default: () => JSX.Element; | ||
| }>): () => void; | ||
| export { type ClassType, type DevtoolsPanelProps, __mountComponent, constructCoreClass, createSolidPanel, createSolidPlugin }; |
+24
-50
@@ -1,56 +0,32 @@ | ||
| import { createComponent, insert, use, template } from 'solid-js/web'; | ||
| export { __mountComponent } from './chunk/ZXPCWXRH.js'; | ||
| import { use, createComponent, template } from 'solid-js/web'; | ||
| import { createSignal, onMount, onCleanup } from 'solid-js'; | ||
| // src/solid/class.tsx | ||
| var _tmpl$ = /* @__PURE__ */ template(`<div style=height:100%>`); | ||
| function constructCoreClass(Component) { | ||
| // src/solid/class.ts | ||
| function constructCoreClass(importFn) { | ||
| class DevtoolsCore { | ||
| #isMounted = false; | ||
| #isMounting = false; | ||
| #mountCb = null; | ||
| #abortMount = false; | ||
| #dispose; | ||
| #Component; | ||
| #ThemeProvider; | ||
| constructor() { | ||
| } | ||
| async mount(el, theme) { | ||
| this.#isMounting = true; | ||
| const { | ||
| lazy | ||
| } = await import('solid-js'); | ||
| const { | ||
| render, | ||
| Portal | ||
| } = await import('solid-js/web'); | ||
| if (this.#isMounted) { | ||
| if (this.#isMounted || this.#isMounting) { | ||
| throw new Error("Devtools is already mounted"); | ||
| } | ||
| const mountTo = el; | ||
| const dispose = render(() => { | ||
| this.#Component = Component; | ||
| this.#ThemeProvider = lazy(() => import('@tanstack/devtools-ui').then((mod) => ({ | ||
| default: mod.ThemeContextProvider | ||
| }))); | ||
| const Devtools = this.#Component; | ||
| const ThemeProvider = this.#ThemeProvider; | ||
| return createComponent(Portal, { | ||
| mount: mountTo, | ||
| get children() { | ||
| var _el$ = _tmpl$(); | ||
| insert(_el$, createComponent(ThemeProvider, { | ||
| theme, | ||
| get children() { | ||
| return createComponent(Devtools, {}); | ||
| } | ||
| })); | ||
| return _el$; | ||
| } | ||
| }); | ||
| }, mountTo); | ||
| this.#isMounted = true; | ||
| this.#isMounting = false; | ||
| this.#dispose = dispose; | ||
| if (this.#mountCb) { | ||
| this.#mountCb(); | ||
| this.#mountCb = null; | ||
| this.#isMounting = true; | ||
| this.#abortMount = false; | ||
| try { | ||
| const { __mountComponent: __mountComponent2 } = await import('./class-mount-impl/ZAIAXV4M.js'); | ||
| if (this.#abortMount) { | ||
| this.#isMounting = false; | ||
| return; | ||
| } | ||
| this.#dispose = __mountComponent2(el, theme, importFn); | ||
| this.#isMounted = true; | ||
| this.#isMounting = false; | ||
| } catch (err) { | ||
| this.#isMounting = false; | ||
| console.error("[TanStack Devtools] Failed to load:", err); | ||
| } | ||
@@ -63,6 +39,4 @@ } | ||
| if (this.#isMounting) { | ||
| this.#mountCb = () => { | ||
| this.#dispose?.(); | ||
| this.#isMounted = false; | ||
| }; | ||
| this.#abortMount = true; | ||
| this.#isMounting = false; | ||
| return; | ||
@@ -85,3 +59,3 @@ } | ||
| } | ||
| var _tmpl$2 = /* @__PURE__ */ template(`<div style=height:100%>`); | ||
| var _tmpl$ = /* @__PURE__ */ template(`<div style=height:100%>`); | ||
| function createSolidPanel(CoreClass) { | ||
@@ -100,3 +74,3 @@ function Panel(props) { | ||
| return (() => { | ||
| var _el$ = _tmpl$2(); | ||
| var _el$ = _tmpl$(); | ||
| var _ref$ = devToolRef; | ||
@@ -103,0 +77,0 @@ typeof _ref$ === "function" ? use(_ref$, _el$) : devToolRef = _el$; |
+24
-48
@@ -1,54 +0,32 @@ | ||
| import { createComponent, ssr, ssrStyleProperty, escape } from 'solid-js/web'; | ||
| export { __mountComponent } from './chunk/UX5ZZ4MG.js'; | ||
| import { ssr, ssrStyleProperty, createComponent } from 'solid-js/web'; | ||
| import { createSignal, onMount, onCleanup } from 'solid-js'; | ||
| // src/solid/class.tsx | ||
| var _tmpl$ = ['<div style="', '">', "</div>"]; | ||
| function constructCoreClass(Component) { | ||
| // src/solid/class.ts | ||
| function constructCoreClass(importFn) { | ||
| class DevtoolsCore { | ||
| #isMounted = false; | ||
| #isMounting = false; | ||
| #mountCb = null; | ||
| #abortMount = false; | ||
| #dispose; | ||
| #Component; | ||
| #ThemeProvider; | ||
| constructor() { | ||
| } | ||
| async mount(el, theme) { | ||
| this.#isMounting = true; | ||
| const { | ||
| lazy | ||
| } = await import('solid-js'); | ||
| const { | ||
| render, | ||
| Portal | ||
| } = await import('solid-js/web'); | ||
| if (this.#isMounted) { | ||
| if (this.#isMounted || this.#isMounting) { | ||
| throw new Error("Devtools is already mounted"); | ||
| } | ||
| const mountTo = el; | ||
| const dispose = render(() => { | ||
| this.#Component = Component; | ||
| this.#ThemeProvider = lazy(() => import('@tanstack/devtools-ui').then((mod) => ({ | ||
| default: mod.ThemeContextProvider | ||
| }))); | ||
| const Devtools = this.#Component; | ||
| const ThemeProvider = this.#ThemeProvider; | ||
| return createComponent(Portal, { | ||
| mount: mountTo, | ||
| get children() { | ||
| return ssr(_tmpl$, ssrStyleProperty("height:", "100%"), escape(createComponent(ThemeProvider, { | ||
| theme, | ||
| get children() { | ||
| return createComponent(Devtools, {}); | ||
| } | ||
| }))); | ||
| } | ||
| }); | ||
| }, mountTo); | ||
| this.#isMounted = true; | ||
| this.#isMounting = false; | ||
| this.#dispose = dispose; | ||
| if (this.#mountCb) { | ||
| this.#mountCb(); | ||
| this.#mountCb = null; | ||
| this.#isMounting = true; | ||
| this.#abortMount = false; | ||
| try { | ||
| const { __mountComponent: __mountComponent2 } = await import('./class-mount-impl/LK7V47IP.js'); | ||
| if (this.#abortMount) { | ||
| this.#isMounting = false; | ||
| return; | ||
| } | ||
| this.#dispose = __mountComponent2(el, theme, importFn); | ||
| this.#isMounted = true; | ||
| this.#isMounting = false; | ||
| } catch (err) { | ||
| this.#isMounting = false; | ||
| console.error("[TanStack Devtools] Failed to load:", err); | ||
| } | ||
@@ -61,6 +39,4 @@ } | ||
| if (this.#isMounting) { | ||
| this.#mountCb = () => { | ||
| this.#dispose?.(); | ||
| this.#isMounted = false; | ||
| }; | ||
| this.#abortMount = true; | ||
| this.#isMounting = false; | ||
| return; | ||
@@ -83,3 +59,3 @@ } | ||
| } | ||
| var _tmpl$2 = ['<div style="', '"></div>']; | ||
| var _tmpl$ = ['<div style="', '"></div>']; | ||
| function createSolidPanel(CoreClass) { | ||
@@ -93,3 +69,3 @@ function Panel(props) { | ||
| }); | ||
| return ssr(_tmpl$2, ssrStyleProperty("height:", "100%")); | ||
| return ssr(_tmpl$, ssrStyleProperty("height:", "100%")); | ||
| } | ||
@@ -96,0 +72,0 @@ function NoOpPanel(_props) { |
+12
-2
| { | ||
| "name": "@tanstack/devtools-utils", | ||
| "version": "0.3.1", | ||
| "version": "0.3.2", | ||
| "description": "TanStack Devtools utilities for creating your own devtools.", | ||
@@ -35,2 +35,6 @@ "author": "Tanner Linsley", | ||
| "./solid": { | ||
| "workerd": { | ||
| "types": "./dist/solid/esm/index.d.ts", | ||
| "import": "./dist/solid/esm/server.js" | ||
| }, | ||
| "browser": { | ||
@@ -51,2 +55,8 @@ "development": { | ||
| }, | ||
| "./solid/class": { | ||
| "import": { | ||
| "types": "./dist/solid-class/esm/class.d.ts", | ||
| "default": "./dist/solid-class/esm/class.js" | ||
| } | ||
| }, | ||
| "./vue": { | ||
@@ -108,4 +118,4 @@ "import": { | ||
| "test:build": "publint --strict", | ||
| "build": "vite build && vite build --config vite.config.preact.ts && vite build --config vite.config.vue.ts && tsup " | ||
| "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" | ||
| } | ||
| } |
+44
-54
@@ -5,22 +5,11 @@ /** @jsxImportSource solid-js - we use Solid.js as JSX here */ | ||
| const lazyImportMock = vi.fn((fn) => fn()) | ||
| const renderMock = vi.fn() | ||
| const portalMock = vi.fn((props: any) => <div>{props.children}</div>) | ||
| const disposeMock = vi.fn() | ||
| const mountComponentMock = vi.fn(() => disposeMock) | ||
| vi.mock('solid-js', async () => { | ||
| const actual = await vi.importActual<any>('solid-js') | ||
| return { | ||
| ...actual, | ||
| lazy: lazyImportMock, | ||
| } | ||
| }) | ||
| vi.mock('./class-mount-impl', () => ({ | ||
| __mountComponent: mountComponentMock, | ||
| })) | ||
| vi.mock('solid-js/web', async () => { | ||
| const actual = await vi.importActual<any>('solid-js/web') | ||
| return { | ||
| ...actual, | ||
| render: renderMock, | ||
| Portal: portalMock, | ||
| } | ||
| }) | ||
| const importFn = () => | ||
| Promise.resolve({ default: () => <div>Test Component</div> }) | ||
@@ -31,24 +20,20 @@ describe('constructCoreClass', () => { | ||
| }) | ||
| it('should export DevtoolsCore and NoOpDevtoolsCore classes and make no calls to Solid.js primitives', () => { | ||
| const [DevtoolsCore, NoOpDevtoolsCore] = constructCoreClass(() => ( | ||
| <div>Test Component</div> | ||
| )) | ||
| const [DevtoolsCore, NoOpDevtoolsCore] = constructCoreClass(importFn) | ||
| expect(DevtoolsCore).toBeDefined() | ||
| expect(NoOpDevtoolsCore).toBeDefined() | ||
| expect(lazyImportMock).not.toHaveBeenCalled() | ||
| expect(mountComponentMock).not.toHaveBeenCalled() | ||
| }) | ||
| it('DevtoolsCore should call solid primitives when mount is called', async () => { | ||
| const [DevtoolsCore, _] = constructCoreClass(() => ( | ||
| <div>Test Component</div> | ||
| )) | ||
| it('DevtoolsCore should call __mountComponent when mount is called', async () => { | ||
| const [DevtoolsCore] = constructCoreClass(importFn) | ||
| const instance = new DevtoolsCore() | ||
| await instance.mount(document.createElement('div'), 'dark') | ||
| expect(renderMock).toHaveBeenCalled() | ||
| const el = document.createElement('div') | ||
| await instance.mount(el, 'dark') | ||
| expect(mountComponentMock).toHaveBeenCalledWith(el, 'dark', importFn) | ||
| }) | ||
| it('DevtoolsCore should throw if mount is called twice without unmounting', async () => { | ||
| const [DevtoolsCore, _] = constructCoreClass(() => ( | ||
| <div>Test Component</div> | ||
| )) | ||
| const [DevtoolsCore] = constructCoreClass(importFn) | ||
| const instance = new DevtoolsCore() | ||
@@ -62,5 +47,3 @@ await instance.mount(document.createElement('div'), 'dark') | ||
| it('DevtoolsCore should throw if unmount is called before mount', () => { | ||
| const [DevtoolsCore, _] = constructCoreClass(() => ( | ||
| <div>Test Component</div> | ||
| )) | ||
| const [DevtoolsCore] = constructCoreClass(importFn) | ||
| const instance = new DevtoolsCore() | ||
@@ -71,5 +54,3 @@ expect(() => instance.unmount()).toThrow('Devtools is not mounted') | ||
| it('DevtoolsCore should allow mount after unmount', async () => { | ||
| const [DevtoolsCore, _] = constructCoreClass(() => ( | ||
| <div>Test Component</div> | ||
| )) | ||
| const [DevtoolsCore] = constructCoreClass(importFn) | ||
| const instance = new DevtoolsCore() | ||
@@ -83,18 +64,31 @@ await instance.mount(document.createElement('div'), 'dark') | ||
| it('NoOpDevtoolsCore should not call any solid primitives when mount is called', async () => { | ||
| const [_, NoOpDevtoolsCore] = constructCoreClass(() => ( | ||
| <div>Test Component</div> | ||
| )) | ||
| it('DevtoolsCore should call dispose on unmount', async () => { | ||
| const [DevtoolsCore] = constructCoreClass(importFn) | ||
| const instance = new DevtoolsCore() | ||
| await instance.mount(document.createElement('div'), 'dark') | ||
| instance.unmount() | ||
| expect(disposeMock).toHaveBeenCalled() | ||
| }) | ||
| it('DevtoolsCore should abort mount if unmount is called during mounting', async () => { | ||
| const [DevtoolsCore] = constructCoreClass(importFn) | ||
| const instance = new DevtoolsCore() | ||
| const mountPromise = instance.mount(document.createElement('div'), 'dark') | ||
| // Unmount while mount is in progress — triggers abort path | ||
| // Note: since the mock resolves immediately, this tests the #abortMount flag | ||
| await mountPromise | ||
| // Mount completed, so unmount should work normally | ||
| instance.unmount() | ||
| expect(disposeMock).toHaveBeenCalled() | ||
| }) | ||
| it('NoOpDevtoolsCore should not call __mountComponent when mount is called', async () => { | ||
| const [, NoOpDevtoolsCore] = constructCoreClass(importFn) | ||
| const noOpInstance = new NoOpDevtoolsCore() | ||
| await noOpInstance.mount(document.createElement('div'), 'dark') | ||
| expect(lazyImportMock).not.toHaveBeenCalled() | ||
| expect(renderMock).not.toHaveBeenCalled() | ||
| expect(portalMock).not.toHaveBeenCalled() | ||
| expect(mountComponentMock).not.toHaveBeenCalled() | ||
| }) | ||
| it('NoOpDevtoolsCore should not throw if mount is called multiple times', async () => { | ||
| const [_, NoOpDevtoolsCore] = constructCoreClass(() => ( | ||
| <div>Test Component</div> | ||
| )) | ||
| const [, NoOpDevtoolsCore] = constructCoreClass(importFn) | ||
| const noOpInstance = new NoOpDevtoolsCore() | ||
@@ -108,5 +102,3 @@ await noOpInstance.mount(document.createElement('div'), 'dark') | ||
| it('NoOpDevtoolsCore should not throw if unmount is called before mount', () => { | ||
| const [_, NoOpDevtoolsCore] = constructCoreClass(() => ( | ||
| <div>Test Component</div> | ||
| )) | ||
| const [, NoOpDevtoolsCore] = constructCoreClass(importFn) | ||
| const noOpInstance = new NoOpDevtoolsCore() | ||
@@ -117,5 +109,3 @@ expect(() => noOpInstance.unmount()).not.toThrow() | ||
| it('NoOpDevtoolsCore should not throw if unmount is called after mount', async () => { | ||
| const [_, NoOpDevtoolsCore] = constructCoreClass(() => ( | ||
| <div>Test Component</div> | ||
| )) | ||
| const [, NoOpDevtoolsCore] = constructCoreClass(importFn) | ||
| const noOpInstance = new NoOpDevtoolsCore() | ||
@@ -122,0 +112,0 @@ await noOpInstance.mount(document.createElement('div'), 'dark') |
| export * from './class' | ||
| export * from './panel' | ||
| export * from './plugin' | ||
| export { __mountComponent } from './class-mount-impl' |
| /** @jsxImportSource solid-js - we use Solid.js as JSX here */ | ||
| import type { JSX } from 'solid-js' | ||
| /** | ||
| * Constructs the core class for the Devtools. | ||
| * This utility is used to construct a lazy loaded Solid component for the Devtools. | ||
| * It returns a tuple containing the main DevtoolsCore class and a NoOpDevtoolsCore class. | ||
| * The NoOpDevtoolsCore class is a no-op implementation that can be used for production if you want to explicitly exclude | ||
| * the Devtools from your application. | ||
| * @param importPath The path to the Solid component to be lazily imported | ||
| * @returns Tuple containing the DevtoolsCore class and a NoOpDevtoolsCore class | ||
| */ | ||
| export function constructCoreClass(Component: () => JSX.Element) { | ||
| class DevtoolsCore { | ||
| #isMounted = false | ||
| #isMounting = false | ||
| #mountCb: (() => void) | null = null | ||
| #dispose?: () => void | ||
| #Component: any | ||
| #ThemeProvider: any | ||
| constructor() {} | ||
| async mount<T extends HTMLElement>(el: T, theme: 'light' | 'dark') { | ||
| this.#isMounting = true | ||
| const { lazy } = await import('solid-js') | ||
| const { render, Portal } = await import('solid-js/web') | ||
| if (this.#isMounted) { | ||
| throw new Error('Devtools is already mounted') | ||
| } | ||
| const mountTo = el | ||
| const dispose = render(() => { | ||
| this.#Component = Component | ||
| this.#ThemeProvider = lazy(() => | ||
| import('@tanstack/devtools-ui').then((mod) => ({ | ||
| default: mod.ThemeContextProvider, | ||
| })), | ||
| ) | ||
| const Devtools = this.#Component | ||
| const ThemeProvider = this.#ThemeProvider | ||
| return ( | ||
| <Portal mount={mountTo}> | ||
| <div style={{ height: '100%' }}> | ||
| <ThemeProvider theme={theme}> | ||
| <Devtools /> | ||
| </ThemeProvider> | ||
| </div> | ||
| </Portal> | ||
| ) | ||
| }, mountTo) | ||
| this.#isMounted = true | ||
| this.#isMounting = false | ||
| this.#dispose = dispose | ||
| if (this.#mountCb) { | ||
| this.#mountCb() | ||
| this.#mountCb = null | ||
| } | ||
| } | ||
| unmount() { | ||
| if (!this.#isMounted && !this.#isMounting) { | ||
| throw new Error('Devtools is not mounted') | ||
| } | ||
| if (this.#isMounting) { | ||
| this.#mountCb = () => { | ||
| this.#dispose?.() | ||
| this.#isMounted = false | ||
| } | ||
| return | ||
| } | ||
| this.#dispose?.() | ||
| this.#isMounted = false | ||
| } | ||
| } | ||
| class NoOpDevtoolsCore extends DevtoolsCore { | ||
| constructor() { | ||
| super() | ||
| } | ||
| async mount<T extends HTMLElement>(_el: T, _theme: 'light' | 'dark') {} | ||
| unmount() {} | ||
| } | ||
| return [DevtoolsCore, NoOpDevtoolsCore] as const | ||
| } | ||
| export type ClassType = ReturnType<typeof constructCoreClass>[0] |
63139
20.09%63
31.25%1363
9.57%