UNPKG

@arminmajerie/dockview

Version:

Zero dependency layout manager supporting tabs, grids and splitviews (SolidJS only)

83 lines (82 loc) 2.74 kB
// packages/dockview/src/solid.tsx import { createSignal, createContext } from 'solid-js'; import { render } from 'solid-js/web'; // Context (use if you actually need context passing) export const SolidPartContext = createContext({}); // Main class export class SolidPart { parent; portalStore; component; parameters; context; _initialProps = {}; componentInstance; ref; disposed = false; constructor(parent, portalStore, component, parameters, context) { this.parent = parent; this.portalStore = portalStore; this.component = component; this.parameters = parameters; this.context = context; this.createPortal(); } update(props) { if (this.disposed) { throw new Error("invalid operation: resource is already disposed"); } if (!this.componentInstance) { this._initialProps = { ...this._initialProps, ...props }; } else { this.componentInstance.update(props); } } createPortal() { if (this.disposed) throw new Error("already disposed"); // The core logic: render the component into `parent` (like a Solid portal) // Optionally wrap with context let cleanup; const ComponentWithContext = () => this.context ? (<SolidPartContext.Provider value={this.context}> {this.component({ ...this.parameters, ...this._initialProps })} </SolidPartContext.Provider>) : this.component({ ...this.parameters, ...this._initialProps }); cleanup = render(ComponentWithContext, this.parent); // Save for disposal this.ref = this.portalStore.addPortal({ dispose: () => { cleanup?.(); this.disposed = true; }, }); } dispose() { this.ref?.dispose(); this.disposed = true; } } /** * A React Hook that returns an array of portals to be rendered by the user of this hook * and a disposable function to add a portal. Calling dispose removes this portal from the * portal array */ export const usePortalsLifecycle = () => { const [portals, setPortals] = createSignal([]); const addPortal = (cleanup) => { setPortals(existing => [...existing, cleanup]); let disposed = false; return { dispose() { if (disposed) throw new Error("invalid operation: resource already disposed"); disposed = true; setPortals(existing => existing.filter(p => p !== cleanup)); cleanup.dispose(); } }; }; return [portals, addPortal]; };