@sheetwrite/core/adapterfunction
Create a grid and wire its lifecycle once, so the React/Vue/Svelte adapters (and any plain host) share a single, drift-free implementation instead of each re-deriving the same create → subscribe → teardown behavior.
initSheetwrite() MUST already have been awaited; createGrid throws
otherwise.
Live handlers
handlers is held by reference, not copied. Every event reads the
object's current fields (handlers.onGridChange?.(…)), so a host may swap
callbacks without rebuilding the grid. Framework adapters must mutate the
shared object only from their commit lifecycle; mutating it during render can
expose callbacks from work that never commits.
- Package
@sheetwrite/core/adapter- Source
packages/core/src/grid-controller.ts#L108
Declaration
function createGridController<Id extends RowBridgeIdtype RowBridgeId = string | number;type RowBridgeId = string | number;type RowBridgeId =
string | number;A stable host identity for one data-space row.API reference → = RowBridgeIdtype RowBridgeId = string | number;type RowBridgeId = string | number;type RowBridgeId =
string | number;A stable host identity for one data-space row.API reference →>( host: HTMLElement, options: GridOptionsinterface GridOptions {
workbook: Workbook;
data?: ColumnarData;
datasource?: DataSource;
datasourceStorage?: DataSourceStorageOptions;
renderer?: "canvas" | "worker";
workerUrl?: string | URL;
presentation?: GridPresentation;
theme?: Partial<Theme>;
readOnly?: boolean;
hyperlinkActivation?:
"event-only" | "internal-navigation" | "disabled";
protectionResolver?: ProtectionResolver;
mutationPolicy?: MutationPolicyMode;
transactionResourceLimits?: Partial<TransactionResourceLimits>;
// … 6 more lines — see the API reference
}interface GridOptions {
workbook: Workbook;
data?: ColumnarData;
datasource?: DataSource;
datasourceStorage?: DataSourceStorageOptions;
renderer?: "canvas" | "worker";
workerUrl?: string | URL;
presentation?: GridPresentation;
theme?: Partial<Theme>;
readOnly?: boolean;
hyperlinkActivation?:
"event-only" | "internal-navigation" | "disabled";
protectionResolver?: ProtectionResolver;
mutationPolicy?: MutationPolicyMode;
transactionResourceLimits?: Partial<TransactionResourceLimits>;
// … 6 more lines — see the API reference
}interface GridOptions {
workbook: Workbook;
data?: ColumnarData;
datasource?: DataSource;
datasourceStorage?: DataSourceStorageOptions;
renderer?: "canvas" | "worker";
workerUrl?: string | URL;
presentation?: GridPresentation;
theme?: Partial<Theme>;
readOnly?: boolean;
hyperlinkActivation?:
| "event-only"
| "internal-navigation"
| "disabled";
protectionResolver?: ProtectionResolver;
mutationPolicy?: MutationPolicyMode;
transactionResourceLimits?: Partial<TransactionResourceLimits>;
renderers?: Record<
string,
// … 10 more lines — see the API reference
}Workbook, data, rendering, policy, and built-in UI options used to create a Grid.API reference →, handlers: GridControllerHandlersinterface GridControllerHandlers<
Id extends RowBridgeId = RowBridgeId,
> {
onGridChange?(event: ChangeEvent): void;
onRowDelta?(
projection: Parameters<RowBridgeHandler<Id>>[0],
): void;
onSelectionChange?(selection: Selection | null): void;
onViewportChange?(event: GridEvents["scroll"]): void;
onEditBegin?(event: GridEvents["edit-begin"]): void;
onEditCommit?(event: GridEvents["edit-commit"]): void;
onSearch?(result: GridEvents["search"]): void;
onCommandStateChange?(
event: GridEvents["command-state-change"],
): void;
// … 6 more lines — see the API reference
}interface GridControllerHandlers<
Id extends RowBridgeId = RowBridgeId,
> {
onGridChange?(event: ChangeEvent): void;
onRowDelta?(
projection: Parameters<RowBridgeHandler<Id>>[0],
): void;
onSelectionChange?(selection: Selection | null): void;
onViewportChange?(event: GridEvents["scroll"]): void;
onEditBegin?(event: GridEvents["edit-begin"]): void;
onEditCommit?(event: GridEvents["edit-commit"]): void;
onSearch?(result: GridEvents["search"]): void;
onCommandStateChange?(
event: GridEvents["command-state-change"],
): void;
// … 6 more lines — see the API reference
}interface GridControllerHandlers<
Id extends RowBridgeId =
RowBridgeId,
> {
onGridChange?(
event: ChangeEvent,
): void;
onRowDelta?(
projection: Parameters<
RowBridgeHandler<Id>
>[0],
): void;
onSelectionChange?(
selection: Selection | null,
): void;
onViewportChange?(
event: GridEvents["scroll"],
): void;
onEditBegin?(
// … 27 more lines — see the API reference
}Event callbacks a host (a framework adapter, or any plain app) hangs off a grid's lifecycle. The controller reads these fields live on every event — see createGridController — so a host may swap any callback at any time by mutating the fields of the object it passed in, without recreating the grid. Every field is optional; a missing callback simply drops that event.API reference →<Id>, rowBridge?: RowBridgeclass RowBridge {
constructor<
Id extends RowBridgeId = RowBridgeId,
Row extends Record<string, CellScalar> = Record<
string,
CellScalar
>,
>(options: RowBridgeOptions<Row, Id>);
columnKeys: (sheet?: SheetId) => readonly string[];
project: (
event: ChangeEvent,
requestedOperations?: readonly DocumentOp[],
transactionId?: string,
) => RowBridgeProjection<Id>;
reconcile: (
// … 4 more lines — see the API reference
}class RowBridge {
constructor<
Id extends RowBridgeId = RowBridgeId,
Row extends Record<string, CellScalar> = Record<
string,
CellScalar
>,
>(options: RowBridgeOptions<Row, Id>);
columnKeys: (sheet?: SheetId) => readonly string[];
project: (
event: ChangeEvent,
requestedOperations?: readonly DocumentOp[],
transactionId?: string,
) => RowBridgeProjection<Id>;
reconcile: (
// … 4 more lines — see the API reference
}class RowBridge {
constructor<
Id extends RowBridgeId =
RowBridgeId,
Row extends Record<
string,
CellScalar
> = Record<
string,
CellScalar
>,
>(
options: RowBridgeOptions<
Row,
Id
>,
);
columnKeys: (
sheet?: SheetId,
// … 13 more lines — see the API reference
}Projects canonical document transactions into host-owned row changes. The bridge only owns compact data-space identity arrays. It never writes to defaultRows, never renders, and never creates a second document store.API reference →<Id>,): GridControllerinterface GridController {
readonly grid: Grid;
setTheme(theme: Partial<Theme> | undefined): void;
setReadOnly(readOnly: boolean): void;
setConfig(config: GridConfig | undefined): void;
setOverscan(overscan: number | undefined): void;
setMinColumns(minColumns: number | undefined): void;
destroy(): void;
}interface GridController {
readonly grid: Grid;
setTheme(theme: Partial<Theme> | undefined): void;
setReadOnly(readOnly: boolean): void;
setConfig(config: GridConfig | undefined): void;
setOverscan(overscan: number | undefined): void;
setMinColumns(minColumns: number | undefined): void;
destroy(): void;
}interface GridController {
readonly grid: Grid;
setTheme(
theme:
Partial<Theme> | undefined,
): void;
setReadOnly(
readOnly: boolean,
): void;
setConfig(
config:
GridConfig | undefined,
): void;
setOverscan(
overscan: number | undefined,
): void;
setMinColumns(
minColumns:
number | undefined,
// … 3 more lines — see the API reference
}The lifecycle handle returned by createGridController: the live grid, a theme passthrough, and a single teardown that detaches every subscription and destroys the grid.API reference →