@inkami/blx 0.17.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/README.md +98 -0
  2. package/dist/attributed-string/attributed-string.d.ts +37 -0
  3. package/dist/attributed-string/index.d.ts +2 -0
  4. package/dist/attributed-string/types.d.ts +13 -0
  5. package/dist/autocomplete/autocomplete-menu.d.ts +24 -0
  6. package/dist/autocomplete/index.d.ts +2 -0
  7. package/dist/autocomplete/types.d.ts +29 -0
  8. package/dist/blob-store/index.d.ts +32 -0
  9. package/dist/blob-store/types.d.ts +24 -0
  10. package/dist/block/block-controller.d.ts +205 -0
  11. package/dist/block/index.d.ts +2 -0
  12. package/dist/block/types.d.ts +15 -0
  13. package/dist/block-action-menu/block-action-menu.d.ts +62 -0
  14. package/dist/block-action-menu/index.d.ts +2 -0
  15. package/dist/block-context-menu/block-context-menu.d.ts +33 -0
  16. package/dist/block-context-menu/index.d.ts +2 -0
  17. package/dist/blx.js +16245 -0
  18. package/dist/blx.js.map +1 -0
  19. package/dist/caret/custom-caret.d.ts +30 -0
  20. package/dist/clipboard/clipboard-manager.d.ts +28 -0
  21. package/dist/clipboard/index.d.ts +2 -0
  22. package/dist/clipboard/paste-parser.d.ts +30 -0
  23. package/dist/commands/command-registry.d.ts +26 -0
  24. package/dist/commands/index.d.ts +2 -0
  25. package/dist/crdt/automerge-sync.d.ts +157 -0
  26. package/dist/crdt/crdt-log.d.ts +57 -0
  27. package/dist/crdt/index.d.ts +8 -0
  28. package/dist/crdt/remote-cursor-renderer.d.ts +28 -0
  29. package/dist/crdt/replay-ui.d.ts +34 -0
  30. package/dist/crdt/types.d.ts +47 -0
  31. package/dist/date-picker/agenda-utils.d.ts +37 -0
  32. package/dist/date-picker/date-parser.d.ts +25 -0
  33. package/dist/date-picker/date-picker.d.ts +115 -0
  34. package/dist/date-picker/index.d.ts +6 -0
  35. package/dist/drag-handle/drag-handle.d.ts +105 -0
  36. package/dist/drag-handle/index.d.ts +1 -0
  37. package/dist/editor.d.ts +864 -0
  38. package/dist/emoji-picker/emoji-data.d.ts +22 -0
  39. package/dist/emoji-picker/emoji-picker.d.ts +43 -0
  40. package/dist/emoji-picker/index.d.ts +3 -0
  41. package/dist/event-bus/event-bus.d.ts +14 -0
  42. package/dist/event-bus/index.d.ts +2 -0
  43. package/dist/event-bus/types.d.ts +320 -0
  44. package/dist/fold/fold-manager.d.ts +27 -0
  45. package/dist/fold/index.d.ts +2 -0
  46. package/dist/grapheme.d.ts +28 -0
  47. package/dist/index.d.ts +62 -0
  48. package/dist/inline-toolbar/highlight-picker.d.ts +41 -0
  49. package/dist/inline-toolbar/index.d.ts +5 -0
  50. package/dist/inline-toolbar/inline-toolbar.d.ts +97 -0
  51. package/dist/inline-toolbar/link-popover.d.ts +24 -0
  52. package/dist/keybindings/defaults.d.ts +2 -0
  53. package/dist/keybindings/index.d.ts +4 -0
  54. package/dist/keybindings/key-matcher.d.ts +41 -0
  55. package/dist/keybindings/types.d.ts +6 -0
  56. package/dist/keybindings/vim.d.ts +2 -0
  57. package/dist/markdown/block-shortcuts.d.ts +35 -0
  58. package/dist/markdown/emoticon-substitutions.d.ts +22 -0
  59. package/dist/markdown/export.d.ts +5 -0
  60. package/dist/markdown/index.d.ts +4 -0
  61. package/dist/markdown/inline-shortcuts.d.ts +13 -0
  62. package/dist/markdown/types.d.ts +29 -0
  63. package/dist/plugins/blockquote.d.ts +6 -0
  64. package/dist/plugins/checklist.d.ts +18 -0
  65. package/dist/plugins/code.d.ts +50 -0
  66. package/dist/plugins/excalidraw.d.ts +26 -0
  67. package/dist/plugins/heading.d.ts +20 -0
  68. package/dist/plugins/horizontal-rule.d.ts +5 -0
  69. package/dist/plugins/image.d.ts +19 -0
  70. package/dist/plugins/index.d.ts +28 -0
  71. package/dist/plugins/list.d.ts +18 -0
  72. package/dist/plugins/mermaid.d.ts +11 -0
  73. package/dist/plugins/paragraph.d.ts +18 -0
  74. package/dist/plugins/prism-loader.d.ts +16 -0
  75. package/dist/plugins/render-utils.d.ts +43 -0
  76. package/dist/plugins/table.d.ts +22 -0
  77. package/dist/plugins/youtube.d.ts +21 -0
  78. package/dist/schema/index.d.ts +2 -0
  79. package/dist/schema/schema-registry.d.ts +35 -0
  80. package/dist/schema/types.d.ts +67 -0
  81. package/dist/search/index.d.ts +4 -0
  82. package/dist/search/search-engine.d.ts +39 -0
  83. package/dist/search/search-ui.d.ts +59 -0
  84. package/dist/selection/index.d.ts +3 -0
  85. package/dist/selection/selection-manager.d.ts +41 -0
  86. package/dist/selection/types.d.ts +20 -0
  87. package/dist/slash-menu/index.d.ts +2 -0
  88. package/dist/slash-menu/slash-menu.d.ts +27 -0
  89. package/dist/table-of-contents/index.d.ts +1 -0
  90. package/dist/table-of-contents/table-of-contents.d.ts +74 -0
  91. package/dist/transaction/index.d.ts +2 -0
  92. package/dist/transaction/transaction.d.ts +29 -0
  93. package/dist/transaction/types.d.ts +40 -0
  94. package/dist/types.d.ts +21 -0
  95. package/dist/ui/context-menu.d.ts +103 -0
  96. package/dist/ui/dismiss.d.ts +33 -0
  97. package/dist/ui/dropdown.d.ts +81 -0
  98. package/dist/ui/floating-scroll-manager.d.ts +50 -0
  99. package/dist/ui/index.d.ts +18 -0
  100. package/dist/ui/modal.d.ts +109 -0
  101. package/dist/ui/popover.d.ts +59 -0
  102. package/dist/ui/position-fixed.d.ts +35 -0
  103. package/dist/ui/toast.d.ts +60 -0
  104. package/dist/ui/tooltip.d.ts +64 -0
  105. package/dist/undo/index.d.ts +5 -0
  106. package/dist/undo/jump-list.d.ts +37 -0
  107. package/dist/undo/types.d.ts +49 -0
  108. package/dist/undo/undo-manager.d.ts +47 -0
  109. package/dist/util/icons.d.ts +13 -0
  110. package/dist/util/id.d.ts +10 -0
  111. package/dist/viewport/block-viewport.d.ts +106 -0
  112. package/dist/viewport/index.d.ts +2 -0
  113. package/package.json +66 -0
  114. package/style.css +4670 -0
@@ -0,0 +1,864 @@
1
+ import type { Block, BlockJSON } from "./types";
2
+ import { AttributedString } from "./attributed-string";
3
+ import type { Attributes } from "./attributed-string";
4
+ import { EventBus } from "./event-bus";
5
+ import type { EditorEventMap, ThemeMode } from "./event-bus";
6
+ import { SchemaRegistry } from "./schema";
7
+ import type { BlockTypePlugin } from "./schema";
8
+ import type { TransactionResult } from "./transaction";
9
+ import type { SlashMenuItem } from "./slash-menu";
10
+ import type { AutoCompleteProvider } from "./autocomplete";
11
+ import type { DateSuggestion } from "./date-picker";
12
+ import type { ToolbarButton } from "./inline-toolbar";
13
+ import type { BlockActionMenuEntry } from "./block-action-menu";
14
+ import type { KeybindingMap } from "./keybindings";
15
+ import type { BlockViewportOptions } from "./viewport";
16
+ import { CrdtLog } from "./crdt/crdt-log";
17
+ import { AutomergeSync } from "./crdt/automerge-sync";
18
+ import type { AutomergeSyncOptions } from "./crdt/automerge-sync";
19
+ import type { CrdtPeer, RemoteCursor, CrdtOperation } from "./crdt/types";
20
+ import type { FoldState } from "./fold";
21
+ import { CommandRegistry, type ExternalCommandEntry } from "./commands/command-registry";
22
+ import type { BlockContextMenuEntry } from "./block-context-menu";
23
+ /**
24
+ * Provider that supplies date suggestions for the @ agenda trigger.
25
+ * Register via `editor.setDateSuggestionProvider()`.
26
+ */
27
+ export interface DateSuggestionProvider {
28
+ /** Parse a natural language query and return date suggestions. */
29
+ suggest(query: string): DateSuggestion[];
30
+ }
31
+ export interface ExternalKeybinding {
32
+ /** Key sequence descriptor, e.g. `" ,a"` for leader+a. */
33
+ keys: string;
34
+ /** Unique command ID for the action. */
35
+ commandId: string;
36
+ /** Handler invoked when the key sequence is matched. */
37
+ handler: () => void;
38
+ }
39
+ export interface EditorOptions {
40
+ schema?: SchemaRegistry;
41
+ eventBus?: EventBus<EditorEventMap>;
42
+ defaultPlugins?: boolean;
43
+ initialBlocks?: Block[];
44
+ /**
45
+ * Custom URL resolver for link hrefs. Receives the raw URL from the
46
+ * content model and should return a fully-qualified URL.
47
+ *
48
+ * Default: prepends `https://` to URLs that lack a protocol and don't
49
+ * look like internal references (`#`, `/`, `mailto:`, `tel:`).
50
+ */
51
+ resolveUrl?: (url: string) => string;
52
+ /**
53
+ * Auto-focus the last block when typing occurs while no block is focused.
54
+ * The `editor:unfocusedInput` event is emitted regardless of this setting.
55
+ */
56
+ autoFocusOnInput?: boolean;
57
+ /**
58
+ * Custom keybinding map. Partial overrides are merged with the defaults.
59
+ */
60
+ keybindings?: Partial<KeybindingMap>;
61
+ /**
62
+ * Color theme. `"system"` (default) follows `prefers-color-scheme`,
63
+ * `"light"` / `"dark"` forces a specific theme.
64
+ */
65
+ theme?: ThemeMode;
66
+ /**
67
+ * Handler for inline link clicks. Called when a user activates a link
68
+ * (Cmd/Ctrl+Click on desktop, double-tap on mobile). If not provided,
69
+ * links open in a new tab via `window.open()`.
70
+ *
71
+ * Return `true` to indicate the click was handled; the default
72
+ * `window.open` will be suppressed.
73
+ */
74
+ onLinkClick?: (href: string, resolvedHref: string, event: MouseEvent) => boolean | void;
75
+ /**
76
+ * Called after a blockRef span is rendered. Use to add CSS classes or
77
+ * data attributes for app-specific styling (e.g. broken-link indicators).
78
+ */
79
+ onBlockRefRender?: (element: HTMLElement, refId: string) => void;
80
+ /**
81
+ * Transform pasted plain text before BLX processes it.
82
+ * Return an object to replace the paste with marked text, or null/undefined
83
+ * for default handling.
84
+ */
85
+ transformPastedText?: (text: string) => {
86
+ text: string;
87
+ attributes: Attributes;
88
+ } | null;
89
+ /**
90
+ * Options for the virtual rendering viewport. When enabled, only blocks
91
+ * visible in the viewport (plus a buffer zone) have their content rendered
92
+ * in the DOM. Off-screen blocks keep lightweight placeholder containers
93
+ * for scroll stability.
94
+ *
95
+ * Set to `false` to disable virtual rendering entirely (all blocks are
96
+ * always rendered). Enabled by default.
97
+ */
98
+ viewport?: BlockViewportOptions | false;
99
+ /** Callback when fold state changes. Host should persist this. */
100
+ onFoldChanged?: (state: FoldState) => void;
101
+ /** Initial fold state to restore. */
102
+ initialFoldState?: FoldState;
103
+ /**
104
+ * An outer container element (e.g. the scroll host) that should also
105
+ * respond to clicks by focusing the nearest block. Clicks inside the
106
+ * editor root are ignored (handled by the editor's own mousedown).
107
+ */
108
+ clickContainer?: HTMLElement;
109
+ }
110
+ export interface EditorJSON {
111
+ blocks: BlockJSON[];
112
+ }
113
+ export declare class Editor {
114
+ readonly root: HTMLElement;
115
+ readonly content: HTMLElement;
116
+ readonly gutter: HTMLElement;
117
+ readonly blocksContainer: HTMLElement;
118
+ readonly schema: SchemaRegistry;
119
+ readonly bus: EventBus<EditorEventMap>;
120
+ readonly commands: CommandRegistry;
121
+ private controllers;
122
+ private controllerMap;
123
+ /** Sticky X position for consecutive ArrowUp/ArrowDown navigation */
124
+ private goalX;
125
+ /** Block selection state */
126
+ private blockSelectAnchor;
127
+ private blockSelectFocus;
128
+ private editorMode;
129
+ /** Whether visual block mode persists without Shift (true = vim V, false = shift-arrow transient) */
130
+ private visualBlockSticky;
131
+ /** Last action that mutated blocks — replayed by the dot (.) command */
132
+ private lastRepeatableAction;
133
+ /** Actions that count as repeatable mutations (navigation, mode changes, etc. are excluded) */
134
+ private static readonly REPEATABLE_ACTIONS;
135
+ /** Slash command menu */
136
+ private slashMenu;
137
+ private slashMenuBlockId;
138
+ private slashCommandOffset;
139
+ private slashMenuKeyHandler;
140
+ private customSlashHandlers;
141
+ private customSlashItems;
142
+ /** Emoji picker */
143
+ private emojiPicker;
144
+ private emojiBlockId;
145
+ private emojiColonOffset;
146
+ private emojiKeyHandler;
147
+ /** Agenda date picker (@) */
148
+ private agendaPicker;
149
+ private agendaBlockId;
150
+ private agendaAtOffset;
151
+ private agendaKeyHandler;
152
+ private dateSuggestionProvider;
153
+ /** Autocomplete menu ([[) */
154
+ private autoCompleteMenu;
155
+ private autoCompleteBlockId;
156
+ private autoCompleteBracketOffset;
157
+ private autoCompleteKeyHandler;
158
+ private autoCompleteProviders;
159
+ /** Drag handle */
160
+ private dragHandle;
161
+ /** Inline formatting toolbar */
162
+ private inlineToolbar;
163
+ private selectionChangeHandler;
164
+ private _toolbarDebounceTimer;
165
+ private _mouseDown;
166
+ private _onMouseDown;
167
+ private _onMouseUp;
168
+ private formatKeyHandler;
169
+ private floatingScroll;
170
+ /** Controller with active pending marks (for clearing when focus moves) */
171
+ private _pendingMarksCtrl;
172
+ /** Block ID force-mounted because it has an active text selection */
173
+ private selectionForceMountedId;
174
+ /** Mouse drag → block selection */
175
+ private mouseDragAnchorBlockId;
176
+ private mouseDragActive;
177
+ /** Saved text cursor offset within the anchor block when entering block selection */
178
+ private mouseDragAnchorOffset;
179
+ /** Auto-scroll during drag */
180
+ private dragScrollRAF;
181
+ private _lastDragMouseX;
182
+ private _lastDragMouseY;
183
+ /** Block action menu */
184
+ private blockActionMenu;
185
+ private customCaret;
186
+ private customActionItems;
187
+ /** Right-click context menu */
188
+ private blockContextMenu;
189
+ private customContextItems;
190
+ /** Link popover */
191
+ private linkPopover;
192
+ /** Highlight picker */
193
+ private highlightPicker;
194
+ /** URL hash navigation handler (bound for cleanup) */
195
+ private hashChangeHandler;
196
+ /** Mobile double-tap tracking for link activation */
197
+ private lastTapTarget;
198
+ private lastTapTime;
199
+ /** Search panel */
200
+ private searchEngine;
201
+ private searchUI;
202
+ private searchKeyHandler;
203
+ /** All current search matches (for dim highlighting) */
204
+ private searchMatches;
205
+ /** Index of the currently focused search match (for bright highlighting) */
206
+ private searchCurrentMatch;
207
+ /** Drop zone indicator for external image drag-drop */
208
+ private imageDropZone;
209
+ /** Full-editor overlay shown when dragging unsupported files */
210
+ private dropRejectOverlay;
211
+ /** Focused non-text block (image, youtube, etc.) */
212
+ private focusedNonTextBlockId;
213
+ private nonTextKeyHandler;
214
+ /** Editor options (stored for runtime checks) */
215
+ private options;
216
+ /** Outer click container for focus-on-click outside the editor root */
217
+ private clickContainer;
218
+ /** Current theme mode */
219
+ private themeMode;
220
+ /** Keybinding map and sequencer for block selection mode */
221
+ private keybindings;
222
+ private keySequencer;
223
+ /** Handlers registered by the host app via registerKeybindings(). */
224
+ private externalActions;
225
+ /** Undo/redo history */
226
+ private undoManager;
227
+ /** When true, mutations are not recorded in undo history (used during undo/redo) */
228
+ private _suppressHistory;
229
+ /** Navigation jumplist (Ctrl-O / Ctrl-I) */
230
+ private jumpList;
231
+ /** Last block that had focus (for jumplist tracking) */
232
+ private _lastFocusedBlockId;
233
+ /** Last edit position for g,. navigation */
234
+ private _lastEditPosition;
235
+ /** Cursor position saved before an overlay (search, link popover, etc.) steals focus */
236
+ private _preOverlayCursor;
237
+ /** Keyboard handler for undo/redo and jump shortcuts */
238
+ private undoKeyHandler;
239
+ /** CRDT operation log (null until enabled) */
240
+ private crdtLog;
241
+ /** Replay state */
242
+ private _replayActive;
243
+ private _replayPosition;
244
+ private _replaySavedState;
245
+ private _replayUI;
246
+ private _replayTimer;
247
+ private _replaySpeed;
248
+ /** Multiplayer peer tracking */
249
+ private _localPeer;
250
+ private _peers;
251
+ private _remoteCursors;
252
+ private _remoteCursorRenderScheduled;
253
+ private _cursorScrollCleanup;
254
+ private _cursorIdleTimers;
255
+ /** Automerge CRDT sync adapter (null until enabled) */
256
+ private _automergeSync;
257
+ /** Heading fold manager */
258
+ private foldManager;
259
+ /** Table of contents navigation widget */
260
+ private toc;
261
+ /** Virtual rendering viewport manager */
262
+ private viewport;
263
+ constructor(root: HTMLElement, options?: EditorOptions);
264
+ /**
265
+ * Fast path for loading the initial set of blocks. Bypasses the per-block
266
+ * overhead of addBlock() — no events emitted, no undo history, no
267
+ * individual DOM insertions. All containers are appended via a single
268
+ * DocumentFragment and viewport registration is batched.
269
+ */
270
+ private loadInitialBlocks;
271
+ /**
272
+ * Replace all blocks in a single batch operation. Destroys existing
273
+ * controllers and bulk-loads the new set via DocumentFragment.
274
+ * Used by AutomergeSync.applyDocToEditor() to avoid per-block overhead
275
+ * on full document reload.
276
+ * @internal
277
+ */
278
+ replaceAllBlocks(blocks: Block[]): void;
279
+ addBlock(blockOrType?: Block | string, index?: number): Block;
280
+ removeBlock(id: string): boolean;
281
+ moveBlock(id: string, toIndex: number): boolean;
282
+ /**
283
+ * Import an array of blocks into the editor, appending after existing content.
284
+ * The entire import is treated as a single compound undo entry so the user
285
+ * can undo the import in one step.
286
+ *
287
+ * @param blocks - Serialized blocks to import
288
+ * @returns The created Block instances
289
+ */
290
+ importBlocks(blocks: ReadonlyArray<BlockJSON>): Block[];
291
+ /**
292
+ * Paste blocks at the current cursor position.
293
+ * Splits the focused block at the cursor and inserts the given blocks
294
+ * between the two halves. The entire operation is a single undo entry.
295
+ *
296
+ * If the first pasted block is a paragraph, its content merges into the
297
+ * end of the "before" half (avoids an awkward empty line). Similarly,
298
+ * if the last pasted block is a paragraph, its content merges into the
299
+ * start of the "after" half.
300
+ *
301
+ * Falls back to importBlocks() when no block is focused.
302
+ */
303
+ pasteBlocks(blocks: ReadonlyArray<BlockJSON>): Block[];
304
+ /**
305
+ * Move multiple blocks as a group to a new position, preserving their
306
+ * internal order. `toIndex` is the target position in the array after
307
+ * all the blocks have been removed.
308
+ */
309
+ moveBlocks(blockIds: string[], toIndex: number): boolean;
310
+ /** Get currently selected block IDs, or null if no selection */
311
+ private getSelectedBlockIds;
312
+ /** Move a completed task to the bottom of consecutive checklist blocks */
313
+ private moveCompletedChecklistToBottom;
314
+ /** Move an unchecked task (and its nested children) above the first checked sibling */
315
+ private moveUncheckedTaskToTop;
316
+ /** Set checked state on all nested checklist children of a toggled task */
317
+ private cascadeChecklistToggle;
318
+ private toggleChecklist;
319
+ private cycleTaskStatus;
320
+ private setTaskStatusExplicit;
321
+ private removeTaskStatus;
322
+ /** Block types that support agenda dates (have badge rendering). */
323
+ static readonly AGENDA_BLOCK_TYPES: Set<string>;
324
+ private openAgendaPickerForBlock;
325
+ getBlock(id: string): Block | undefined;
326
+ getBlocks(): ReadonlyArray<Block>;
327
+ getBlockAt(index: number): Block | undefined;
328
+ getBlockIndex(id: string): number;
329
+ getBlockCount(): number;
330
+ changeBlockType(id: string, newType: string, metadata?: Record<string, unknown>): boolean;
331
+ /**
332
+ * Focus the block nearest to the given viewport coordinates.
333
+ * If the point is below the last block, focuses or creates an empty
334
+ * paragraph at the end.
335
+ */
336
+ focusAtPoint(clientX: number, clientY: number): void;
337
+ private focusOrCreateAtEnd;
338
+ focusBlock(id: string, offset?: number): void;
339
+ /** Focus a block and select the text range [start, end). */
340
+ private selectBlockRange;
341
+ /**
342
+ * Scroll a block into view and optionally focus it.
343
+ * Returns `true` if the block was found.
344
+ */
345
+ scrollToBlock(id: string, focus?: boolean): boolean;
346
+ /**
347
+ * Focus the block whose container is closest to the given click point.
348
+ * Used when a click lands in the editor but outside any block element.
349
+ */
350
+ private focusNearestBlock;
351
+ /**
352
+ * Handle a click that landed outside any block element.
353
+ * If the click is below the last block, create a new empty paragraph
354
+ * (or focus the existing empty last block). Otherwise focus the nearest block.
355
+ */
356
+ private handleEmptyAreaClick;
357
+ registerBlockType(plugin: BlockTypePlugin): void;
358
+ /** Register a custom slash menu item with a handler. */
359
+ addSlashMenuItem(item: SlashMenuItem, handler: (blockId: string) => void): void;
360
+ /**
361
+ * Add a custom button to the inline formatting toolbar.
362
+ *
363
+ * Buttons with an `attribute` field act as simple toggles (the editor
364
+ * applies/removes the attribute via transactions automatically).
365
+ *
366
+ * Buttons with an `onAction` callback receive a `ToolbarActionContext`
367
+ * and can implement arbitrary behavior (open a popover, apply complex
368
+ * formatting, etc.).
369
+ *
370
+ * Plugin buttons appear after a separator, to the right of the
371
+ * built-in formatting buttons.
372
+ *
373
+ * @example
374
+ * // Simple attribute toggle
375
+ * editor.addToolbarButton({
376
+ * key: "highlight",
377
+ * label: "Highlight",
378
+ * icon: "H",
379
+ * attribute: "highlight",
380
+ * });
381
+ *
382
+ * @example
383
+ * // Custom action with render function
384
+ * editor.addToolbarButton({
385
+ * key: "link",
386
+ * label: "Link",
387
+ * icon: (container) => { container.textContent = "🔗"; },
388
+ * onAction: (ctx) => showLinkDialog(ctx),
389
+ * isActive: (ctx) => !!ctx.activeAttributes.href,
390
+ * });
391
+ */
392
+ addToolbarButton(button: ToolbarButton): void;
393
+ /**
394
+ * Remove a previously-added custom toolbar button by key.
395
+ * Returns `true` if the button was found and removed.
396
+ */
397
+ removeToolbarButton(key: string): boolean;
398
+ /** Add a custom item to the block action context menu. */
399
+ addBlockActionItem(entry: BlockActionMenuEntry): void;
400
+ /** Remove a custom block action item by key. Returns true if found. */
401
+ removeBlockActionItem(key: string): boolean;
402
+ /** Return all registered commands with execute handlers for external integration. */
403
+ getCommands(): ExternalCommandEntry[];
404
+ toJSON(): EditorJSON;
405
+ static fromJSON(root: HTMLElement, json: EditorJSON, options?: EditorOptions): Editor;
406
+ /**
407
+ * Set the color theme. `"system"` follows `prefers-color-scheme`,
408
+ * `"light"` / `"dark"` forces a specific theme.
409
+ */
410
+ setTheme(mode: ThemeMode): void;
411
+ /** Return the current theme mode. */
412
+ getTheme(): ThemeMode;
413
+ /** Undo the last action. Returns true if an entry was undone. */
414
+ undo(): boolean;
415
+ /** Redo the last undone action. Returns true if an entry was redone. */
416
+ redo(): boolean;
417
+ /** Whether there are entries to undo */
418
+ canUndo(): boolean;
419
+ /** Whether there are entries to redo */
420
+ canRedo(): boolean;
421
+ /** Execute a function with history recording suppressed. */
422
+ withSuppressedHistory(fn: () => void): void;
423
+ /** Clear all undo/redo history */
424
+ clearHistory(): void;
425
+ /** Toggle fold on a heading block */
426
+ toggleFold(headingBlockId: string): void;
427
+ /** Fold a heading section */
428
+ foldBlock(headingBlockId: string): void;
429
+ /** Unfold a heading section */
430
+ unfoldBlock(headingBlockId: string): void;
431
+ /** Fold all headings */
432
+ foldAll(): void;
433
+ /** Unfold all headings */
434
+ unfoldAll(): void;
435
+ /** Check if a heading is folded */
436
+ isFolded(headingBlockId: string): boolean;
437
+ /** Check if a block is hidden by a fold */
438
+ isBlockHidden(blockId: string): boolean;
439
+ /** Load fold state (e.g. from localStorage on document open) */
440
+ loadFoldState(state: FoldState): void;
441
+ /** Get current fold state for persistence */
442
+ getFoldState(): FoldState;
443
+ private applyFoldVisibility;
444
+ /**
445
+ * Navigate backwards in the jumplist (Ctrl-O).
446
+ * Returns true if a jump was performed.
447
+ */
448
+ jumpBack(): boolean;
449
+ /**
450
+ * Navigate forwards in the jumplist (Ctrl-I).
451
+ * Returns true if a jump was performed.
452
+ */
453
+ jumpForward(): boolean;
454
+ /**
455
+ * Jump to the last edit position.
456
+ * Records current position in jumplist, then focuses the last edit.
457
+ * Returns true if a jump was performed.
458
+ */
459
+ jumpToLastEdit(): boolean;
460
+ /** Record the current cursor position in the jumplist before a jump */
461
+ recordJump(): void;
462
+ /** Whether there are entries to jump back to */
463
+ canJumpBack(): boolean;
464
+ /** Whether there are entries to jump forward to */
465
+ canJumpForward(): boolean;
466
+ /**
467
+ * Enable CRDT operation logging. Captures the current editor state as
468
+ * the initial snapshot and begins recording every subsequent edit.
469
+ * Returns the log instance.
470
+ */
471
+ enableCrdtLog(): CrdtLog;
472
+ /** Get the CRDT log, or null if not enabled */
473
+ getCrdtLog(): CrdtLog | null;
474
+ /** Whether replay mode is currently active */
475
+ get isReplayActive(): boolean;
476
+ /**
477
+ * Show the replay bar UI at the bottom of the editor.
478
+ * Automatically enables the CRDT log if not already enabled.
479
+ */
480
+ showReplayUI(): void;
481
+ /** Hide the replay bar UI */
482
+ hideReplayUI(): void;
483
+ /** Enter replay mode: save state, disable editing */
484
+ private enterReplayMode;
485
+ /** Exit replay mode: restore saved state, re-enable editing */
486
+ private exitReplayMode;
487
+ /** Seek to a specific position in the CRDT log */
488
+ private replaySeekTo;
489
+ /** Render peer cursors based on the current replay position */
490
+ private renderReplayCursors;
491
+ /** Step one operation forward in replay */
492
+ private replayStepForward;
493
+ /** Step one operation backward in replay */
494
+ private replayStepBackward;
495
+ /** Start auto-playing operations */
496
+ private replayPlay;
497
+ /** Pause auto-play */
498
+ private replayPause;
499
+ /** Apply a single CRDT operation in the given direction */
500
+ private applyCrdtOperation;
501
+ /**
502
+ * Replace all blocks in the editor with the given block state.
503
+ * Used by replay to restore state on exit.
504
+ */
505
+ private loadBlockState;
506
+ /**
507
+ * Set the local peer identity. All subsequent CRDT operations will be
508
+ * tagged with this peer ID. Call this before users start editing.
509
+ */
510
+ setLocalPeer(peer: CrdtPeer): void;
511
+ /** Get the local peer, or null if not set */
512
+ getLocalPeer(): CrdtPeer | null;
513
+ /**
514
+ * Register a remote peer. Their cursor will be rendered when
515
+ * `setRemoteCursor()` is called.
516
+ */
517
+ addPeer(peer: CrdtPeer): void;
518
+ /** Remove a remote peer and their cursor */
519
+ removePeer(peerId: string): void;
520
+ /** Get all registered peers (including local) */
521
+ getPeers(): CrdtPeer[];
522
+ /**
523
+ * Update a remote peer's cursor position. Pass null blockId to hide the cursor.
524
+ * When endOffset is provided and differs from offset, a selection highlight is rendered.
525
+ */
526
+ setRemoteCursor(peerId: string, blockId: string | null, offset?: number, endOffset?: number, endBlockId?: string): void;
527
+ /** Get all current remote cursor positions */
528
+ getRemoteCursors(): RemoteCursor[];
529
+ /**
530
+ * Apply a remote peer's operation to the editor.
531
+ * This applies the operation, records it in the CRDT log, and updates
532
+ * the remote peer's cursor to the operation's afterCursor.
533
+ */
534
+ applyRemoteOperation(op: CrdtOperation): void;
535
+ /** Schedule a microtask to render remote cursors (batches rapid updates) */
536
+ private scheduleRemoteCursorRender;
537
+ /** Render remote cursors into all blocks that have them */
538
+ private renderAllRemoteCursors;
539
+ /**
540
+ * Compute all peer cursor positions at a given replay position by
541
+ * replaying the operation log. Returns the last known cursor for
542
+ * each peer up to that point.
543
+ */
544
+ private computeReplayCursors;
545
+ /**
546
+ * Enable Automerge CRDT sync. Returns the AutomergeSync instance
547
+ * which provides the sync protocol API (generateSyncMessage,
548
+ * receiveSyncMessage, merge, save/load, etc.).
549
+ *
550
+ * Calling this multiple times returns the same instance.
551
+ */
552
+ enableAutomerge(options?: AutomergeSyncOptions): AutomergeSync;
553
+ /** Get the AutomergeSync instance, or null if not enabled */
554
+ getAutomergeSync(): AutomergeSync | null;
555
+ /**
556
+ * Update a block's content, metadata, and optionally type.
557
+ * Suppresses undo history and re-renders with cursor preservation.
558
+ * Used by AutomergeSync for remote changes and by consumers for
559
+ * streaming / progressive content updates.
560
+ */
561
+ updateBlockContent(blockId: string, content: AttributedString, metadata?: Record<string, unknown>, blockType?: string): void;
562
+ /**
563
+ * Apply a single undo action in the given direction.
564
+ * Called with _suppressHistory = true.
565
+ */
566
+ private applyUndoAction;
567
+ /** Record a single undo action (delegates to compound group if active) */
568
+ private recordUndoAction;
569
+ /** Create a snapshot of a block for undo storage */
570
+ private snapshotBlock;
571
+ /** Get the current cursor state, or null if nothing is focused */
572
+ private getCursorState;
573
+ /** Save the current cursor so it can be restored after an overlay is dismissed. */
574
+ saveOverlayCursor(): void;
575
+ /** Restore focus to the position saved before an overlay opened, then clear it. */
576
+ restoreOverlayCursor(): void;
577
+ /** Emit historyChanged event with current canUndo/canRedo state */
578
+ private emitHistoryChanged;
579
+ /** Listen to block:contentChanged to record transaction-based content changes */
580
+ private setupUndoContentListener;
581
+ /** Set up keyboard shortcuts for undo/redo and navigation history */
582
+ private setupUndoShortcuts;
583
+ /** Track block focus changes for the jumplist */
584
+ private setupJumpListTracking;
585
+ /** Re-render remote cursors after any DOM change (content, add, remove) and on scroll */
586
+ private setupRemoteCursorRefresh;
587
+ /** @internal Apply a pre-computed transaction result to a block */
588
+ applyTransactionToBlock(blockId: string, result: TransactionResult): void;
589
+ private registerBuiltInCommands;
590
+ destroy(): void;
591
+ private setupHashNavigation;
592
+ private navigateToHash;
593
+ /** Unsub callbacks for ToC event subscriptions */
594
+ private tocUnsubs;
595
+ private setupTableOfContents;
596
+ private setupEventHandlers;
597
+ private handleClickContainerMouseDown;
598
+ private handleMouseDown;
599
+ private handleMouseDrag;
600
+ /**
601
+ * Detect the block under the given viewport coordinates and update
602
+ * selection. Called from both mousemove (with event) and the auto-scroll
603
+ * RAF tick (without event).
604
+ */
605
+ private updateDragBlockUnderMouse;
606
+ /** Find the nearest scrollable ancestor of the editor root. */
607
+ private findScrollParent;
608
+ /** Start a RAF loop that auto-scrolls when the mouse is near viewport edges. */
609
+ private startDragAutoScroll;
610
+ /** Stop the drag auto-scroll RAF loop. */
611
+ private stopDragAutoScroll;
612
+ /**
613
+ * Re-focus the anchor block and create a text selection from the saved
614
+ * anchor offset to the position under the mouse cursor.
615
+ */
616
+ private restoreDragSelection;
617
+ /**
618
+ * Walk text nodes within a container and find the DOM node + offset
619
+ * for a given character offset.
620
+ */
621
+ private findTextPosition;
622
+ private handleMouseDragEnd;
623
+ private handleSplit;
624
+ private handleMerge;
625
+ private handleFocusNavigation;
626
+ private static MAX_INDENT_LEVEL;
627
+ private handleIndent;
628
+ private handleOutdent;
629
+ /** Enter normal mode on a single block (Escape from editing) */
630
+ private enterNormalMode;
631
+ /** Enter visual block mode from normal mode (v key or shift+arrow) */
632
+ private enterVisualBlockMode;
633
+ /** Enter visual block mode from insert mode (Shift+Arrow, mouse drag) */
634
+ private enterVisualBlockFromInsert;
635
+ /** Calculate the approximate number of blocks that fit in a page (viewport) */
636
+ private calculatePageJump;
637
+ /** Handle PageUp/PageDown — jump focus by approximately one viewport of blocks */
638
+ private handlePageJump;
639
+ /** Select all blocks (enter visual block mode spanning first to last) */
640
+ private selectAllBlocks;
641
+ /** Move a block up or down by one position */
642
+ private handleBlockMove;
643
+ private handleBlockSelectTo;
644
+ /** Action dispatch map for normal mode keybindings (single-block) */
645
+ private get normalModeActions();
646
+ /** Action dispatch map for visual block mode keybindings (multi-block) */
647
+ private get visualBlockModeActions();
648
+ private handleEditorKeyDown;
649
+ /**
650
+ * Handle keyboard input when no block is focused.
651
+ * Emits `editor:unfocusedInput` and optionally auto-focuses the last block.
652
+ */
653
+ private handleUnfocusedInput;
654
+ private deleteBlockSelection;
655
+ private buildMultiBlockSelection;
656
+ private applyBlockSelectionCSS;
657
+ private clearBlockSelectionCSS;
658
+ /** Exit to insert mode and focus a block */
659
+ private exitToInsertMode;
660
+ /** Exit to insert mode without focusing any block */
661
+ private exitToInsertModeSilent;
662
+ /** Exit visual block mode back to normal mode (Escape or v from visual) */
663
+ private exitVisualBlockToNormal;
664
+ /** Set editor mode and update CSS classes on root */
665
+ private setMode;
666
+ /** @internal Whether the editor is in block selection mode (normal or visual block) */
667
+ get isBlockSelecting(): boolean;
668
+ /** @internal Get the current editor mode */
669
+ get mode(): "insert" | "normal" | "visualBlock";
670
+ private openOrUpdateSlashMenu;
671
+ private closeSlashMenu;
672
+ private handleSlashMenuSelect;
673
+ private openOrUpdateEmojiPicker;
674
+ private closeEmojiPicker;
675
+ private commitEmoji;
676
+ /**
677
+ * Register a provider that supplies date suggestions when the user types
678
+ * after `@`. If no provider is set, the @ trigger shows only the calendar.
679
+ */
680
+ setDateSuggestionProvider(provider: DateSuggestionProvider): void;
681
+ /** Remove the date suggestion provider. */
682
+ removeDateSuggestionProvider(): void;
683
+ /**
684
+ * Register additional keybindings from the host application.
685
+ * Each binding adds a key sequence to the normal-mode binding map
686
+ * and registers its handler so the editor can dispatch it.
687
+ */
688
+ registerKeybindings(bindings: ExternalKeybinding[]): void;
689
+ /** Pass the current query to the date suggestion provider and update the picker. */
690
+ private updateAgendaSearch;
691
+ setBlockAgenda(blockId: string, role: "due" | "scheduled" | "event", date: string | null, recurrence?: {
692
+ interval: number;
693
+ unit: string;
694
+ anchor?: string;
695
+ fromCompletion?: boolean;
696
+ } | null): void;
697
+ /** @deprecated Use `setBlockAgenda` instead. */
698
+ setBlockRecurrence(blockId: string, recurrence: {
699
+ interval: number;
700
+ unit: string;
701
+ anchor?: string;
702
+ fromCompletion?: boolean;
703
+ } | null): void;
704
+ /** @deprecated Use `setBlockAgenda(blockId, "due", date)` instead. */
705
+ setBlockAgendaDate(blockId: string, agendaDate: string | null): void;
706
+ /** @deprecated Use `setBlockAgenda(blockId, role, null)` instead. */
707
+ removeBlockAgendaDate(blockId: string): void;
708
+ /** Open the date picker for a new agenda item (triggered by `@` in text) */
709
+ private openAgendaPicker;
710
+ /** Open the date picker for editing an existing agenda item (triggered by badge/label click) */
711
+ private openAgendaPickerForEdit;
712
+ private ensureAgendaPicker;
713
+ private registerAgendaScrollAndKeys;
714
+ private closeAgendaPicker;
715
+ private commitAgendaDate;
716
+ /**
717
+ * Register an autocomplete provider that supplies entries when `[[` is typed.
718
+ * Multiple providers can be registered; results are merged in order.
719
+ */
720
+ addAutoCompleteProvider(provider: AutoCompleteProvider): void;
721
+ /** Remove a previously-registered autocomplete provider by id. */
722
+ removeAutoCompleteProvider(id: string): boolean;
723
+ private openOrUpdateAutoComplete;
724
+ /** Search headings in the current document. */
725
+ private searchDocumentHeadings;
726
+ private commitAutoComplete;
727
+ private closeAutoComplete;
728
+ private linkClickHandler;
729
+ private touchEndHandler;
730
+ private blockRefHoverHandler;
731
+ private blockRefHoverEndHandler;
732
+ private setupLinkClickHandler;
733
+ private teardownLinkClickHandler;
734
+ /**
735
+ * Open a link, delegating to the consumer's `onLinkClick` callback if set.
736
+ * Falls back to `window.open()` in a new tab.
737
+ */
738
+ private activateLink;
739
+ /**
740
+ * Handle a click on a blockRef pill.
741
+ * Scrolls to the referenced block by default.
742
+ * Emits `blockRef:click` so external consumers can also react.
743
+ */
744
+ private activateBlockRef;
745
+ /** Returns true when two taps on the same element occur within 400ms. */
746
+ private isDoubleTap;
747
+ private setupInlineToolbar;
748
+ private setupLinkButton;
749
+ private showLinkPopover;
750
+ private _linkContext;
751
+ private applyLinkToSelection;
752
+ private removeLinkFromSelection;
753
+ private _highlightContext;
754
+ private setupHighlightButton;
755
+ private showHighlightPicker;
756
+ private applyHighlightToSelection;
757
+ private removeHighlightFromSelection;
758
+ private teardownInlineToolbar;
759
+ private handleSelectionChange;
760
+ /**
761
+ * Force-mount the block that owns the active text selection so the
762
+ * viewport never unloads it. Release the previous force-mount when
763
+ * the selection moves or collapses.
764
+ */
765
+ private updateSelectionForceMount;
766
+ private handleFormatKeyDown;
767
+ /** Apply inline formatting to the current selection */
768
+ private applyInlineFormat;
769
+ /** Apply inline formatting to a table cell via metadata */
770
+ private applyFormatToTableCell;
771
+ /** Clear pending marks from the tracked controller */
772
+ private clearPendingMarks;
773
+ private applyFormatToController;
774
+ /**
775
+ * Get the attributes that are common across the entire selection range.
776
+ * An attribute is "active" only if every character in the range has it.
777
+ * Checks all attribute keys used by registered toolbar buttons.
778
+ */
779
+ private getSelectionAttributes;
780
+ /** Get the selection range (start, end) within a block controller's content */
781
+ private getControllerSelectionRange;
782
+ /** Restore a text selection after re-rendering */
783
+ private restoreSelection;
784
+ /**
785
+ * Get attributes common across a selection range within an array of spans.
786
+ * Used for table cells where content is in metadata, not block content.
787
+ */
788
+ private getAttributesFromSpans;
789
+ /** Restore selection in a table cell after re-render */
790
+ private restoreTableCellSelection;
791
+ /** Get the block ID of the currently focused block, or null */
792
+ private getFocusedBlockId;
793
+ /** Find the BlockController that contains the given DOM node */
794
+ private findControllerForNode;
795
+ private getActionTargetBlockIds;
796
+ /** Map a conversion target (type + metadata) to a lucide icon HTML string */
797
+ private static convertTargetIcon;
798
+ /** Returns true if a key descriptor is a non-vim binding (modifier combos or named keys). */
799
+ private static isNonVimKey;
800
+ /** Format a key descriptor as a human-readable OS-aware hint string. */
801
+ private static formatKeyHint;
802
+ /** Return the display hint for the first non-vim keybinding for a command, or undefined. */
803
+ private getKeybindingHint;
804
+ private buildActionMenuItems;
805
+ /**
806
+ * Resolve block IDs for right-click context menu.
807
+ * If blocks are selected and the click is on a selected block, use the selection.
808
+ * Otherwise, use the single block under the click.
809
+ */
810
+ private resolveContextMenuBlockIds;
811
+ /** Build context menu items for given block IDs */
812
+ private buildContextMenuItems;
813
+ /** Add a custom item to the right-click context menu */
814
+ addContextMenuItem(entry: BlockContextMenuEntry): void;
815
+ /** Remove a custom item from the right-click context menu */
816
+ removeContextMenuItem(key: string): void;
817
+ private clipboardKeyHandler;
818
+ private setupClipboardShortcuts;
819
+ /**
820
+ * Read blocks from clipboard and paste AFTER the focused block as discrete
821
+ * new blocks (no content merging). Used by `p` in normal/visual modes.
822
+ */
823
+ private pasteBlocksFromClipboard;
824
+ /**
825
+ * Read blocks from clipboard and paste BEFORE the focused block as discrete
826
+ * new blocks. Used by `P` in normal/visual modes.
827
+ */
828
+ private pasteBlocksBeforeFromClipboard;
829
+ /**
830
+ * Walk all blocks and set `<ol start="N">` on consecutive ordered list
831
+ * blocks at the same indent level. Non-list blocks or a change in
832
+ * indent level reset the counter.
833
+ */
834
+ private recomputeListIndices;
835
+ /**
836
+ * Focus a table block's cell directly, bypassing block-level focus.
837
+ * @param direction "down" focuses first row, "up" focuses last row.
838
+ */
839
+ private focusTableCell;
840
+ private focusNonTextBlock;
841
+ private blurNonTextBlock;
842
+ /** Find the nearest text block index in the given direction (-1 or 1). */
843
+ private findTextBlockIndex;
844
+ private removeImageDropZone;
845
+ private showDropRejectOverlay;
846
+ private removeDropRejectOverlay;
847
+ private setupMediaBlockHandlers;
848
+ private setupSearchShortcut;
849
+ /** Open (or re-focus) the search panel. */
850
+ openSearch(): void;
851
+ /** Close the search panel. */
852
+ closeSearch(): void;
853
+ /** Highlight ALL search matches dimly across all blocks. */
854
+ private highlightAllSearchMatches;
855
+ /** Add bright highlight to the current/focused search match. */
856
+ private highlightSearchMatch;
857
+ /** Remove bright highlight from the current match (keep dim highlights). */
858
+ private clearCurrentSearchHighlight;
859
+ /** Clear ALL search highlights (dim + bright) from all blocks. */
860
+ private clearSearchHighlights;
861
+ private replaceSearchMatch;
862
+ private replaceAllSearchMatches;
863
+ private getPlugin;
864
+ }