Thank you for being patient! We're working hard on resolving the issue
Plugins control how rows render in the sheet. Each row type has a plugin that decides what cells look like, what legends to show, and how to respond to user gestures.
A plugin implements RenderPlugin and is registered by type name. When
the sheet renders a row, it looks up the plugin for that row's type and
delegates rendering to it.
Sheet renders row (type: "tasks")
→ PluginManager.getPlugin("tasks")
→ TaskPlugin.bindCell($cell, context)
Implement RenderPlugin with at minimum an id, icon, makeCell(),
and bindCell():
import type { RenderPlugin, BindCellContext } from "@tento-lona/sheets-ui";
export class TaskPlugin implements RenderPlugin<TaskCell, TaskLegend> {
readonly id = "tasks";
readonly icon = taskIconTemplate;
makeCell(): TaskCell {
return TaskCell.make();
}
bindCell($cell: TaskCell, context: BindCellContext): void {
const { row, column, handle } = context;
const tasks = this.getTasksForColumn(row, column);
$cell.bind(tasks);
}
onResize($cell: TaskCell, context: BindCellContext): void {
$cell.updateWidth(context.widthPx);
}
optionsInfo(): Option<string> {
return null;
}
onBindRow(): void {}
onViewportColumnsChanged(): void {}
onRenderedColumnsWillChange(): void {}
}
Register it in the plugin manager:
pluginManager.register("tasks", new TaskPlugin(events, sdk));
Every plugin method receives a SheetDelegate (via context.handle)
that provides access to the sheet's positioning APIs:
| Handle | Purpose | Coordinate system |
|---|---|---|
handle.popover | Scroll-aware popovers | Column + RowLocalId |
handle.fixedChild | Fixed overlays (ghosts, spans) | Column + RowLocalId |
handle.staticChild | Static positioned children | RowLocalId + pixel offset |
handle.tooltip | Tooltips | Column + RowLocalId |
These handles are what your plugin uses to show menus, tooltips, and overlays in response to user interaction.
Plugins can attach persistent elements to a row (event spans, indicators,
ghosts) via fixedChildrenForRow():
async fixedChildrenForRow(
row: SheetRow.Joined.Client,
context: FixedChildRowContext,
): Promise<SheetDelegate.FixedChildSpec[]> {
return [{
id: "task-progress-bar",
x: { type: "date-range", startDate, endDate },
inset: { left: 0, top: 0 },
widthBehavior: "fill",
makeElement: () => TaskProgressBar.make(),
}];
}
Plugins can declare async data dependencies. The sheet calls loadData()
before rendering and waits for the result:
async loadData(sheet, row, column) {
return this.store.fetchForRange(row.id, column.toDateRange());
}