@arminmajerie/dockview
Version:
Zero dependency layout manager supporting tabs, grids and splitviews (SolidJS only)
83 lines (82 loc) • 2.74 kB
JSX
// 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];
};