Import it from @grafloria/element.
The typed façade — the erTable/umlClass equivalent for dashboards.
tsinterface DashboardHandle
Properties
| Name | Type | Default | Description |
|---|---|---|---|
views | string[] | The view ids, in declaration order. | |
activeView | string | The currently shown view id. |
Members
showView(id: string): void— Show a view (the others park off-camera) and frame it.widget(id: string): WidgetHandle | undefined— A widget handle by id (undefined when unknown).focusWidget(id: string): boolean— SELECT a widget and move keyboard focus to it — what a press on the widget does. The selected widget shows its painted grip (dragHandle: { grip }) and a quiet ring; a void click clears. False when the id is unknown.selectWidget(id: string | undefined): boolean— SELECT a widget WITHOUT moving keyboard focus — the ring and the grip, nothing else; what a mouse press does.undefinedclears the selection on every view. False when the id is unknown.getSelectedWidget(): string | undefined— The selected widget, if any (across views: only the on-camera one can be).widgetsOf(viewId?: string): WidgetHandle[]— Every widget handle of a view (default: the active one).setLayout(layout: 'grid' | 'split', viewId?: string): void— Switch a view (default: the active one) between the cell grid and the split tree, live and keeping the picture: cells → tree by guillotine cuts, tree → cells by snapping to the columns. Persisted on the board, so a saved document reopens in the layout it was left in.getLayout(viewId?: string): 'grid' | 'split' | 'tabs'— A container built withlayout: 'tabs'reports 'tabs'; views never do.setCaption(id: string, caption: SectionCaption): boolean— Set a SECTION's caption live —falseremoves it,trueis the title, a string or the options. Repaints the band, gives the reserve back or takes it, persists on the section, one undo step. False for anything that is not a container.getCaption(id: string): SectionCaption | undefined— The caption as authored or last set; undefined when the section has none.activateTab(containerId: string, pageId: string): boolean— Show a PAGE of a tab container (layout: 'tabs'). False when the container or the page is not one. Persisted, so a saved board reopens on the page it was left on.getActiveTab(containerId: string): string | undefined— The page showing in a tab container.moveToTab(widgetId: string, containerId: string, index?: number): Promise<boolean>— Move a WIDGET intocontainerIdas a NEW TAB atindex(default: the end): the widget becomes the only member of a fresh page named by its title, and that page the active tab — what dropping a widget on a strip does. One undoable step; the board it left re-packs, and a page it emptied closes.moveTab(containerId: string, pageId: string, index: number): boolean— Reorder a page along its container's strip. One undoable step; the order is saved with the container.setSizing(mode: 'fit' | 'grow'): void— Live sizing/float switches — the two prototype toggles.getSizing(): 'fit' | 'grow'setFloat(on: boolean): voidgetFloat(): booleansetColumns(n: number, layout?: GridColumnLayout, viewId?: string): void— Set the COLUMN COUNT of every board (or one view), live. Goes through the engine's per-column layout cache, so shrinking then growing back restores the wide layout rather than re-deriving it. An explicit call PINS the count — the width-drivenresponsiveevaluator stops overriding it.getColumns(viewId?: string): number— The LIVE column count of a view (default: the active one).setRtl(on: boolean): void— RTL mirroring, live — pixels only, cells never change.getRtl(): booleansetStatic(on: boolean): void— Static (read-only for the pointer) mode, live — the viewer/designer switch.getStatic(): booleansetDragHandle(v: DragHandleOption): void— Drag-handle mode, live, every view:true= the caption strip, a selector = your own handle,{ grip: true, … }= a painted grip,false= the whole card.getDragHandle(): DragHandleOptionaddWidget(spec: DashboardWidgetSpec, viewId?: string, opts?: { displaced?: Command[] }): WidgetHandle | undefined— Add a widget to a view. CREATES the node (you do not pre-build one), wires its metadata, and commits node + membership as ONE undoable step. Auto-positions when the spec names no cell.opts.displaced: the commands a palette drop handedonDropInfor the tiles the placeholder pushed aside — folded into the same step, so the widget lands on the cell the drop showed and undo puts the pushed tiles back with it. Left out, the board is re-read from the model and the push is forgotten: the new widget then auto-positions into whatever hole is left (Quantia's "lands on the cell it was aimed at", element 0.4.54).refresh(): void— Re-read every board from the model — call after undo/redo, or any out-of-band mutation, so the grid and the projection agree again.fit(viewId?: string): void— Re-frame the camera on a view (default: the active one).metrics(viewId?: string): ReturnType<DashboardGridHandle['metrics']> | undefined— Live geometry of a view's board (columns, gap, rows, rowHeight, frame…).toJSON(): DashboardSnapshot— The whole board as plain data — feed it straight back todashboard():
tsdashboard({ ...handle.toJSON(), renderWidget }); // a true round trip
Everything DashboardOptions takes EXCEPT the function seams
(renderWidget, onLayoutChange), which cannot be written to a file and
must be supplied again on the way back in.
Values are read from the LIVE board, not from the authored literal, so a mode or column count the user changed after mount is what you get back.
This used to return only views, which made the round-trip claim true of
the layout and false of the board: a board authored grow at a 10-column,
6px-gap geometry reloaded as a 12-column fit one. It is also what
JSON.stringify(handle) calls, so the partial answer was a permanent
footgun in a save API rather than merely an omission.
exportIds(viewId?: string): Set<string>— The node ids ONE view occupies — pass straight toincludeIdsto export just that board:
tsapi.export('pdf', { includeIds: handle.exportIds() });
WHY THIS EXISTS. Tabs park the inactive views far off-camera, which is
invisible on screen and ruinous on export: export() frames the whole
MODEL, so a two-view board writes a ~21,000px document that is almost
entirely empty — with no warning, because nothing is technically wrong. Scoping was always possible; knowing WHAT to scope to was not.
The set includes the view's GROUP as well as its widgets. Rolling this by
hand from toJSON() looks equivalent and is not — it drops the group, and
the widgets export without the frame they sit in.
binderOf(viewId?: string): DashboardGridHandle | undefined— THE DOCUMENTED ESCAPE HATCH: the view's ownbindDashboardGridhandle (default: the active view). Reach for it only for what this façade does not cover yet — palette drag-in (beginPaletteDrag), boardmetrics(),cellRectOf,planRemoval, and re-sync()after an external undo. Every call site is a named gap in this API, not a normal way to drive a board.dispose(): void
Was this page helpful?