Input System
The input system translates browser events into editor transactions. It consists of several registries and handlers that plugins use to register keymaps, input rules, and file handlers.
InputManager
Section titled “InputManager”Facade that coordinates all input-related handlers. Created internally by the editor.
import { InputManager } from '@notectl/core';import type { InputManagerDeps } from '@notectl/core';InputManagerDeps
Section titled “InputManagerDeps”interface InputManagerDeps { readonly getState: () => EditorState; readonly dispatch: (tr: Transaction) => void; readonly syncSelection: () => void; readonly undo: () => void; readonly redo: () => void; readonly schemaRegistry?: SchemaRegistry; readonly keymapRegistry?: KeymapRegistry; readonly inputRuleRegistry?: InputRuleRegistry; readonly fileHandlerRegistry?: FileHandlerRegistry; readonly isReadOnly: () => boolean; readonly getPasteInterceptors?: () => readonly PasteInterceptorEntry[]; readonly getTextDirection?: (element: HTMLElement) => 'ltr' | 'rtl'; readonly navigateFromGapCursor?: ( state: EditorState, direction: 'left' | 'right' | 'up' | 'down', container?: HTMLElement, ) => Transaction | null;}Constructor
Section titled “Constructor”const manager = new InputManager(contentElement, deps);Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
compositionTracker | CompositionTracker | Tracks IME composition state |
Methods
Section titled “Methods”| Method | Description |
|---|---|
destroy() | Removes all event listeners and cleans up resources |
KeymapRegistry
Section titled “KeymapRegistry”Stores keymaps registered by plugins, organized by priority level.
import { KeymapRegistry } from '@notectl/core';
const registry = new KeymapRegistry();Methods
Section titled “Methods”| Method | Signature | Description |
|---|---|---|
registerKeymap | (keymap: Keymap, options?: KeymapOptions) => void | Register a keymap at a priority level |
getKeymaps | () => readonly Keymap[] | Get all keymaps (flat list) |
getKeymapsByPriority | () => { context, navigation, default } | Get keymaps grouped by priority |
removeKeymap | (keymap: Keymap) => void | Remove a specific keymap |
clear | () => void | Remove all keymaps |
Priority System
Section titled “Priority System”Keymaps are dispatched in priority order: context > navigation > default.
type KeymapPriority = 'context' | 'navigation' | 'default';
interface KeymapOptions { readonly priority?: KeymapPriority;}| Priority | Use Case |
|---|---|
context | Context-sensitive shortcuts (e.g. code block Tab handling) |
navigation | Caret/selection movement (e.g. arrow keys, Home/End) |
default | General commands (e.g. Ctrl+B for bold) — this is the default |
Keymap Types
Section titled “Keymap Types”type KeymapHandler = () => boolean;type Keymap = Readonly<Record<string, KeymapHandler>>;A Keymap maps key descriptors to handlers. Handlers return true if they consumed the event.
Key descriptors use the format Mod-B, Shift-Enter, Alt-ArrowUp, etc. Mod maps to Cmd on macOS and Ctrl on other platforms.
normalizeKeyDescriptor(e)
Section titled “normalizeKeyDescriptor(e)”Normalizes a KeyboardEvent into a consistent key descriptor string. Format: "Mod-Shift-Alt-Key" where Mod = Ctrl/Cmd.
import { normalizeKeyDescriptor } from '@notectl/core';
// Takes a KeyboardEvent, not a stringelement.addEventListener('keydown', (e) => { const descriptor = normalizeKeyDescriptor(e); // e.g. 'Mod-B', 'Mod-Shift-1', 'Enter', 'Space'});function normalizeKeyDescriptor(e: KeyboardEvent): stringInputRuleRegistry
Section titled “InputRuleRegistry”Stores pattern-based text transform rules registered by plugins.
import { InputRuleRegistry } from '@notectl/core';
const registry = new InputRuleRegistry();Methods
Section titled “Methods”| Method | Signature | Description |
|---|---|---|
registerInputRule | (rule: InputRule) => void | Register an input rule |
getInputRules | () => readonly InputRule[] | Get all registered rules |
removeInputRule | (rule: InputRule) => void | Remove a specific rule |
clear | () => void | Remove all rules |
InputRule Interface
Section titled “InputRule Interface”interface InputRule { readonly pattern: RegExp; handler( state: EditorState, match: RegExpMatchArray, start: number, end: number, ): Transaction | null;}Input rules are matched against text as the user types. When a pattern matches, the handler is called with the match and can return a transaction to apply.
Example — auto-convert # to heading:
const headingRule: InputRule = { pattern: /^(#{1,6})\s$/, handler(state, match, start, end) { const level = match[1].length; return state.transaction('input') .deleteTextAt(blockId, start, end) .setBlockType(blockId, nodeType('heading'), { level }) .build(); },};FileHandlerRegistry
Section titled “FileHandlerRegistry”Manages handlers for dropped or pasted files, matched by MIME type patterns.
import { FileHandlerRegistry } from '@notectl/core';
const registry = new FileHandlerRegistry();Methods
Section titled “Methods”| Method | Signature | Description |
|---|---|---|
registerFileHandler | (pattern: string, handler: FileHandler) => void | Register a handler for a MIME pattern |
getFileHandlers | () => readonly FileHandlerEntry[] | Get all registered handlers |
matchFileHandlers | (mimeType: string) => FileHandler[] | Find handlers matching a MIME type |
removeFileHandler | (handler: FileHandler) => void | Remove a specific handler |
clear | () => void | Remove all handlers |
type FileHandler = ( file: File, position: Position | null,) => boolean | Promise<boolean>;
interface FileHandlerEntry { readonly pattern: string; readonly handler: FileHandler;}MIME Pattern Matching
Section titled “MIME Pattern Matching”Patterns support wildcards:
| Pattern | Matches |
|---|---|
image/* | image/png, image/jpeg, etc. |
text/plain | Only text/plain |
*/* | Any MIME type |
Example:
registry.registerFileHandler('image/*', async (file, position) => { const url = URL.createObjectURL(file); // Insert image block at position return true; // handled});ClipboardHandler
Section titled “ClipboardHandler”Handles copy and cut operations, serializing the selection to text/plain and text/html clipboard formats.
import { ClipboardHandler } from '@notectl/core';
const handler = new ClipboardHandler(element, { getState: () => editor.getState(), dispatch: (tr) => editor.dispatch(tr), schemaRegistry, syncSelection: () => { /* ... */ }, isReadOnly: () => false,});Constructor Options
Section titled “Constructor Options”The constructor accepts an options object with the following shape (the type itself is not exported):
{ readonly getState: () => EditorState; readonly dispatch: (tr: Transaction) => void; readonly schemaRegistry?: SchemaRegistry; readonly syncSelection?: () => void; readonly isReadOnly?: () => boolean;}Methods
Section titled “Methods”| Method | Description |
|---|---|
destroy() | Removes clipboard event listeners |
The ClipboardHandler automatically listens for copy and cut events on the provided element. For cut operations, it dispatches a deleteSelectionCommand after writing to the clipboard.
CompositionTracker
Section titled “CompositionTracker”Tracks IME (Input Method Editor) composition state for languages like Chinese, Japanese, and Korean.
import { CompositionTracker } from '@notectl/core';
const tracker = new CompositionTracker();Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
isComposing | boolean | Whether an IME composition is active |
activeBlockId | BlockId | null | The block where composition is happening |
Methods
Section titled “Methods”| Method | Signature | Description |
|---|---|---|
start | (blockId: BlockId) => void | Begin composition tracking |
end | () => void | End composition tracking |
CompositionState Interface
Section titled “CompositionState Interface”interface CompositionState { readonly isComposing: boolean; readonly activeBlockId: BlockId | null;}The CompositionTracker implements this interface. During composition, the editor defers DOM reconciliation to avoid interfering with the IME.
Related
Section titled “Related”- Plugin Interface —
registerKeymap(),registerInputRule(),registerFileHandler() - Commands — commands dispatched by keymaps
- Keyboard Navigation — guide to keyboard shortcuts