# Editor API

> The Editor class — options, events and every public member, generated from its JSDoc.

The editor: a document, its history, and a view that owns each block's content element. Construct it with the modules you use, render it with a binding (`<Blocks>` from `verbal-editor/react`), and read or change the document through the methods below.

```js
const editor = new Editor({ blocks: [heading], marks: [bold], ui: [slash] });
editor.on('change', () => save(editor.getDoc()));
```

## Options

Editor options. `editable: false` renders the document read-only: text can be selected and copied, nothing changes it (every transaction is ignored) and modules hide their controls. Anything else beyond the modules and the document is read by modules or bindings: `upload(file) → Promise<url>` (image), `unfurl(url) → Promise<{ title }>` (embed), `onRender(id)` (React binding: called on every block render).

| Option | Type |
| --- | --- |
| `blocks?` | `BlockModule[]` |
| `marks?` | `MarkModule[]` |
| `ui?` | `UiModule[]` |
| `doc?` | `Doc \| string` |
| `editable?` | `boolean` |
| `upload?` | `(file: File) => Promise<string>` |
| `unfurl?` | `(url: string) => Promise<{ title?: string } \| null>` |
| `onRender?` | `(id: string) => void` |

## Events

Events: 'change' ({ ops, origin }) after every transaction; 'selectionchange' (Selection | null); 'input' ({ id, data }) after typed text, before Markdown rules — return true to skip them; 'key' ({ name, e }) before any key is handled — return true to claim it.

## Members

### `new Editor()`

@param {EditorOptions} [options]

### `editor.options`

Options for modules and bindings (everything except blocks, marks, ui and doc).

### `editor.ui`

@type {UiModule[]}

### `editor.selection`

The current selection: text points, whole blocks, or null.

### `editor.store`

Per-block versions that bindings subscribe to; bumped by structural edits, never by typing.

### `editor.history`

Undo/redo stacks.

### `editor.registry`

Every registered block type, mark, slash entry, shortcut and typing rule.

### `editor.view`

The DOM side: content elements, selection mapping, events. For modules and bindings.

### `editor.doc`

The live document. Treat it as read-only; change it with transactions.

### `editor.setDoc(doc)`

Replaces the document; history starts over and the selection clears.

| Parameter | Type | Description |
| --- | --- | --- |
| `doc` | `Doc \| string` | a payload from getDoc() (or its JSON) |

### `editor.getDoc()`

A deep copy of the document payload, blocks in document order (HLD §3.3).

Returns `Doc`.

### `editor.get(id)`

A block by id (live — do not mutate).

| Parameter | Type | Description |
| --- | --- | --- |
| `id` | `string` | — |

Returns `Block | undefined`.

### `editor.parent(id)`

The id of a block's parent.

| Parameter | Type | Description |
| --- | --- | --- |
| `id` | `string` | — |

Returns `string | undefined`.

### `editor.span(a, b)`

The outermost blocks from `a` to `b` inclusive, in document order.

| Parameter | Type | Description |
| --- | --- | --- |
| `a` | `string` | — |
| `b` | `string` | — |

Returns `string[]`.

### `editor.tx()`

A new transaction on the current document; pass it to dispatch().

Returns `Tx`.

### `editor.mod(id)`

The module of a block's type.

| Parameter | Type | Description |
| --- | --- | --- |
| `id` | `string` | — |

Returns `BlockModule | undefined`.

### `editor.len(id)`

Length of a block's text.

| Parameter | Type | Description |
| --- | --- | --- |
| `id` | `string` | — |

Returns `number`.

### `editor.targets(s?)`

What a block command acts on: the selected blocks, or every block the text selection touches.

| Parameter | Type | Description |
| --- | --- | --- |
| `s?` | `Selection \| null` | — |

Returns `string[]`.

### `editor.range`

The selection when it lies inside one block, as { block, from, to }; null otherwise.

Returns `Range | null`.

### `editor.on(type, fn)`

Listens for an editor event; returns the function that stops listening.

| Parameter | Type | Description |
| --- | --- | --- |
| `type` | `EditorEvent` | — |
| `fn` | `(e: any, editor: Editor) => boolean \| void` | — |

Returns `() => void`.

### `editor.emit(type, e?)`

Calls listeners in order; true when one of them handled the event.

| Parameter | Type | Description |
| --- | --- | --- |
| `type` | `EditorEvent` | — |
| `e?` | `any` | — |

Returns `boolean`.

### `editor.mount(root)`

Attaches the view to its root element; every module with a mount(editor) hook starts. Bindings call this.

| Parameter | Type | Description |
| --- | --- | --- |
| `root` | `HTMLElement` | — |

### `editor.unmount()`

Detaches the view and runs every module's cleanup.

### `editor.dispatch(t, options?)`

Applies a transaction: the model, then text repaints, then one version bump per structurally changed block (so only those re-render), then history and the 'change' event. A transaction that throws part-way is rolled back; a read-only editor (`editable: false`) ignores it.

| Parameter | Type | Description |
| --- | --- | --- |
| `t` | `Tx \| object[]` | a transaction from tx(), or its ops |
| `options?` | `{ selection?: Selection \| null, origin?: 'input' \| 'history' \| string, kind?: string, before?: Selection \| null }` | `selection` to select afterwards (undo restores `before`); `kind: 'text'` coalesces with adjacent typing |

### `editor.undo()`

Undoes the last step, restoring the model and the selection.

Returns `true`.

### `editor.redo()`

Redoes the last undone step.

Returns `true`.

### `editor.select(sel)`

Selects text points or whole blocks, in the model and on screen.

| Parameter | Type | Description |
| --- | --- | --- |
| `sel` | `Selection \| null` | — |

### `editor.key(name, e?)`

Runs a key as if pressed: UI interceptors, then scoped module keys (block → ancestors), shortcuts, core defaults. Names look like 'Enter', 'Shift-Tab', 'Mod-b' (Mod is ⌘ on Apple, Ctrl elsewhere).

| Parameter | Type | Description |
| --- | --- | --- |
| `name` | `string` | — |
| `e?` | `any` | — |

Returns `boolean` — whether something handled it.

### `editor.container(id)`

Nearest ancestor that holds blocks but no text (doc, column, table…).

| Parameter | Type | Description |
| --- | --- | --- |
| `id` | `string` | — |

Returns `string | undefined`.

### `editor.split()`

Enter: splits the focused block at the caret (the new block's type comes from the module's `next`).

Returns `boolean`.

### `editor.join(dir)`

Backspace at a block's start (dir -1) or Delete at its end (dir 1): drop a void neighbour or merge.

| Parameter | Type | Description |
| --- | --- | --- |
| `dir` | `-1 \| 1` | — |

Returns `boolean`.

### `editor.indent(ids)`

Tab: nests each block under the one above it — one transaction for any number of blocks.

| Parameter | Type | Description |
| --- | --- | --- |
| `ids` | `...string` | default: targets() |

Returns `boolean`.

### `editor.outdent(ids)`

Shift-Tab: each block follows its parent out; the last goes first so they keep their order.

| Parameter | Type | Description |
| --- | --- | --- |
| `ids` | `...string` | default: targets() |

Returns `boolean`.

### `editor.replace(range, str)`

Replaces a range inside one block with plain text, keeping the marks at its start.

| Parameter | Type | Description |
| --- | --- | --- |
| `range` | `Range` | — |
| `str` | `string` | — |

Returns `true`.

### `editor.remove(ids)`

Removes whole blocks; the caret lands on the nearest remaining text block.

| Parameter | Type | Description |
| --- | --- | --- |
| `ids` | `string[]` | — |

Returns `true`.

### `editor.setType(type, props?, ids)`

Turns text blocks into `type`, keeping their text — one transaction.

| Parameter | Type | Description |
| --- | --- | --- |
| `type` | `string` | — |
| `props?` | `Record<string, any>` | — |
| `ids` | `...string` | default: targets() |

Returns `boolean`.

### `editor.insert(type, props?, t?)`

Converts the focused empty paragraph into `type`, or inserts `type` after the focused block (after the whole grid when the caret is in a table cell); the caret lands where you can type next.

| Parameter | Type | Description |
| --- | --- | --- |
| `type` | `string` | — |
| `props?` | `Record<string, any>` | — |
| `t?` | `Tx` | a transaction to add to |

Returns `string` — the new block's id.

### `editor.toggleMark(type, attrs?, force?)`

Toggles (or with `force`, sets) a mark over the selection, or as a stored mark for the next typed text.

| Parameter | Type | Description |
| --- | --- | --- |
| `type` | `string` | — |
| `attrs?` | `Record<string, any>` | e.g. { href } |
| `force?` | `boolean` | — |

Returns `boolean`.

### `editor.active(type)`

Whether every selected character carries `type` (or the stored marks do, for a caret).

| Parameter | Type | Description |
| --- | --- | --- |
| `type` | `string` | — |

Returns `boolean`.

### `editor.copy(cut?)`

Clipboard payload for the selection: HTML carrying the exact blocks, Markdown as plain text.

| Parameter | Type | Description |
| --- | --- | --- |
| `cut?` | `boolean` | also remove the selection |

Returns `{ html: string, text: string } | null`.

### `editor.paste(data)`

Pastes at the selection: a module may claim it (files, table cells); otherwise HTML or Markdown is parsed into blocks, never injected.

| Parameter | Type | Description |
| --- | --- | --- |
| `data` | `{ html?: string, text?: string, files?: File[] }` | — |

Returns `true`.

### `editor.edit(id)`

Puts the caret at the end of a text block.

| Parameter | Type | Description |
| --- | --- | --- |
| `id` | `string` | — |

Returns `true`.

### `editor.selectAll()`

⌘A: the block's text first, then every top-level block.

Returns `boolean`.
