### Get started with craftsmith CLI (bash) Source: https://docs.logisheets.com/craft/craft.html Scaffold, install, and validate a new craft using the `craftsmith` CLI. Run these commands in order: create the craft, install dependencies, validate the contract, and then build to compile to `dist/`. ```bash npx craftsmith new my-craft cd my-craft && npm install npx craftsmith check . # validate the contract npx craftsmith build . # compile → dist/ ``` -------------------------------- ### Install craftsmith and scaffold a project Source: https://docs.logisheets.com/craft/writing-a-craft.html Install the craftsmith CLI and scaffold a new craft project. Run these commands in order from your terminal. ```bash npm i -D logisheets-craftsmith # the CLI npx craftsmith new my-craft # scaffold a project cd my-craft && npm install ``` -------------------------------- ### WorkbookWatcher usage with start() and get() Source: https://docs.logisheets.com/runtime.html Creates a WorkbookWatcher that polls './watch' every 10 seconds, logs each loaded id, and starts polling. After starting, the current workbook for 'sales-2026' can be retrieved with get(). ```ts const runtime = new SpreadsheetRuntime() const watcher = new WorkbookWatcher(runtime, './watch', { intervalMs: 10_000, onLoad: (id) => console.log('loaded', id), }) watcher.start() // ... elsewhere, serve the current revision: const wb = watcher.get('sales-2026') ``` -------------------------------- ### Install logisheets-formula-editor Source: https://docs.logisheets.com/engine.html Install the companion package that provides the formula bar and in-cell editor. The engine itself does not ship these UI components. ```bash npm install logisheets-formula-editor ``` -------------------------------- ### Install logisheets-runtime with npm Source: https://docs.logisheets.com/runtime.html Install the logisheets-runtime package from npm to use the headless LogiSheets engine on Node. ```bash npm install logisheets-runtime ``` -------------------------------- ### Register methods with RpcServer Source: https://docs.logisheets.com/runtime.html Shows how to create a runtime and server, register methods that create workbooks and read cell values, and start listening on an ephemeral port. Handlers receive an RpcContext and can throw RpcError for structured errors. ```typescript const runtime = new SpreadsheetRuntime() const server = new RpcServer(runtime) server .register('newWorkbook', (_p, {runtime}) => ({id: runtime.createWorkbook().id})) .register('getCell', (p, {runtime}) => { const wb = runtime.workbooks.find((w) => w.id === p.id) if (!wb) throw new RpcError(RPC_INVALID_PARAMS, `no workbook ${p.id}`) return wb.getValue(0, p.row, p.col) }) const addr = await server.listen(0) // POST JSON-RPC 2.0 to http://127.0.0.1:${addr.port} ``` -------------------------------- ### Craft manifest example (schemaVersion, craftId, tools) Source: https://docs.logisheets.com/craft/writing-a-craft.html The manifest is a generated build artifact that the host reads to discover and drive your craft. Run `craftsmith check` in CI to guarantee it matches your code. The `url`, `rtJs`, and `tools` fields are present only when you have a UI, runtime, or tools respectively. ```jsonc { "schemaVersion": 1, "craftId": "my-craft", "version": "0.1.0", "label": "My Craft", "url": "index.html", // present iff you have a UI "rtJs": "runtime.js", // present iff you have a runtime "skill": { "description": "…", "guidance": "…" }, "tools": [ { "name": "write_cell", "description": "…", "inputSchema": { /* from your types */ }, "paramOrder": ["row","col","text"], "entry": "tools.js", "export": "writeCell", "mutates": true, "confirmation": "always" } ] } ``` -------------------------------- ### WorkbookWatcher descriptor files (wb_*.json) Source: https://docs.logisheets.com/runtime.html Two example descriptor files for the WorkbookWatcher. Each must include an id, version, and at least one of path or url; when both are present, path wins. Relative paths resolve against the watched directory. ```json {"id": "sales-2026", "version": 7, "path": "books/sales.xlsx"} {"id": "sales-2026", "version": 7, "url": "https://host/books/sales.xlsx"} ``` -------------------------------- ### Zoom control example using engine zoom API Source: https://docs.logisheets.com/engine.html Example of a zoom control in a toolbar: listens to 'zoomChange' to update a label, then calls zoomIn, setZoom(1.5), and resetZoom. ```typescript // A zoom control in your toolbar. engine.on('zoomChange', (z) => setLabel(`${Math.round(z * 100)}%`)) await engine.zoomIn() await engine.setZoom(1.5) await engine.resetZoom() ``` -------------------------------- ### Install logisheets-engine and logisheets-web via npm Source: https://docs.logisheets.com/introduction.html Install the required packages for embedding the LogiSheets spreadsheet UI in a web page. ```bash npm install logisheets-engine logisheets-web ``` -------------------------------- ### Subscribe to engine events (selectionChange, gridChange, startEdit, contextMenu) Source: https://docs.logisheets.com/engine.html Shows how to subscribe to engine events using on(). The payload types are determined by the event; for example, selectionChange provides SelectedData, gridChange provides Grid | null, startEdit provides {row, col, initialText}, and contextMenu provides {context, x, y}. ```TypeScript engine.on('selectionChange', (data) => setSelection(data)) engine.on('gridChange', (grid) => setGrid(grid)) engine.on('startEdit', ({row, col, initialText}) => openEditor(row, col, initialText)) engine.on('contextMenu', ({context, x, y}) => openMyMenu(context, x, y)) ``` -------------------------------- ### Quick start: create workbook, input cells, read evaluated values Source: https://docs.logisheets.com/runtime.html Create a runtime, create a workbook, input a value and a formula, read the evaluated result, change the input, and confirm the formula recalculates. Cells are 0-indexed as (sheetIdx, row, col): A1 = (0,0,0), B1 = (0,0,1). ```ts import {SpreadsheetRuntime} from 'logisheets-runtime' const runtime = new SpreadsheetRuntime() const wb = runtime.createWorkbook() await wb.ops.inputCell(0, 0, 0, '10') // A1 = 10 (value) await wb.ops.inputCell(0, 0, 1, '=A1*2') // B1 = =A1*2 (formula) wb.getValue(0, 0, 1) // → { type: 'number', value: 20 } await wb.ops.inputCell(0, 0, 0, '21') // change A1 wb.getValue(0, 0, 1) // → { type: 'number', value: 42 } (recalculated) runtime.closeAll() ``` -------------------------------- ### Insert rows and set column width (Rust and TypeScript) Source: https://docs.logisheets.com/usage.html Shows how to build a payload action in Rust and the equivalent transaction object in TypeScript for inserting rows and setting column width. The Rust example uses `PayloadsAction::new()` with `add_payload` calls; the TypeScript example sets `undoable: true` and `temp: false`. ```rust use logisheets_rs::{InsertRows, SetColWidth}; PayloadsAction::new() .add_payload(InsertRows { sheet_idx: 0, start: 2, count: 3 }) .add_payload(SetColWidth { sheet_idx: 0, col: 0, width: 120.0 }); ``` ```ts const tx = { payloads: [ {type: 'insertRows', value: {sheetIdx: 0, start: 2, count: 3}}, {type: 'setColWidth', value: {sheetIdx: 0, col: 0, width: 120}}, ], undoable: true, temp: false, } ``` -------------------------------- ### Initialize via UMD build without a bundler Source: https://docs.logisheets.com/engine.html Loads the style and UMD script from a script tag, wiring up a new engine from the LogiSheetsEngine global. Requires a container element; otherwise nothing is rendered. ```html ``` -------------------------------- ### Import Engine and mount as ES module (with bundler) Source: https://docs.logisheets.com/engine.html Creates an Engine instance, mounts it when ready. Must be used with a bundler that resolves imports and processes the CSS import. ```typescript import {Engine} from 'logisheets-engine' import 'logisheets-engine/style.css' const engine = new Engine() engine.on('ready', () => engine.mount(document.getElementById('app')!)) ``` -------------------------------- ### Create cellStyleUpdate payload with StyleUpdateType Source: https://docs.logisheets.com/usage.html Create a cellStyleUpdate payload. The Rust example uses StyleUpdateType::default() and sets optional fields; the TypeScript example uses StyleUpdateTypeBuilder and CellStyleUpdateBuilder. The resulting payload is a cellStyleUpdate when placed in a transaction. ```rust use logisheets_rs::{CellStyleUpdate}; // StyleUpdateType has the same optional fields as the TS shape above. let mut ty = logisheets_rs::StyleUpdateType::default(); ty.set_font_bold = Some(true); ty.set_font_color = Some("FFFF0000".to_string()); PayloadsAction::new() .add_payload(CellStyleUpdate { sheet_idx: 0, row: 0, col: 0, ty }); ``` ```ts import {CellStyleUpdateBuilder, StyleUpdateTypeBuilder} from 'logisheets-web' const ty = new StyleUpdateTypeBuilder() .setFontBold(true) .setFontColor('FFFF0000') .build() const payload = new CellStyleUpdateBuilder() .sheetIdx(0).row(0).col(0).ty(ty) .build() // -> { type: 'cellStyleUpdate', value: ... } when placed in a transaction ``` -------------------------------- ### new Engine(config?: Partial) Source: https://docs.logisheets.com/engine.html Creates the engine and its own Web Worker. Worker + WASM initialization happens asynchronously; wait for the `ready` event before use. ```APIDOC ## new Engine(config?: Partial) ### Description Creates the engine and its own Web Worker. Worker + WASM initialization happens asynchronously; wait for the `ready` event before use. ### Method constructor ### Endpoint new Engine(config?: Partial) ### Parameters #### Request Body - **config** (Partial) - Optional - Configuration object for the engine. All fields are optional; defaults come from `DEFAULT_ENGINE_CONFIG`. ### Response #### Success Response - **engine** (Engine) - The constructed Engine instance. ### Response Example ```ts const engine = new Engine() ``` ``` -------------------------------- ### Create transaction with cellInput and cellClear payloads Source: https://docs.logisheets.com/usage.html Create a transaction with cellInput and cellClear payloads. The Rust example uses PayloadsAction::new().add_payload; the TypeScript example shows the transaction object with payloads, undoable, and temp fields. content is always a string, even for numbers. ```rust use logisheets_rs::{CellInput, CellClear}; PayloadsAction::new() .add_payload(CellInput { sheet_idx: 0, row: 0, col: 0, content: "=SUM(B1:B9)".into() }) .add_payload(CellClear { sheet_idx: 0, row: 5, col: 0 }); ``` ```ts const tx = { payloads: [ {type: 'cellInput', value: {sheetIdx: 0, row: 0, col: 0, content: '=SUM(B1:B9)'}}, {type: 'cellClear', value: {sheetIdx: 0, row: 5, col: 0}}, ], undoable: true, temp: false, } ``` -------------------------------- ### Svelte integration with logisheets-engine Source: https://docs.logisheets.com/engine.html Svelte component that mounts the engine on mount and destroys it on unmount. Uses bind:this to get the host element and creates the engine once in the script. ```svelte
``` -------------------------------- ### Vue 3 integration with logisheets-engine Source: https://docs.logisheets.com/engine.html Vue 3 component that mounts the engine on mount and destroys it on unmount. Uses a template ref for the host element and creates the engine once in the setup scope. ```vue ``` -------------------------------- ### isReady(): boolean Source: https://docs.logisheets.com/engine.html Returns whether the worker + WASM finished initializing. ```APIDOC ## isReady(): boolean ### Description Returns whether the worker + WASM finished initializing. ### Method isReady ### Endpoint isReady(): boolean ### Parameters None ### Response #### Success Response - **boolean** (boolean) - `true` if the worker + WASM finished initializing, `false` otherwise. ### Response Example ```ts const ready = engine.isReady() ``` ``` -------------------------------- ### Inspecting sheets (Rust and TypeScript) Source: https://docs.logisheets.com/usage.html Inspect workbook sheets: get the sheet count, all sheet info, a sheet name by index, and retrieve a worksheet by index or by name (Rust) or by stable id (TypeScript). ```rust let count = wb.get_sheet_count(); let info = wb.get_all_sheet_info(); // Vec { id, idx, name, ... } let name = wb.get_sheet_name_by_idx(0)?; let ws = wb.get_sheet_by_idx(0)?; // by index let ws = wb.get_sheet_by_name("Sheet1")?; // by name ``` ```typescript const count = wb.getSheetCount() const info = wb.getAllSheetInfo() // SheetInfo[] { id, idx, name, ... } const name = wb.getSheetNameByIdx(0) const ws = wb.getWorksheet(0) // by index const ws = wb.getWorksheetById(sheetId) // by stable id ``` -------------------------------- ### Creating or loading a workbook (Rust and TypeScript) Source: https://docs.logisheets.com/usage.html Create an empty workbook or load one from .xlsx bytes. In Rust, use Workbook::new() or Workbook::from_file(&bytes, "example.xlsx"). In TypeScript, construction is synchronous because WASM is bundled; use wb.load(new Uint8Array(bytes), 'example.xlsx') after fetching the file. ```rust use logisheets_rs::Workbook; // Empty workbook (starts with one sheet) let mut wb = Workbook::new(); // Or load from .xlsx bytes let bytes = std::fs::read("example.xlsx")?; let mut wb = Workbook::from_file(&bytes, "example.xlsx".to_string())?; ``` ```typescript import {Workbook} from 'logisheets-web' // or 'logisheets' in Node // Empty workbook — WASM is bundled, so construction is synchronous const wb = new Workbook() // Or load from .xlsx bytes (Uint8Array) const bytes = await fetch('/example.xlsx').then(r => r.arrayBuffer()) wb.load(new Uint8Array(bytes), 'example.xlsx') ``` -------------------------------- ### package.json identity fields Source: https://docs.logisheets.com/craft/writing-a-craft.html The three identity fields in `package.json` that the host needs. `craftId` is stable and kebab-case; `label` is the human name; `version` is the package version. When published, the host installs by `craftId` and reads the generated `manifest.json`. ```json { "craftId": "my-craft", // stable, kebab-case — the id the host installs under "label": "My Craft", // human name shown in the craft picker "version": "0.1.0" } ``` -------------------------------- ### Create block with description and per-operation permissions Source: https://docs.logisheets.com/craft/writing-a-craft.html Creates a block with a description and per-operation permissions. The description is saved and reported by getBlockInfo, so write it for a stranger. Set owner to 'my-craft' (required for any policy to bite) and use modifyPolicy as the fallback; operations left out follow modifyPolicy. The operations are insertDeleteLines, removeBlock, modifySchema, cellInput, sortByField, modifyDescription, and overrideValidation, each taking all, ownerAndUser, or ownerOnly. ```ts await ctx.workbook.handleTransaction({ transaction: { payloads: [ { type: 'createBlock', value: { sheetIdx, id: blockId, masterRow: 0, masterCol: 0, rowCnt: 8, colCnt: 3, owner: 'my-craft', // required for any policy to bite description: 'One row per run. `score` is computed by my-craft; ' + 'edit `input`, never `score`.', modifyPolicy: 'ownerAndUser', // the fallback permissions: { cellInput: 'all', // let anyone type insertDeleteLines: 'ownerOnly', removeBlock: 'ownerOnly', modifySchema: 'ownerOnly', // sortByField left out → follows modifyPolicy }, }, }, ], undoable: true, temp: false, }, }) ``` -------------------------------- ### Insert rows via context menu transaction Source: https://docs.logisheets.com/engine.html Branches on context.target to build different menus and runs the chosen action as a transaction. Uses getSelectedLines to compute the start row and calls engine.getDataService().handleTransaction with an insertRows payload, marking it undoable. ```typescript async function insertRows(context, count) { const lines = getSelectedLines(context.selectedData) // {start, end, type} const start = lines ? Math.min(lines.start, lines.end) : (context.row ?? 0) await engine.getDataService().handleTransaction({ payloads: [{type: 'insertRows', value: {sheetIdx: engine.getCurrentSheetIndex(), start, count}}], undoable: true, temp: false, }) } ``` -------------------------------- ### runtime.createWorkbook() Source: https://docs.logisheets.com/runtime.html Creates a new, empty workbook in the runtime. ```APIDOC ## [SDK] runtime.createWorkbook() ### Description Creates a new, empty workbook in the runtime. ### Method createWorkbook ### Signature `(): Workbook` ### Parameters None ### Returns A new Workbook instance. ### Example ```ts const wb = runtime.createWorkbook() ``` ``` -------------------------------- ### Project structure after scaffolding Source: https://docs.logisheets.com/craft/writing-a-craft.html Shows the project structure created by `craftsmith new`. The `tools.ts` file is the core logic; `index.html` is optional; `runtime.ts` is not scaffolded and must be added manually for the runtime face. ```text my-craft/ ├── package.json # identity: craftId, label, version (+ check/build scripts) ├── tools.ts # YOUR LOGIC — pure functions (the core) ├── index.html # a browser UI (optional) └── tsconfig.json ``` -------------------------------- ### loadFile Source: https://docs.logisheets.com/engine.html Loads a `.xlsx` file into the engine and refreshes the mounted grid. ```APIDOC ## loadFile ### Description Load `.xlsx` bytes and refresh the mounted grid. Prefer this over `DataService.loadWorkbook` when the UI is mounted — it also updates the Svelte component's dimensions/anchors. ### Method loadFile ### Endpoint `loadFile(buffer: Uint8Array, filename: string): Promise` ### Parameters - **buffer** (Uint8Array) - Required - The `.xlsx` file bytes. - **filename** (string) - Required - The name of the file being loaded. ### Request Example ```ts const buf = await fetch('workbook.xlsx').then((r) => r.arrayBuffer()) const grid = await engine.loadFile(new Uint8Array(buf), 'workbook.xlsx') ``` ### Response #### Success Response - **Grid | null** - The loaded grid, or `null` if loading failed. #### Response Example ```ts const grid = await engine.loadFile(new Uint8Array(buf), 'workbook.xlsx') ``` ``` -------------------------------- ### Import Engine and required CSS Source: https://docs.logisheets.com/engine.html Import the Engine class and the required style.css to ship the grid styles. The CSS import is mandatory. ```ts import {Engine} from 'logisheets-engine' import 'logisheets-engine/style.css' // required — ships the grid styles ``` -------------------------------- ### mount(container: HTMLElement, options?: EngineMountOptions): void Source: https://docs.logisheets.com/engine.html Mounts the grid UI into the given container on the default session. Options are all optional. ```APIDOC ## mount(container: HTMLElement, options?: EngineMountOptions): void ### Description Mounts the grid UI into the given container on the default session. Options are all optional. ### Method mount ### Endpoint mount(container: HTMLElement, options?: EngineMountOptions): void ### Parameters #### Path Parameters - **container** (HTMLElement) - Required - The DOM element to mount the grid UI into. #### Request Body - **options** (EngineMountOptions) - Optional - Mount options. All fields optional. - **showSheetTabs** (boolean) - Optional - Render the sheet-tab bar at the bottom. Set `false` if you provide your own tabs. - **showScrollbars** (boolean) - Optional - Render scrollbars. - **cellLayouts** (CellLayout[]) - Optional - Per-cell visual overrides (background, tooltip). See CellLayout. - **getIsEditingFormula** (() => boolean) - Optional - Return `true` while the user is editing a formula in your own input, so the canvas doesn't steal focus. - **onInvalidFormula** (() => void) - Optional - Called when the user commits an invalid formula. ### Request Example ```ts engine.mount(container, { showSheetTabs: false, // app renders its own tabs showScrollbars: true, cellLayouts, getIsEditingFormula: () => isEditingFormulaRef.current(), }) ``` ### Response #### Success Response - **void** - No return value. ### Response Example ```ts engine.mount(document.getElementById('spreadsheet')!) ``` ``` -------------------------------- ### Import SpreadsheetRuntime and RpcServer from logisheets-runtime Source: https://docs.logisheets.com/runtime.html Import the SpreadsheetRuntime and RpcServer classes from the logisheets-runtime package to create and host workbooks. ```ts import {SpreadsheetRuntime, RpcServer} from 'logisheets-runtime' ``` -------------------------------- ### initOffscreen(canvas: HTMLCanvasElement): Promise Source: https://docs.logisheets.com/engine.html Headless rendering into your own canvas, without mounting the interactive UI. Advanced; only needed for custom render pipelines. ```APIDOC ## initOffscreen(canvas: HTMLCanvasElement): Promise ### Description Headless rendering into your own canvas, without mounting the interactive UI. Advanced; only needed for custom render pipelines. ### Method initOffscreen ### Endpoint initOffscreen(canvas: HTMLCanvasElement): Promise ### Parameters #### Path Parameters - **canvas** (HTMLCanvasElement) - Required - The canvas element to render into. ### Response #### Success Response - **Promise** (Promise) - Resolves when offscreen rendering is initialized. ### Response Example ```ts await engine.initOffscreen(canvas) ``` ``` -------------------------------- ### craftsmith CLI: check, build, pack Source: https://docs.logisheets.com/craft/writing-a-craft.html Commands to check, build, and pack a craft. `check` validates the tool contract and purity without writing; `build` compiles tools.ts/runtime.ts into dist/ and manifest.json; `pack` tars dist/ into a shippable -.tgz. ```bash npx craftsmith check . # validate the tool contract + purity — no writes npx craftsmith build . # compile tools.ts/runtime.ts → dist/ + manifest.json npx craftsmith pack . # tar dist/ into a shippable -.tgz ``` -------------------------------- ### mountWhenReady helper for logisheets-engine Source: https://docs.logisheets.com/engine.html Helper that mounts the engine once it is ready, handling the case where the engine is already ready (since 'ready' won't fire again). Use it in any framework to encapsulate the mount-on-ready logic. ```ts import type {Engine} from 'logisheets-engine' export function mountWhenReady(engine: Engine, el: HTMLElement) { const run = () => engine.mount(el, {showSheetTabs: true, showScrollbars: true}) engine.isReady() ? run() : engine.on('ready', run) } ``` -------------------------------- ### Engine initialization and ready event Source: https://docs.logisheets.com/engine.html Constructs an Engine and waits for the 'ready' event before mounting into a DOM element. The engine creates its own Web Worker; worker and WASM initialization are asynchronous. ```TypeScript const engine = new Engine(/* config? */) engine.on('ready', () => { engine.mount(document.getElementById('spreadsheet')!) }) ``` -------------------------------- ### Create formula bar with createFormulaEditor and createEngineFormulaSource Source: https://docs.logisheets.com/engine.html Wire a vanilla formula bar to the engine using createEngineFormulaSource and createFormulaEditor. The onSubmit handler commits a cellInput transaction, and the selectionChange listener keeps the bar in sync with the selected cell. ```ts import {createFormulaEditor} from 'logisheets-formula-editor/core' import {createEngineFormulaSource} from 'logisheets-formula-editor/engine' const source = createEngineFormulaSource(engine.getDataService()) const bar = createFormulaEditor(document.getElementById('formula-bar')!, { ...source, onSubmit: (value) => { const sel = engine.getSelection() if (sel.data?.ty !== 'cellRange') return const {startRow, startCol} = sel.data.d // commit — see "Editing data" above engine.getWorkbook().handleTransaction({ transaction: { payloads: [{type: 'cellInput', value: {sheetIdx: engine.getCurrentSheetIndex(), row: startRow, col: startCol, content: value}}], undoable: true, temp: false, }, temp: false, }) }, }) // keep the bar showing the selected cell engine.on('selectionChange', async (sel) => { if (sel.data?.ty !== 'cellRange') return const {startRow, startCol} = sel.data.d const cell = await engine.getDataService().getCellInfo(engine.getCurrentSheetIndex(), startRow, startCol) if (!isErrorMessage(cell)) bar.setValue(cell.getFormula() ? `=${cell.getFormula()}` : cell.getText()) }) ``` -------------------------------- ### runtime.loadWorkbookFromBytes(content, name, path?) Source: https://docs.logisheets.com/runtime.html Loads a workbook from .xlsx bytes already in memory. ```APIDOC ## [SDK] runtime.loadWorkbookFromBytes(content, name, path?) ### Description Loads a workbook from .xlsx bytes already in memory. ### Method loadWorkbookFromBytes ### Signature `(content: Uint8Array, name: string, path?: string): Workbook` ### Parameters - **content** (Uint8Array) - Required - The .xlsx file bytes. - **name** (string) - Required - The name of the workbook. - **path** (string) - Optional - The file path associated with the workbook. ### Returns A Workbook instance. ### Example ```ts const bytes = new Uint8Array(...) const wb = runtime.loadWorkbookFromBytes(bytes, 'book.xlsx') ``` ``` -------------------------------- ### Create multiple sessions for split views Source: https://docs.logisheets.com/engine.html Creates two sessions on the same engine to display the same workbook in multiple views. Loads the file once, mounts each session to its own container, sets an independent active sheet, listens for selection changes, and destroys the second session when its window closes. ```typescript const engine = new Engine() engine.on('ready', async () => { await engine.loadFile(bytes, 'book.xlsx') // load once, on the engine // First view. const main = engine.createSession() main.mount(document.getElementById('view-main')!) // Second view of the SAME workbook — edits sync both ways. const second = engine.createSession() second.mount(document.getElementById('view-second')!) second.setCurrentSheetIndex(1) // independent active sheet second.on('selectionChange', (sel) => console.log('view 2', sel)) // When the second window closes: second.destroy() // unmounts and frees its canvas in the worker }) ``` -------------------------------- ### Create in-cell editor with createInlineCellEditor Source: https://docs.logisheets.com/engine.html Create an in-cell editor controller that listens for the engine's startEdit event, positions an editor over the target cell, commits edits, and paints reference highlights. Keep it in sync with gridChange events. ```ts import {createInlineCellEditor} from 'logisheets-formula-editor/inline' const inline = createInlineCellEditor({ container: gridEl, // the same element you mounted the engine into eventSource: engine, // the Engine (or a Session) emitting startEdit dataService: engine.getDataService(), sheetIdx: engine.getCurrentSheetIndex(), getSheetName: () => engine.getSheets()[engine.getCurrentSheetIndex()]?.name ?? '', inputCell: (sheetIdx, row, col, text) => engine.getWorkbook().handleTransaction({ transaction: {payloads: [{type: 'cellInput', value: {sheetIdx, row, col, content: text}}], undoable: true, temp: false}, temp: false, }), setSelection: (sel) => engine.setSelection(sel), grid: engine.getGrid(), }) engine.on('gridChange', (g) => inline.setGrid(g)) ``` -------------------------------- ### runtime.loadWorkbook(path) Source: https://docs.logisheets.com/runtime.html Loads a .xlsx workbook from disk. Loading the same path twice returns the already-open workbook until it is closed. ```APIDOC ## [SDK] runtime.loadWorkbook(path) ### Description Loads a .xlsx workbook from disk. Loading the same path twice returns the already-open workbook until it is closed. ### Method loadWorkbook ### Signature `(path: string): Promise` ### Parameters - **path** (string) - Required - The file path to the .xlsx file. ### Returns A Promise that resolves to a Workbook instance. ### Example ```ts const wb = await runtime.loadWorkbook('./book.xlsx') ``` ``` -------------------------------- ### initOffscreen Source: https://docs.logisheets.com/engine.html Binds an offscreen canvas for rendering. ```APIDOC ## [POST] /dataService/initOffscreen ### Description Binds an offscreen canvas for rendering. ### Method POST ### Endpoint /dataService/initOffscreen ### Parameters #### Request Body - **canvas** (OffscreenCanvas) - Required - The offscreen canvas to bind. ### Request Example ```json { "canvas": {} } ``` ### Response #### Success Response (200) - **void** - No content on success. #### Error Response - **ErrorMessage** - An error message if binding fails. ### Response Example ```json {} ``` ```