creo-edit 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +169 -0
- package/dist/clipboard/drop.d.ts +17 -0
- package/dist/clipboard/htmlParser.d.ts +18 -0
- package/dist/clipboard/htmlSerializer.d.ts +9 -0
- package/dist/commands/imageCommands.d.ts +32 -0
- package/dist/commands/insertCommands.d.ts +33 -0
- package/dist/commands/listCommands.d.ts +19 -0
- package/dist/commands/markCommands.d.ts +21 -0
- package/dist/commands/navigationCommands.d.ts +27 -0
- package/dist/commands/structuralCommands.d.ts +22 -0
- package/dist/commands/textCommands.d.ts +18 -0
- package/dist/controller/history.d.ts +31 -0
- package/dist/controller/navigation.d.ts +18 -0
- package/dist/controller/selection.d.ts +25 -0
- package/dist/controller/wordBoundary.d.ts +25 -0
- package/dist/createEditor.d.ts +252 -0
- package/dist/dom/anchorMap.d.ts +27 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +7833 -0
- package/dist/index.js.map +72 -0
- package/dist/input/keymap.d.ts +47 -0
- package/dist/input/mobile.d.ts +13 -0
- package/dist/input/nativeInput.d.ts +27 -0
- package/dist/markdown/serialize.d.ts +2 -0
- package/dist/model/blockText.d.ts +42 -0
- package/dist/model/cellAccess.d.ts +2 -0
- package/dist/model/doc.d.ts +45 -0
- package/dist/model/fractional.d.ts +57 -0
- package/dist/model/rebalance.d.ts +12 -0
- package/dist/model/types.d.ts +133 -0
- package/dist/plugin/anchorCodec.d.ts +18 -0
- package/dist/plugin/atomic.d.ts +2 -0
- package/dist/plugin/builtin.d.ts +10 -0
- package/dist/plugin/decorations.d.ts +35 -0
- package/dist/plugin/htmlCodec.d.ts +8 -0
- package/dist/plugin/keymapMatch.d.ts +2 -0
- package/dist/plugin/registry.d.ts +29 -0
- package/dist/plugin/runsAt.d.ts +9 -0
- package/dist/plugin/serializeCodec.d.ts +6 -0
- package/dist/plugin/triggers.d.ts +33 -0
- package/dist/plugin/types.d.ts +188 -0
- package/dist/plugins/add-block/index.d.ts +17 -0
- package/dist/plugins/calendar/index.d.ts +7 -0
- package/dist/plugins/calendar/view.d.ts +29 -0
- package/dist/plugins/cells/codecs.d.ts +6 -0
- package/dist/plugins/cells/commands.d.ts +5 -0
- package/dist/plugins/cells/controls.d.ts +3 -0
- package/dist/plugins/cells/htmlCodec.d.ts +6 -0
- package/dist/plugins/cells/index.d.ts +3 -0
- package/dist/plugins/cells/views.d.ts +27 -0
- package/dist/plugins/drag-handle/index.d.ts +6 -0
- package/dist/plugins/infinite-scroll/index.d.ts +44 -0
- package/dist/plugins/md-shortcuts/index.d.ts +2 -0
- package/dist/plugins/search/engine.d.ts +33 -0
- package/dist/plugins/search/highlight.d.ts +13 -0
- package/dist/plugins/search/index.d.ts +5 -0
- package/dist/plugins/search/navigate.d.ts +15 -0
- package/dist/plugins/search/styles.d.ts +1 -0
- package/dist/plugins/search/types.d.ts +73 -0
- package/dist/plugins/search/ui.d.ts +2 -0
- package/dist/plugins/slash/index.d.ts +12 -0
- package/dist/plugins/slash/items.d.ts +21 -0
- package/dist/plugins/slash/menu.d.ts +17 -0
- package/dist/plugins/styles.css +233 -0
- package/dist/render/DocView.d.ts +7 -0
- package/dist/render/InlineRunsView.d.ts +7 -0
- package/dist/render/blocks/CodeBlockView.d.ts +7 -0
- package/dist/render/blocks/HeadingView.d.ts +7 -0
- package/dist/render/blocks/ImageView.d.ts +8 -0
- package/dist/render/blocks/ListItemView.d.ts +7 -0
- package/dist/render/blocks/ParagraphView.d.ts +7 -0
- package/dist/virtual/VirtualDoc.d.ts +28 -0
- package/dist/virtual/heightIndex.d.ts +36 -0
- package/package.json +53 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/createEditor.ts", "../src/model/blockText.ts", "../src/model/fractional.ts", "../src/model/doc.ts", "../src/plugin/atomic.ts", "../src/controller/selection.ts", "../src/controller/navigation.ts", "../src/commands/navigationCommands.ts", "../src/commands/insertCommands.ts", "../src/commands/imageCommands.ts", "../src/clipboard/drop.ts", "../src/plugin/htmlCodec.ts", "../src/clipboard/htmlParser.ts", "../src/input/mobile.ts", "../src/commands/listCommands.ts", "../src/commands/markCommands.ts", "../src/plugin/runsAt.ts", "../src/commands/structuralCommands.ts", "../src/commands/textCommands.ts", "../src/controller/history.ts", "../src/model/rebalance.ts", "../src/input/keymap.ts", "../src/plugin/anchorCodec.ts", "../src/dom/anchorMap.ts", "../src/clipboard/htmlSerializer.ts", "../src/plugin/keymapMatch.ts", "../src/input/nativeInput.ts", "../src/render/DocView.ts", "../src/plugin/serializeCodec.ts", "../src/plugin/registry.ts", "../src/virtual/VirtualDoc.ts", "../src/virtual/heightIndex.ts", "../src/plugin/builtin.ts", "../src/render/blocks/ParagraphView.ts", "../src/render/InlineRunsView.ts", "../src/render/blocks/HeadingView.ts", "../src/render/blocks/ListItemView.ts", "../src/render/blocks/CodeBlockView.ts", "../src/render/blocks/ImageView.ts", "../src/plugins/cells/codecs.ts", "../src/plugins/cells/htmlCodec.ts", "../src/plugins/cells/views.ts", "../src/plugins/cells/commands.ts", "../src/plugins/cells/controls.ts", "../src/plugins/cells/index.ts", "../src/plugin/triggers.ts", "../src/plugin/decorations.ts", "../src/plugins/slash/items.ts", "../src/plugins/slash/menu.ts", "../src/plugins/slash/index.ts", "../src/plugins/drag-handle/index.ts", "../src/plugins/add-block/index.ts", "../src/plugins/md-shortcuts/index.ts", "../src/plugins/calendar/view.ts", "../src/plugins/calendar/index.ts", "../src/plugins/infinite-scroll/index.ts", "../src/plugins/search/engine.ts", "../src/plugins/search/highlight.ts", "../src/plugins/search/navigate.ts", "../src/plugins/search/styles.ts", "../src/plugins/search/ui.ts", "../src/plugins/search/index.ts", "../src/markdown/serialize.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { _ } from \"creo\";\nimport { div, store, view } from \"creo\";\nimport type { PublicView, Store } from \"creo\";\nimport { moveTo } from \"./commands/navigationCommands\";\nimport { attachDrop, type DropHandle } from \"./clipboard/drop\";\nimport { parseHTML } from \"./clipboard/htmlParser\";\nimport {\n attachVisualViewport,\n type ViewportHandle,\n} from \"./input/mobile\";\nimport {\n endOfBlock,\n endOfDocAnchor,\n homeOfBlock,\n homeOfDoc,\n} from \"./controller/navigation\";\nimport { isAtomicBlockType } from \"./plugin/atomic\";\nimport {\n insertColumns as cmdInsertColumns,\n insertImage as cmdInsertImage,\n insertTable as cmdInsertTable,\n} from \"./commands/insertCommands\";\nimport {\n indentList as cmdIndentList,\n outdentList as cmdOutdentList,\n toggleList as cmdToggleList,\n} from \"./commands/listCommands\";\nimport { toggleMark as cmdToggleMark } from \"./commands/markCommands\";\nimport {\n mergeBackward as cmdMergeBackward,\n mergeForward as cmdMergeForward,\n setBlockType as cmdSetBlockType,\n splitBlock as cmdSplitBlock,\n type SetBlockTypePayload,\n} from \"./commands/structuralCommands\";\nimport {\n deleteBackward as cmdDeleteBackward,\n deleteForward as cmdDeleteForward,\n insertText as cmdInsertText,\n} from \"./commands/textCommands\";\nimport { endOfDoc } from \"./controller/selection\";\nimport { createHistory, type History } from \"./controller/history\";\nimport { attachAutoRebalance } from \"./model/rebalance\";\nimport {\n attachNativeInput,\n type NativeInputHandle,\n} from \"./input/nativeInput\";\nimport { docFromBlocks, emptyDoc, insertManyAt, newBlockId } from \"./model/doc\";\nimport type {\n Anchor,\n Block,\n BlockId,\n BlockSpec,\n DistOmit,\n DocState,\n InlineRun,\n Mark,\n Selection,\n} from \"./model/types\";\n\n/**\n * Input shape for `appendBlocks` / `prependBlocks` — same as `BlockSpec`\n * but with `id` optional. The editor generates an id when missing so most\n * callers can stay terse:\n *\n * editor.appendBlocks([{ type: \"p\", runs: [] }]);\n */\nexport type BlockInsertInput = DistOmit<BlockSpec, \"id\"> & { id?: BlockId };\nimport { DocView } from \"./render/DocView\";\nimport { VirtualDoc } from \"./virtual/VirtualDoc\";\nimport { defaultPlugins } from \"./plugin/builtin\";\nimport { Registry } from \"./plugin/registry\";\nimport {\n deserializeBlock as registryDeserializeBlock,\n serializeBlock as registrySerializeBlock,\n} from \"./plugin/serializeCodec\";\nimport { TriggerManager } from \"./plugin/triggers\";\nimport { DecorationManager } from \"./plugin/decorations\";\nimport type { EditorPlugin } from \"./plugin/types\";\n\nlet __editorIdCounter = 0;\n\n// ---------------------------------------------------------------------------\n// Public-facing types\n// ---------------------------------------------------------------------------\n\nexport type SerializedRun = {\n text: string;\n marks?: string[]; // mark identifiers\n};\n\n/**\n * SerializedBlock — wire shape the editor reads from `setDoc()` and emits\n * from `toJSON()`. Built-in block types are listed exhaustively here so the\n * compiler still catches typos in user code. Plugins that introduce new\n * block types extend the runtime serialize codec registry without changing\n * this type — their entries appear as the catch-all `Record<string, unknown>`\n * branch.\n */\nexport type SerializedBlock =\n | { id?: string; type: \"p\"; runs: SerializedRun[] }\n | { id?: string; type: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\"; runs: SerializedRun[] }\n | {\n id?: string;\n type: \"li\";\n ordered: boolean;\n depth?: 0 | 1 | 2 | 3;\n runs: SerializedRun[];\n }\n | {\n id?: string;\n type: \"code\";\n runs: SerializedRun[];\n lang?: string;\n }\n | {\n id?: string;\n type: \"img\";\n src: string;\n alt?: string;\n width?: number;\n height?: number;\n }\n | {\n id?: string;\n type: \"table\";\n rows: number;\n cols: number;\n cells: SerializedRun[][][];\n }\n | {\n id?: string;\n type: \"columns\";\n cols: number;\n cells: SerializedRun[][];\n }\n | {\n id?: string;\n type: \"calendar\";\n date: string;\n days: number;\n }\n | {\n id?: string;\n type: \"date-marker\";\n date: string;\n };\n\n/**\n * Catch-all shape for plugin-introduced block types. Plugins serializing\n * outside the built-in union should cast through this when constructing\n * `SerializedDoc.blocks` — the runtime serialize codec registry handles\n * dispatch by `type` and ignores extra fields.\n */\nexport type ExternalSerializedBlock = {\n id?: string;\n type: string;\n [k: string]: unknown;\n};\n\nexport type SerializedDoc = {\n blocks: SerializedBlock[];\n};\n\nexport type EditorViewProps = {\n class?: string;\n};\n\n/**\n * Built-in command shape. Plugin commands dispatch through the same\n * `dispatch()` entry point using the `{ t: string; payload?: unknown }`\n * fallback shape — see `Editor.dispatch` below.\n */\nexport type Command =\n | { t: \"noop\" }\n | { t: \"insertText\"; text: string }\n | { t: \"deleteBackward\" }\n | { t: \"deleteForward\" }\n | { t: \"splitBlock\" }\n | { t: \"mergeBackward\" }\n | { t: \"mergeForward\" }\n | { t: \"setBlockType\"; payload: SetBlockTypePayload }\n | { t: \"toggleMark\"; mark: Mark }\n | { t: \"toggleList\"; ordered: boolean }\n | { t: \"indentList\" }\n | { t: \"outdentList\" }\n | {\n t: \"insertImage\";\n src: string;\n alt?: string;\n width?: number;\n height?: number;\n }\n | { t: \"insertTable\"; rows: number; cols: number }\n | { t: \"insertColumns\"; cols: number }\n | { t: \"tableInsertRow\"; where: \"above\" | \"below\" }\n | { t: \"tableInsertCol\"; where: \"before\" | \"after\" }\n | { t: \"tableRemoveRow\" }\n | { t: \"tableRemoveCol\" }\n | { t: \"moveCursor\"; to: Anchor; extend?: boolean };\n\n/** Anything dispatchable — the typed `Command` union for built-ins, plus the\n * open `{ t: string; payload?: unknown }` shape for plugin commands. */\nexport type DispatchableCommand =\n | Command\n | { t: string; payload?: unknown };\n\n/**\n * Editing mode.\n *\n * - `\"wysiwyg\"`: rich-text editor with all blocks rendered visually.\n * - `\"md\"`: raw markdown source view (the doc is serialized to markdown\n * and edited as plain text); markdown-shortcut input rules also active\n * when the user re-enters wysiwyg via mdShortcutsPlugin.\n *\n * Replaces the older `\"regular\" | \"mono\"` cosmetic flag — host apps that\n * want a monospaced editor should add their own CSS class.\n */\nexport type EditorMode = \"wysiwyg\" | \"md\";\n\nexport type EditorOptions = {\n initial?: SerializedDoc;\n uploadImage?: (f: File) => Promise<string>;\n /**\n * Enable virtualized rendering — only blocks intersecting the viewport\n * are mounted. Recommended for documents with > ~500 blocks. The host\n * page must put a scroll container around the editor for this to work.\n */\n virtualized?: boolean;\n /** Estimated block height (px) when virtualized — default 32. */\n virtualEstimatedHeight?: number;\n /**\n * Initial editing mode — see `EditorMode`. Defaults to `\"wysiwyg\"`.\n * Toggle at runtime via `editor.setMode(...)`.\n */\n mode?: EditorMode;\n /**\n * Plugins to install in addition to the default set (paragraph, heading,\n * list, code-block, image, cells). Registered AFTER built-ins so plugin\n * codecs can override built-in HTML matchers by registering more specific\n * tag matchers.\n */\n plugins?: EditorPlugin[];\n};\n\nexport type Editor = {\n docStore: Store<DocState>;\n selStore: Store<Selection>;\n /** Dispatch any registered command — typed built-ins or plugin commands. */\n dispatch: (cmd: DispatchableCommand) => void;\n undo: () => void;\n redo: () => void;\n EditorView: PublicView<EditorViewProps, void>;\n setDocFromHTML: (html: string) => void;\n /**\n * Replace the entire document with a SerializedDoc. Resets selection to\n * the end and clears history — used for swapping content on top of a\n * long-lived editor instance (e.g. routing between different docs in a\n * docs site without reallocating the input pipeline & DOM listeners).\n */\n setDoc: (doc: SerializedDoc) => void;\n toJSON: () => SerializedDoc;\n /**\n * Append `specs` to the end of the doc. Preserves all existing block\n * identities (no full rebuild) so existing renders stay; the renderer's\n * identity-based shouldUpdate skips them. Returns the assigned block ids.\n * Specs may omit `id`; an id is generated when missing. Selection is left\n * untouched — callers move the caret separately if they want it on a new\n * block.\n */\n appendBlocks: (specs: BlockInsertInput[]) => BlockId[];\n /**\n * Prepend `specs` to the start of the doc. Same identity-preserving\n * mutation as `appendBlocks`. NOTE: prepending grows the doc upward; the\n * viewport will jump unless the host re-anchors scrollTop. The\n * `infiniteScrollPlugin` does this anchoring automatically; manual\n * callers can capture `scrollHeight` + `scrollTop` before the call and\n * adjust after the next animation frame.\n */\n prependBlocks: (specs: BlockInsertInput[]) => BlockId[];\n // Imperative focus / blur — wired in M3+.\n focus: () => void;\n blur: () => void;\n /** Read or change the editing mode (wysiwyg ↔ md). */\n getMode: () => EditorMode;\n setMode: (mode: EditorMode) => void;\n /** Plugin registry for this editor instance — exposed for advanced\n * consumers (devtools, the M3 trigger manager, etc.). */\n registry: Registry;\n /**\n * Scroll a block into view by id. Works for both virtualized and\n * non-virtualized editors — for virtualized off-screen blocks, jumps\n * the scroll container to the height-index-resolved Y. Used by the\n * search plugin's jump-to-match; safe for any host code that wants\n * to focus a specific block (e.g. permalink navigation).\n */\n scrollToBlock: (\n blockId: BlockId,\n opts?: { block?: \"start\" | \"center\" | \"end\" | \"nearest\"; behavior?: ScrollBehavior },\n ) => void;\n};\n\n// ---------------------------------------------------------------------------\n// Serialization helpers — registry-driven per-block.\n// ---------------------------------------------------------------------------\n\nfunction deserializeDoc(s: SerializedDoc): DocState {\n const blocks: BlockSpec[] = [];\n for (const sb of s.blocks) {\n const id = sb.id ?? newBlockId();\n const decoded = registryDeserializeBlock(sb.type, sb, id);\n if (decoded) blocks.push(decoded);\n // Unknown block types are silently dropped — same posture the old\n // exhaustive switch took for unrecognized variants.\n }\n return docFromBlocks(blocks);\n}\n\nfunction serializeDoc(doc: DocState): SerializedDoc {\n const blocks: SerializedBlock[] = [];\n for (const id of doc.order) {\n const b = doc.byId.get(id)!;\n const enc = registrySerializeBlock(b);\n if (enc) blocks.push(enc as SerializedBlock);\n }\n return { blocks };\n}\n\n// ---------------------------------------------------------------------------\n// createEditor\n// ---------------------------------------------------------------------------\n\nfunction historyTagFor(cmd: DispatchableCommand): string {\n switch (cmd.t) {\n case \"insertText\":\n return \"text:insert\";\n case \"deleteBackward\":\n return \"text:deleteBack\";\n case \"deleteForward\":\n return \"text:deleteFwd\";\n default:\n return cmd.t;\n }\n}\n\nfunction defaultSelection(doc: DocState): Selection {\n return { kind: \"caret\", at: endOfDoc(doc) };\n}\n\nexport function createEditor(opts: EditorOptions = {}): Editor {\n const editorId = `creo-edit-${++__editorIdCounter}`;\n\n // Install plugins BEFORE we touch any block-bearing state so the\n // serialize codec, anchor codecs, and view registry are ready.\n const registry = new Registry();\n for (const p of defaultPlugins) registry.install(p);\n if (opts.plugins) for (const p of opts.plugins) registry.install(p);\n\n const initialDoc = opts.initial\n ? deserializeDoc(opts.initial)\n : seedEmpty();\n const docStore = store.new<DocState>(initialDoc);\n\n // Selection store — separate from doc so caret movement doesn't dirty the\n // document subscribers (and vice versa).\n const selStore = store.new<Selection>(defaultSelection(initialDoc));\n\n let nativeInput: NativeInputHandle | null = null;\n let drop: DropHandle | null = null;\n let viewport: ViewportHandle | null = null;\n let decorations: DecorationManager | null = null;\n void nativeInput;\n void drop;\n void viewport;\n void decorations;\n\n const history: History = createHistory({ docStore, selStore });\n // Microtask rebalance — keeps fractional indices short under adversarial\n // insertion patterns. No-op on every doc change unless any key has\n // outgrown the soft threshold.\n attachAutoRebalance(docStore);\n\n const ctx = { docStore, selStore };\n\n // Trigger manager — needs `dispatch` for plugin trigger callbacks. Defined\n // before dispatch so the dispatch closure can reference it; the manager\n // gets the dispatch fn injected by closure rather than via `this`.\n let dispatchRef: ((cmd: DispatchableCommand) => void) | null = null;\n const triggers = new TriggerManager({\n registry,\n docStore,\n selStore,\n dispatch: (cmd) => dispatchRef?.(cmd),\n });\n\n const dispatch = (cmd: DispatchableCommand): void => {\n // Snapshot for undo BEFORE mutating. Tag drives coalescing.\n history.record(historyTagFor(cmd));\n switch (cmd.t) {\n case \"noop\":\n return;\n case \"insertText\":\n cmdInsertText(ctx, (cmd as Extract<Command, { t: \"insertText\" }>).text);\n return;\n case \"deleteBackward\":\n cmdDeleteBackward(ctx);\n return;\n case \"deleteForward\":\n cmdDeleteForward(ctx);\n return;\n case \"splitBlock\":\n cmdSplitBlock(ctx);\n return;\n case \"mergeBackward\":\n cmdMergeBackward(ctx);\n return;\n case \"mergeForward\":\n cmdMergeForward(ctx);\n return;\n case \"setBlockType\":\n cmdSetBlockType(ctx, (cmd as Extract<Command, { t: \"setBlockType\" }>).payload);\n return;\n case \"toggleMark\":\n cmdToggleMark(ctx, (cmd as Extract<Command, { t: \"toggleMark\" }>).mark);\n return;\n case \"toggleList\":\n cmdToggleList(ctx, (cmd as Extract<Command, { t: \"toggleList\" }>).ordered);\n return;\n case \"indentList\":\n cmdIndentList(ctx);\n return;\n case \"outdentList\":\n cmdOutdentList(ctx);\n return;\n case \"insertImage\": {\n const c = cmd as Extract<Command, { t: \"insertImage\" }>;\n cmdInsertImage(ctx, { src: c.src, alt: c.alt, width: c.width, height: c.height });\n return;\n }\n case \"insertTable\": {\n const c = cmd as Extract<Command, { t: \"insertTable\" }>;\n cmdInsertTable(ctx, { rows: c.rows, cols: c.cols });\n return;\n }\n case \"insertColumns\": {\n const c = cmd as Extract<Command, { t: \"insertColumns\" }>;\n cmdInsertColumns(ctx, { cols: c.cols });\n return;\n }\n case \"tableInsertRow\":\n registry.runCommand(\"tableInsertRow\", { where: (cmd as Extract<Command, { t: \"tableInsertRow\" }>).where }, ctx);\n return;\n case \"tableInsertCol\":\n registry.runCommand(\"tableInsertCol\", { where: (cmd as Extract<Command, { t: \"tableInsertCol\" }>).where }, ctx);\n return;\n case \"tableRemoveRow\":\n registry.runCommand(\"tableRemoveRow\", undefined, ctx);\n return;\n case \"tableRemoveCol\":\n registry.runCommand(\"tableRemoveCol\", undefined, ctx);\n return;\n case \"moveCursor\": {\n const c = cmd as Extract<Command, { t: \"moveCursor\" }>;\n moveTo(ctx, c.to, c.extend === true);\n return;\n }\n default: {\n // Plugin command — route through the registry. Payload shape is\n // plugin-defined; built-ins handled above don't reach this branch.\n const payload = (cmd as { payload?: unknown }).payload;\n registry.runCommand(cmd.t, payload, ctx);\n return;\n }\n }\n };\n\n dispatchRef = dispatch;\n\n const undo = (): void => {\n history.undo();\n };\n const redo = (): void => {\n history.redo();\n };\n\n const setDocFromHTML = (html: string): void => {\n const blocks = parseHTML(html);\n if (blocks.length === 0) return;\n docStore.set(docFromBlocks(blocks));\n selStore.set(defaultSelection(docStore.get()));\n history.reset();\n };\n\n const setDoc = (s: SerializedDoc): void => {\n docStore.set(deserializeDoc(s));\n selStore.set(defaultSelection(docStore.get()));\n history.reset();\n };\n\n const toJSON = (): SerializedDoc => serializeDoc(docStore.get());\n\n // ---------------------------------------------------------------------\n // appendBlocks / prependBlocks — identity-preserving doc growth used by\n // the infinite-scroll plugin and any host that wants to add blocks\n // without disturbing existing block renders or the caret.\n // ---------------------------------------------------------------------\n const ensureIds = (specs: BlockInsertInput[]): BlockSpec[] => {\n return specs.map(\n (s) => (s.id ? s : { ...s, id: newBlockId() }) as BlockSpec,\n );\n };\n const appendBlocks = (specs: BlockInsertInput[]): BlockId[] => {\n if (specs.length === 0) return [];\n const withIds = ensureIds(specs);\n const doc = docStore.get();\n docStore.set(insertManyAt(doc, doc.order.length, withIds));\n return withIds.map((s) => s.id!);\n };\n const prependBlocks = (specs: BlockInsertInput[]): BlockId[] => {\n if (specs.length === 0) return [];\n const withIds = ensureIds(specs);\n const doc = docStore.get();\n docStore.set(insertManyAt(doc, 0, withIds));\n return withIds.map((s) => s.id!);\n };\n\n // Mode state — held in a creo store so the EditorView re-renders when it\n // changes. Default \"wysiwyg\" matches the legacy non-mode behavior.\n const modeStore = store.new<EditorMode>(opts.mode ?? \"wysiwyg\");\n const getMode = (): EditorMode => modeStore.get();\n const setMode = (m: EditorMode): void => {\n if (modeStore.get() === m) return;\n modeStore.set(m);\n };\n\n const scrollToBlock = (\n blockId: BlockId,\n opts?: { block?: \"start\" | \"center\" | \"end\" | \"nearest\"; behavior?: ScrollBehavior },\n ): void => {\n const order = docStore.get().order;\n const idx = order.indexOf(blockId);\n if (idx < 0) return;\n const root = document.querySelector(\n `[data-creo-edit=\"${editorId}\"]`,\n ) as HTMLElement | null;\n if (!root) return;\n const escaped = blockId.replace(/([\"\\\\])/g, \"\\\\$1\");\n const el = root.querySelector(\n `[data-block-kind][data-block-id=\"${escaped}\"]`,\n ) as HTMLElement | null;\n if (el) {\n el.scrollIntoView({\n block: opts?.block ?? \"center\",\n behavior: opts?.behavior ?? \"auto\",\n });\n return;\n }\n // Virtualized off-screen — defer to VirtualDoc's height-index-aware\n // scroller exposed at mount time.\n const v = (root as unknown as {\n __creoVirtual?: {\n scrollToIndex: (\n i: number,\n opts?: { block?: \"start\" | \"center\" | \"end\" | \"nearest\"; behavior?: ScrollBehavior },\n ) => void;\n };\n }).__creoVirtual;\n v?.scrollToIndex(idx, opts);\n };\n\n const focus = (): void => {\n const root = document.querySelector(\n `[data-creo-edit=\"${editorId}\"]`,\n ) as HTMLElement | null;\n root?.focus();\n };\n const blur = (): void => {\n const root = document.querySelector(\n `[data-creo-edit=\"${editorId}\"]`,\n ) as HTMLElement | null;\n root?.blur();\n };\n\n // Cmd+A selects the editable \"section\" surrounding the caret — the run\n // of blocks bounded by the nearest atomic blocks (calendar, date-marker,\n // image…) above and below, rather than the entire doc. Wiping the\n // current list with Cmd+A → Backspace shouldn't also wipe every other\n // section's content. Pressing Cmd+A again when the section is already\n // fully selected expands to the whole doc so the \"select everything\"\n // intent stays reachable.\n const handleSelectAll = (): void => {\n const doc = docStore.get();\n if (doc.order.length === 0) return;\n const sel = selStore.get();\n const pivotId = sel.kind === \"caret\" ? sel.at.blockId : sel.anchor.blockId;\n const pivotIdx = doc.order.indexOf(pivotId);\n const pivotBlock = pivotIdx >= 0 ? doc.byId.get(pivotId) : undefined;\n\n // Caret on an atomic block, or pivot block missing — fall back to\n // the original whole-doc behavior.\n if (!pivotBlock || isAtomicBlockType(pivotBlock.type)) {\n selStore.set({\n kind: \"range\",\n anchor: homeOfDoc(doc),\n focus: endOfDocAnchor(doc),\n });\n return;\n }\n\n // Walk outward to find the editable section's edges.\n let startIdx = pivotIdx;\n while (startIdx > 0) {\n const prev = doc.byId.get(doc.order[startIdx - 1]!);\n if (prev && isAtomicBlockType(prev.type)) break;\n startIdx--;\n }\n let endIdx = pivotIdx;\n while (endIdx < doc.order.length - 1) {\n const next = doc.byId.get(doc.order[endIdx + 1]!);\n if (next && isAtomicBlockType(next.type)) break;\n endIdx++;\n }\n const startId = doc.order[startIdx]!;\n const endId = doc.order[endIdx]!;\n const sectionStart = homeOfBlock(doc, {\n blockId: startId,\n path: [0],\n offset: 0,\n });\n const sectionEnd = endOfBlock(doc, {\n blockId: endId,\n path: [0],\n offset: 0,\n });\n\n // Progressive expansion: if the section is ALREADY fully selected,\n // expand to whole-doc. Detected by comparing the current range's\n // ordered endpoints with the section's endpoints.\n if (sel.kind === \"range\") {\n const docStart = homeOfDoc(doc);\n const docEnd = endOfDocAnchor(doc);\n const a = sel.anchor;\n const f = sel.focus;\n const matchesSection =\n (anchorEq(a, sectionStart) && anchorEq(f, sectionEnd)) ||\n (anchorEq(a, sectionEnd) && anchorEq(f, sectionStart));\n const alreadyWholeDoc =\n (anchorEq(a, docStart) && anchorEq(f, docEnd)) ||\n (anchorEq(a, docEnd) && anchorEq(f, docStart));\n if (matchesSection && !alreadyWholeDoc) {\n selStore.set({ kind: \"range\", anchor: docStart, focus: docEnd });\n return;\n }\n }\n\n selStore.set({ kind: \"range\", anchor: sectionStart, focus: sectionEnd });\n };\n\n const anchorEq = (a: Anchor, b: Anchor): boolean =>\n a.blockId === b.blockId &&\n a.offset === b.offset &&\n a.path.length === b.path.length &&\n a.path.every((v, i) => v === b.path[i]);\n\n // EditorView — minimal contentEditable wrapper. The browser handles caret,\n // drag-selection, IME composition, and the long-press OS context menu;\n // attachNativeInput intercepts beforeinput and translates it into commands.\n const EditorView: PublicView<EditorViewProps, void> = view<EditorViewProps>(\n ({ props, use }) => {\n const doc = use(docStore);\n // Subscribe to mode changes so the wrapper re-renders (and CSS class\n // updates).\n void use(modeStore);\n\n return {\n onMount() {\n const root = document.querySelector(\n `[data-creo-edit=\"${editorId}\"]`,\n ) as HTMLElement | null;\n if (!root) return;\n // Expose the editor stores on the root so decoration plugins\n // (drag handle, add-block) can access docStore/selStore without\n // an explicit handle argument. Marked as a hidden property so\n // it doesn't clutter the DOM inspector.\n (root as unknown as { __creoEdit?: unknown }).__creoEdit = {\n docStore,\n selStore,\n dispatch,\n appendBlocks,\n prependBlocks,\n scrollToBlock,\n };\n nativeInput = attachNativeInput(\n root,\n { docStore, selStore },\n {\n dispatch,\n undo: () => history.undo(),\n redo: () => history.redo(),\n selectAll: () => handleSelectAll(),\n uploadImage: opts.uploadImage,\n registry,\n triggers,\n },\n );\n drop = attachDrop(root, { docStore, selStore }, opts.uploadImage);\n viewport = attachVisualViewport(root, { docStore, selStore });\n // Decoration manager — only mounts a layer if at least one\n // plugin contributes a decoration. Cheap to instantiate either\n // way; the layer is empty when there are no decorations.\n // Guard against repeated onMount invocations (Creo re-mounts the\n // view when its props identity changes, e.g. on plugin toggles in\n // the demo): tear down the previous instance before creating a\n // new one so we don't accumulate orphan layers + listeners.\n if (registry.decorations.length > 0) {\n decorations?.destroy();\n decorations = new DecorationManager({\n registry,\n docStore,\n editorRoot: root,\n });\n }\n },\n render() {\n const mode = modeStore.get();\n const modeCls = mode === \"md\" ? \" creo-edit-md\" : \" creo-edit-wysiwyg\";\n const cls =\n (props()?.class\n ? `creo-edit ${props()!.class}`\n : \"creo-edit\") + modeCls;\n div(\n {\n class: cls,\n \"data-creo-edit\": editorId,\n // `cursor: text` so hovering shows the I-beam. Image blocks\n // override this to keep the default pointer arrow.\n //\n // `white-space: pre-wrap` is REQUIRED — the default `normal`\n // collapses trailing spaces visually, so typing a space at\n // end-of-line would advance the model offset but never render.\n style: \"position:relative;cursor:text;white-space:pre-wrap;\",\n },\n () => {\n if (opts.virtualized) {\n VirtualDoc({\n docStore,\n selStore,\n estimatedHeight: opts.virtualEstimatedHeight,\n });\n } else {\n DocView({ doc: doc.get() });\n }\n },\n );\n void _;\n },\n };\n },\n );\n\n return {\n docStore,\n selStore,\n dispatch,\n undo,\n redo,\n EditorView,\n setDocFromHTML,\n setDoc,\n toJSON,\n appendBlocks,\n prependBlocks,\n focus,\n blur,\n getMode,\n setMode,\n registry,\n scrollToBlock,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction seedEmpty(): DocState {\n // A fresh editor needs at least one empty paragraph so the user has\n // something to type into.\n const block: BlockSpec = {\n id: newBlockId(),\n type: \"p\",\n runs: [],\n };\n return docFromBlocks([block]);\n}\n\n// Re-export emptyDoc for convenience.\nexport { emptyDoc };\n\n// Avoid an unused-import warning on Block in some downstream typings.\nvoid (null as unknown as Block);\nvoid (null as unknown as InlineRun);\n",
|
|
6
|
+
"import type { Block, InlineRun, Mark } from \"./types\";\n\n/** Blocks whose content is a single InlineRun[] (paragraphs, headings, list items). */\nexport type TextBearingBlock = Extract<\n Block,\n { runs: InlineRun[] }\n>;\n\nexport function isTextBearing(block: Block): block is TextBearingBlock {\n return (\n block.type === \"p\" ||\n block.type === \"h1\" ||\n block.type === \"h2\" ||\n block.type === \"h3\" ||\n block.type === \"h4\" ||\n block.type === \"h5\" ||\n block.type === \"h6\" ||\n block.type === \"li\" ||\n block.type === \"code\"\n );\n}\n\n/** Total length of plain text across all runs of a text-bearing block. */\nexport function runsLength(runs: InlineRun[]): number {\n let n = 0;\n for (const r of runs) n += r.text.length;\n return n;\n}\n\nexport function blockTextLength(block: TextBearingBlock): number {\n return runsLength(block.runs);\n}\n\nfunction marksEqual(\n a: ReadonlySet<Mark> | undefined,\n b: ReadonlySet<Mark> | undefined,\n): boolean {\n if (a === b) return true;\n const an = a ? a.size : 0;\n const bn = b ? b.size : 0;\n if (an !== bn) return false;\n if (an === 0) return true;\n for (const m of a!) if (!b!.has(m)) return false;\n return true;\n}\n\n/**\n * Normalize: drop empty runs and merge adjacent runs with identical marks.\n * Always returns a fresh array.\n */\nexport function normalizeRuns(runs: InlineRun[]): InlineRun[] {\n const out: InlineRun[] = [];\n for (const r of runs) {\n if (r.text.length === 0) continue;\n const last = out[out.length - 1];\n if (last && marksEqual(last.marks, r.marks)) {\n out[out.length - 1] = {\n text: last.text + r.text,\n ...(last.marks ? { marks: last.marks } : {}),\n };\n } else {\n out.push(r);\n }\n }\n return out;\n}\n\n/**\n * Find the run + local offset that owns the given character position.\n * `offset` is clamped to [0, runsLength].\n *\n * The \"boundary\" rule: if `offset` lands exactly between two runs, we report\n * `runIndex` = the index of the run that *ends* at that boundary (so callers\n * inserting text inherit the LEFT run's marks by default).\n */\nexport type RunPos = {\n runIndex: number; // -1 when offset === 0 and there are no runs\n localOffset: number;\n /** Aggregate length of all runs strictly before runIndex. */\n prefixLen: number;\n};\n\nexport function locateRun(runs: InlineRun[], offset: number): RunPos {\n if (runs.length === 0) {\n return { runIndex: -1, localOffset: 0, prefixLen: 0 };\n }\n if (offset <= 0) {\n return { runIndex: 0, localOffset: 0, prefixLen: 0 };\n }\n let prefix = 0;\n for (let i = 0; i < runs.length; i++) {\n const len = runs[i]!.text.length;\n if (offset <= prefix + len) {\n return { runIndex: i, localOffset: offset - prefix, prefixLen: prefix };\n }\n prefix += len;\n }\n // Past the end — clamp to last run.\n const last = runs.length - 1;\n return {\n runIndex: last,\n localOffset: runs[last]!.text.length,\n prefixLen: prefix - runs[last]!.text.length,\n };\n}\n\n/** Marks the next inserted character should inherit at `offset`. */\nexport function marksAt(\n runs: InlineRun[],\n offset: number,\n): ReadonlySet<Mark> | undefined {\n if (runs.length === 0) return undefined;\n const pos = locateRun(runs, offset);\n // At absolute start, no marks.\n if (offset === 0) return undefined;\n return runs[pos.runIndex]!.marks;\n}\n\n/**\n * Insert `text` (with optional `marks`) at character `offset`.\n * Returns a new runs array.\n */\nexport function insertText(\n runs: InlineRun[],\n offset: number,\n text: string,\n marks?: ReadonlySet<Mark>,\n): InlineRun[] {\n if (text.length === 0) return runs;\n const pos = locateRun(runs, offset);\n\n // Build the output: [unchanged runs before pos] + split run + [unchanged after]\n const out: InlineRun[] = [];\n for (let i = 0; i < pos.runIndex; i++) out.push(runs[i]!);\n\n const inheritMarks = marks ?? marksAt(runs, offset);\n const newRun: InlineRun = inheritMarks && inheritMarks.size\n ? { text, marks: inheritMarks }\n : { text };\n\n if (pos.runIndex === -1) {\n // Empty runs: just emit the new run.\n out.push(newRun);\n } else {\n const r = runs[pos.runIndex]!;\n const left = r.text.slice(0, pos.localOffset);\n const right = r.text.slice(pos.localOffset);\n if (left.length) {\n out.push(r.marks ? { text: left, marks: r.marks } : { text: left });\n }\n out.push(newRun);\n if (right.length) {\n out.push(r.marks ? { text: right, marks: r.marks } : { text: right });\n }\n for (let i = pos.runIndex + 1; i < runs.length; i++) out.push(runs[i]!);\n }\n return normalizeRuns(out);\n}\n\n/** Delete characters in [start, end). Returns a new runs array. */\nexport function deleteRange(\n runs: InlineRun[],\n start: number,\n end: number,\n): InlineRun[] {\n if (start >= end) return runs;\n const total = runsLength(runs);\n const s = Math.max(0, Math.min(total, start));\n const e = Math.max(0, Math.min(total, end));\n if (s === e) return runs;\n if (s === 0 && e === total) return [];\n\n const out: InlineRun[] = [];\n let prefix = 0;\n for (const r of runs) {\n const rs = prefix;\n const re = prefix + r.text.length;\n if (re <= s || rs >= e) {\n out.push(r);\n } else {\n const keepLeft = Math.max(0, s - rs);\n const keepRightStart = Math.max(0, e - rs);\n const left = r.text.slice(0, keepLeft);\n const right = r.text.slice(keepRightStart);\n const txt = left + right;\n if (txt.length) {\n out.push(r.marks ? { text: txt, marks: r.marks } : { text: txt });\n }\n }\n prefix = re;\n }\n return normalizeRuns(out);\n}\n\n/** Split runs at offset into [left, right] arrays. */\nexport function splitRunsAt(\n runs: InlineRun[],\n offset: number,\n): [InlineRun[], InlineRun[]] {\n const total = runsLength(runs);\n const o = Math.max(0, Math.min(total, offset));\n if (o === 0) return [[], runs.slice()];\n if (o === total) return [runs.slice(), []];\n const pos = locateRun(runs, o);\n const left: InlineRun[] = [];\n const right: InlineRun[] = [];\n for (let i = 0; i < pos.runIndex; i++) left.push(runs[i]!);\n const r = runs[pos.runIndex]!;\n const lText = r.text.slice(0, pos.localOffset);\n const rText = r.text.slice(pos.localOffset);\n if (lText.length) {\n left.push(r.marks ? { text: lText, marks: r.marks } : { text: lText });\n }\n if (rText.length) {\n right.push(r.marks ? { text: rText, marks: r.marks } : { text: rText });\n }\n for (let i = pos.runIndex + 1; i < runs.length; i++) right.push(runs[i]!);\n return [normalizeRuns(left), normalizeRuns(right)];\n}\n\n/** Concatenate two runs arrays, normalizing the seam. */\nexport function concatRuns(a: InlineRun[], b: InlineRun[]): InlineRun[] {\n return normalizeRuns([...a, ...b]);\n}\n",
|
|
7
|
+
"/**\n * Fractional indexing over a base-62 alphabet.\n *\n * Alphabet ordering (string compare matches numeric order):\n * '0'..'9' < 'A'..'Z' < 'a'..'z' → 62 symbols.\n *\n * A key is a non-empty string of alphabet characters; lexicographic comparison\n * yields the same ordering as the rationals they represent. The first symbol's\n * value is the most-significant fractional digit.\n *\n * `generateBetween(a, b)` returns a key strictly between `a` and `b`. `null`\n * means \"no bound\" — use it for the document's first or last position.\n *\n * `generateN(a, b, n)` produces `n` evenly-spaced keys between `a` and `b` in\n * O(n + log span); used by bulk-paste so we don't pay O(n²) re-midpointing.\n */\n\nconst ALPHABET =\n \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\";\nconst BASE = ALPHABET.length; // 62\nconst MIN_CHAR = ALPHABET[0]!;\nconst MAX_CHAR = ALPHABET[BASE - 1]!;\n\nconst ORD: Record<string, number> = (() => {\n const map: Record<string, number> = {};\n for (let i = 0; i < ALPHABET.length; i++) map[ALPHABET[i]!] = i;\n return map;\n})();\n\nfunction ord(c: string): number {\n const v = ORD[c];\n if (v === undefined) {\n throw new Error(`Invalid fractional-index character: ${JSON.stringify(c)}`);\n }\n return v;\n}\n\nfunction chr(n: number): string {\n if (n < 0 || n >= BASE) {\n throw new Error(`Out-of-range alphabet index: ${n}`);\n }\n return ALPHABET[n]!;\n}\n\n/** Random base-62 character — used as a tail to keep keys distinct. */\nfunction randomChar(): string {\n return chr(Math.floor(Math.random() * BASE));\n}\n\n/** Strip trailing MIN_CHAR ('0') noise from a key (those bits are zeros). */\nfunction trimZeros(s: string): string {\n let end = s.length;\n while (end > 1 && s[end - 1] === MIN_CHAR) end--;\n return s.slice(0, end);\n}\n\n/**\n * Read the i-th character of `s`, treating it as if zero-padded indefinitely\n * (right pad with '0' for `a`-side keys, '~' for `b`-side keys).\n */\nfunction digitAt(s: string | null, i: number, padChar: string): string {\n if (s == null) return padChar;\n return i < s.length ? s[i]! : padChar;\n}\n\n/**\n * Generate a key strictly between `a` and `b`.\n * - If a==null, the new key is < b.\n * - If b==null, the new key is > a.\n * - Both null → returns \"U\" (mid-range).\n */\nexport function generateBetween(\n a: string | null,\n b: string | null,\n): string {\n if (a != null && b != null && a >= b) {\n throw new Error(\n `generateBetween: a (${a}) must be strictly less than b (${b})`,\n );\n }\n\n if (a == null && b == null) {\n // Mid-alphabet seed.\n return chr(Math.floor(BASE / 2));\n }\n\n // Walk character by character looking for a usable midpoint.\n const out: string[] = [];\n let i = 0;\n while (true) {\n const ac = ord(digitAt(a, i, MIN_CHAR));\n const bc = ord(digitAt(b, i, MAX_CHAR));\n\n if (ac === bc) {\n // Equal at this position — emit & descend.\n out.push(chr(ac));\n i++;\n continue;\n }\n\n if (bc - ac >= 2) {\n // Gap of ≥ 2 — pick the midpoint character.\n out.push(chr(ac + Math.floor((bc - ac) / 2)));\n return out.join(\"\");\n }\n\n // Gap of exactly 1 — emit ac, then descend on the a side searching for\n // a character > '0'. The new key is strictly > a (because we'll add a\n // non-zero tail digit below) and strictly < b (because its first digit\n // equals ac < bc).\n out.push(chr(ac));\n i++;\n\n // From here, we're producing the suffix of a new key whose prefix is\n // already > a's prefix (since we matched bc ahead). Walk a's tail until\n // we can append a digit greater than a's; if a runs out, append a random\n // non-zero tail character to avoid collisions and keep the key bounded.\n while (true) {\n const an = ord(digitAt(a, i, MIN_CHAR));\n if (an < BASE - 1) {\n // Pick something strictly > an.\n const offset = 1 + Math.floor(Math.random() * (BASE - 1 - an));\n out.push(chr(an + offset));\n return out.join(\"\");\n }\n // a's character is the alphabet max — must keep walking and emit it.\n out.push(chr(an));\n i++;\n }\n }\n}\n\n/**\n * Generate `n` evenly-spaced keys strictly between `a` and `b`.\n * Returns them in ascending order.\n *\n * O(n) total — far cheaper than calling generateBetween repeatedly with\n * a moving cursor (which would degrade by binary descent each step).\n */\nexport function generateN(\n a: string | null,\n b: string | null,\n n: number,\n): string[] {\n if (n <= 0) return [];\n if (n === 1) return [generateBetween(a, b)];\n if (a != null && b != null && a >= b) {\n throw new Error(\"generateN: a must be strictly less than b\");\n }\n\n // Strategy: recursively split. mid = generateBetween(a, b); then split\n // [a..mid] for n/2 keys and [mid..b] for the remainder. The midpoint goes\n // into the result.\n const half = Math.floor(n / 2);\n const mid = generateBetween(a, b);\n const left = half > 0 ? generateN(a, mid, half) : [];\n const right = n - half - 1 > 0 ? generateN(mid, b, n - half - 1) : [];\n return [...left, mid, ...right];\n}\n\n// ---------------------------------------------------------------------------\n// Rebalance helpers\n// ---------------------------------------------------------------------------\n\n/** Soft cap; once any key exceeds this length, schedule a rebalance. */\nexport const REBALANCE_THRESHOLD = 32;\n\n/** Returns true if any key in the sorted list exceeds REBALANCE_THRESHOLD. */\nexport function needsRebalance(keys: string[]): boolean {\n for (const k of keys) {\n if (k.length > REBALANCE_THRESHOLD) return true;\n }\n return false;\n}\n\n/**\n * Produce a fresh, evenly-spaced sequence of N keys, replacing an existing\n * sorted sequence. Used by the doc layer when keys grow past threshold.\n */\nexport function rebalance(count: number): string[] {\n return generateN(null, null, count);\n}\n\n// ---------------------------------------------------------------------------\n// Internal exports for tests\n// ---------------------------------------------------------------------------\n\nexport const __internal = {\n ALPHABET,\n BASE,\n MIN_CHAR,\n MAX_CHAR,\n ord,\n chr,\n randomChar,\n trimZeros,\n};\n",
|
|
8
|
+
"import {\n generateBetween,\n generateN,\n needsRebalance,\n rebalance,\n} from \"./fractional\";\nimport type { Block, BlockId, BlockSpec, DocState, FracIndex } from \"./types\";\n\n// ---------------------------------------------------------------------------\n// ID generation\n// ---------------------------------------------------------------------------\n\nlet __idCounter = 0;\nconst __sessionPrefix = Math.floor(Math.random() * 0xffffffff)\n .toString(36)\n .padStart(7, \"0\");\n\n/** Cheap, monotonically increasing block id with a per-session prefix. */\nexport function newBlockId(): BlockId {\n __idCounter = (__idCounter + 1) | 0;\n return `b_${__sessionPrefix}_${__idCounter.toString(36)}`;\n}\n\n// ---------------------------------------------------------------------------\n// DocState construction\n// ---------------------------------------------------------------------------\n\nexport function emptyDoc(): DocState {\n return { byId: new Map(), order: [] };\n}\n\n/** Build a DocState from a list of blocks (will assign indices if missing). */\nexport function docFromBlocks(blocks: BlockSpec[]): DocState {\n const indices = generateN(null, null, blocks.length);\n const doc = emptyDoc();\n for (let i = 0; i < blocks.length; i++) {\n const b = { ...blocks[i]!, index: indices[i]! } as Block;\n doc.byId.set(b.id, b);\n doc.order.push(b.id);\n }\n return doc;\n}\n\n// ---------------------------------------------------------------------------\n// Order helpers — binary search over `order` keyed by Block.index\n// ---------------------------------------------------------------------------\n\n/**\n * Returns the insertion index in `order` such that the new key sorts at that\n * position. Pure binary search by `Block.index`.\n */\nexport function findInsertionPos(doc: DocState, index: FracIndex): number {\n let lo = 0;\n let hi = doc.order.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n const midIdx = doc.byId.get(doc.order[mid]!)!.index;\n if (midIdx < index) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n}\n\n/** Returns the position of `id` in `order`, or -1 if not found. */\nexport function findPos(doc: DocState, id: BlockId): number {\n const block = doc.byId.get(id);\n if (!block) return -1;\n // Binary-search by index (faster than linear once doc is large).\n let lo = 0;\n let hi = doc.order.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n const cur = doc.byId.get(doc.order[mid]!)!;\n if (cur.index < block.index) lo = mid + 1;\n else if (cur.index > block.index) hi = mid;\n else return mid;\n }\n return -1;\n}\n\n// ---------------------------------------------------------------------------\n// CRUD — all return a NEW DocState (immutable from the caller's perspective).\n// `byId` and `order` are replaced rather than mutated so referential identity\n// signals \"the doc changed\".\n// ---------------------------------------------------------------------------\n\n/**\n * Insert `block` between the blocks at positions [pos-1] and [pos].\n * The new block's `index` is overwritten with a fractional key in that gap.\n */\nexport function insertAt(\n doc: DocState,\n pos: number,\n block: BlockSpec,\n): DocState {\n const before =\n pos <= 0 ? null : doc.byId.get(doc.order[pos - 1]!)!.index;\n const after =\n pos >= doc.order.length\n ? null\n : doc.byId.get(doc.order[pos]!)!.index;\n const index = generateBetween(before, after);\n return insertWithIndex(doc, { ...block, index } as Block);\n}\n\n/** Insert a block whose `index` has already been assigned. */\nexport function insertWithIndex(doc: DocState, block: Block): DocState {\n if (doc.byId.has(block.id)) {\n throw new Error(`insertWithIndex: duplicate block id ${block.id}`);\n }\n const pos = findInsertionPos(doc, block.index);\n const order = doc.order.slice();\n order.splice(pos, 0, block.id);\n const byId = new Map(doc.byId);\n byId.set(block.id, block);\n return { byId, order };\n}\n\n/** Insert `block` immediately after `afterId` (or at the start if null). */\nexport function insertAfter(\n doc: DocState,\n afterId: BlockId | null,\n block: BlockSpec,\n): DocState {\n const pos = afterId == null ? 0 : findPos(doc, afterId) + 1;\n return insertAt(doc, pos, block);\n}\n\n/** Replace the block with the same id. */\nexport function updateBlock(doc: DocState, block: Block): DocState {\n if (!doc.byId.has(block.id)) {\n throw new Error(`updateBlock: unknown id ${block.id}`);\n }\n const byId = new Map(doc.byId);\n byId.set(block.id, block);\n // Order doesn't change unless the index changed.\n const prev = doc.byId.get(block.id)!;\n if (prev.index === block.index) {\n return { byId, order: doc.order };\n }\n // Re-sort: remove + reinsert by new index.\n const order = doc.order.filter((x) => x !== block.id);\n const interim: DocState = { byId, order };\n const pos = findInsertionPos(interim, block.index);\n order.splice(pos, 0, block.id);\n return { byId, order };\n}\n\n/** Remove a block. */\nexport function removeBlock(doc: DocState, id: BlockId): DocState {\n if (!doc.byId.has(id)) return doc;\n const byId = new Map(doc.byId);\n byId.delete(id);\n const order = doc.order.filter((x) => x !== id);\n return { byId, order };\n}\n\n/**\n * Remove multiple blocks in one pass. Single allocation of the new order\n * array — avoids the O(M*N) cost of calling removeBlock M times in a loop.\n */\nexport function removeBlocks(doc: DocState, ids: Iterable<BlockId>): DocState {\n const removeSet = new Set<BlockId>();\n for (const id of ids) {\n if (doc.byId.has(id)) removeSet.add(id);\n }\n if (removeSet.size === 0) return doc;\n const byId = new Map(doc.byId);\n for (const id of removeSet) byId.delete(id);\n const order: BlockId[] = [];\n for (const id of doc.order) {\n if (!removeSet.has(id)) order.push(id);\n }\n return { byId, order };\n}\n\n/**\n * Bulk-insert: drop `n` new blocks evenly spaced into the gap before `pos`.\n * Faster than calling insertAt repeatedly because we compute all keys at once.\n *\n * Builds the new `order` array in a single pass (O(N + M) where N = current\n * doc size, M = inserted block count) instead of splicing in a loop. Splicing\n * inside a loop is O(N) per call → O(M*N) overall, which hurts catastrophically\n * for large pastes (e.g. ~10k paragraphs from a long document).\n */\nexport function insertManyAt(\n doc: DocState,\n pos: number,\n blocks: BlockSpec[],\n): DocState {\n if (blocks.length === 0) return doc;\n const before =\n pos <= 0 ? null : doc.byId.get(doc.order[pos - 1]!)!.index;\n const after =\n pos >= doc.order.length\n ? null\n : doc.byId.get(doc.order[pos]!)!.index;\n const indices = generateN(before, after, blocks.length);\n const byId = new Map(doc.byId);\n // Single-allocation order rebuild — avoid O(N) splice per block.\n const insertedIds: BlockId[] = new Array(blocks.length);\n for (let i = 0; i < blocks.length; i++) {\n const b = { ...blocks[i]!, index: indices[i]! } as Block;\n if (byId.has(b.id)) {\n throw new Error(`insertManyAt: duplicate block id ${b.id}`);\n }\n byId.set(b.id, b);\n insertedIds[i] = b.id;\n }\n const order: BlockId[] = new Array(doc.order.length + blocks.length);\n for (let i = 0; i < pos; i++) order[i] = doc.order[i]!;\n for (let i = 0; i < blocks.length; i++) order[pos + i] = insertedIds[i]!;\n for (let i = pos; i < doc.order.length; i++) {\n order[i + blocks.length] = doc.order[i]!;\n }\n return { byId, order };\n}\n\n// ---------------------------------------------------------------------------\n// Rebalance — once any key grows past the soft threshold, regenerate keys.\n// ---------------------------------------------------------------------------\n\nexport function maybeRebalance(doc: DocState): DocState {\n const keys = doc.order.map((id) => doc.byId.get(id)!.index);\n if (!needsRebalance(keys)) return doc;\n const fresh = rebalance(doc.order.length);\n const byId = new Map<BlockId, Block>();\n for (let i = 0; i < doc.order.length; i++) {\n const id = doc.order[i]!;\n const block = doc.byId.get(id)!;\n byId.set(id, { ...block, index: fresh[i]! } as Block);\n }\n return { byId, order: doc.order.slice() };\n}\n\n// ---------------------------------------------------------------------------\n// Iteration / lookup\n// ---------------------------------------------------------------------------\n\nexport function* iterBlocks(doc: DocState): IterableIterator<Block> {\n for (const id of doc.order) {\n yield doc.byId.get(id)!;\n }\n}\n\nexport function getBlock(doc: DocState, id: BlockId): Block | undefined {\n return doc.byId.get(id);\n}\n\nexport function blockAt(doc: DocState, pos: number): Block | undefined {\n const id = doc.order[pos];\n return id == null ? undefined : doc.byId.get(id);\n}\n",
|
|
9
|
+
"// ---------------------------------------------------------------------------\n// Atomic-block registry — module-global Set tracking which block types are\n// non-editable \"atomic\" islands. Atomic blocks have only two valid caret\n// positions (before / after) encoded as `path: [side]` where side ∈ {0, 1}.\n// They render with `contenteditable=\"false\"` so the browser places the\n// caret around the block, not inside it.\n//\n// Built-in `img` is registered by its plugin definition. Third-party\n// plugins (calendar, embeds, formulas, …) opt in by setting\n// `BlockDef.isAtomic = true` — the registry installer mirrors the flag\n// into this Set so navigation / input / selection code can check the kind\n// via a single helper without importing block-specific knowledge.\n// ---------------------------------------------------------------------------\n\nconst atomicTypes = new Set<string>();\n\nexport function registerAtomic(type: string): void {\n atomicTypes.add(type);\n}\n\nexport function isAtomicBlockType(type: string): boolean {\n return atomicTypes.has(type);\n}\n",
|
|
10
|
+
"import { findPos, getBlock } from \"../model/doc\";\nimport {\n blockTextLength,\n isTextBearing,\n type TextBearingBlock,\n} from \"../model/blockText\";\nimport { isAtomicBlockType } from \"../plugin/atomic\";\nimport type {\n Anchor,\n Block,\n BlockId,\n ColumnsBlock,\n DocState,\n Selection,\n TableBlock,\n} from \"../model/types\";\n\n// ---------------------------------------------------------------------------\n// Anchor builders\n// ---------------------------------------------------------------------------\n\nexport function caretAt(blockId: BlockId, offset: number): Anchor {\n return { blockId, path: [offset], offset };\n}\n\nexport function caret(at: Anchor): Selection {\n return { kind: \"caret\", at };\n}\n\nexport function range(anchor: Anchor, focus: Anchor): Selection {\n return { kind: \"range\", anchor, focus };\n}\n\n// ---------------------------------------------------------------------------\n// Inspection\n// ---------------------------------------------------------------------------\n\nexport function anchorOffset(a: Anchor): number {\n // Path encodings:\n // text-bearing: [charOffset]\n // columns: [colIndex, charOffset]\n // tables: [row, col, charOffset]\n if (a.path.length >= 3) return a.path[2]!;\n if (a.path.length === 2) return a.path[1]!;\n if (a.path.length >= 1) return a.path[0]!;\n return a.offset;\n}\n\nexport function withCharOffset(a: Anchor, offset: number): Anchor {\n if (a.path.length >= 3) {\n return {\n ...a,\n path: [a.path[0]!, a.path[1]!, offset],\n offset,\n };\n }\n if (a.path.length === 2) {\n return { ...a, path: [a.path[0]!, offset], offset };\n }\n return { ...a, path: [offset], offset };\n}\n\n/** Returns true when the selection is a collapsed caret. */\nexport function isCaret(s: Selection): s is { kind: \"caret\"; at: Anchor } {\n return s.kind === \"caret\";\n}\n\n/** Same anchor & focus → effectively a caret. */\nexport function selectionStart(s: Selection): Anchor {\n return s.kind === \"caret\" ? s.at : s.anchor;\n}\n\nexport function selectionEnd(s: Selection): Anchor {\n return s.kind === \"caret\" ? s.at : s.focus;\n}\n\n/** Compares two anchors that point into the same doc. Returns -1/0/+1. */\nexport function compareAnchors(\n doc: DocState,\n a: Anchor,\n b: Anchor,\n): number {\n if (a.blockId === b.blockId) {\n // Same block — compare by path lexicographically, longer path wins ties.\n const al = a.path.length;\n const bl = b.path.length;\n const n = Math.min(al, bl);\n for (let i = 0; i < n; i++) {\n const ai = a.path[i]!;\n const bi = b.path[i]!;\n if (ai !== bi) return ai < bi ? -1 : 1;\n }\n if (al !== bl) return al < bl ? -1 : 1;\n return 0;\n }\n const ai = findPos(doc, a.blockId);\n const bi = findPos(doc, b.blockId);\n if (ai === bi) return 0;\n return ai < bi ? -1 : 1;\n}\n\n/** Anchor in document-order start..end ascending. */\nexport function orderedRange(\n doc: DocState,\n s: Selection,\n): { start: Anchor; end: Anchor } {\n if (s.kind === \"caret\") return { start: s.at, end: s.at };\n return compareAnchors(doc, s.anchor, s.focus) <= 0\n ? { start: s.anchor, end: s.focus }\n : { start: s.focus, end: s.anchor };\n}\n\n// ---------------------------------------------------------------------------\n// Clamping\n// ---------------------------------------------------------------------------\n\n/** Clamp an anchor so it points at a valid offset inside its block. */\nexport function clampAnchor(doc: DocState, a: Anchor): Anchor {\n const block = getBlock(doc, a.blockId);\n if (!block) {\n // Block was removed — fall back to the doc's first block, offset 0.\n const firstId = doc.order[0];\n if (firstId == null) {\n return { blockId: \"\", path: [0], offset: 0 };\n }\n return caretAt(firstId, 0);\n }\n return clampAnchorInBlock(block, a);\n}\n\nfunction clampAnchorInBlock(block: Block, a: Anchor): Anchor {\n if (isTextBearing(block)) {\n const max = blockTextLength(block as TextBearingBlock);\n const offset = Math.max(0, Math.min(max, anchorOffset(a)));\n return withCharOffset({ ...a, blockId: block.id }, offset);\n }\n if (isAtomicBlockType(block.type)) {\n const side = a.path[0] === 1 ? 1 : 0;\n return {\n blockId: block.id,\n path: [side],\n offset: side,\n };\n }\n if (block.type === \"columns\") {\n const cb = block as ColumnsBlock;\n const c = Math.max(0, Math.min(cb.cols - 1, a.path[0] ?? 0));\n const cell = cb.cells[c] ?? [];\n const cellLen = cell.reduce((n, run) => n + run.text.length, 0);\n const off = Math.max(0, Math.min(cellLen, a.path[1] ?? 0));\n return { blockId: block.id, path: [c, off], offset: off };\n }\n // table\n const t = block as TableBlock;\n const r = Math.max(0, Math.min(t.rows - 1, a.path[0] ?? 0));\n const c = Math.max(0, Math.min(t.cols - 1, a.path[1] ?? 0));\n const cell = t.cells[r]?.[c] ?? [];\n const cellLen = cell.reduce((n, run) => n + run.text.length, 0);\n const off = Math.max(0, Math.min(cellLen, a.path[2] ?? 0));\n return { blockId: block.id, path: [r, c, off], offset: off };\n}\n\nexport function clampSelection(doc: DocState, s: Selection): Selection {\n if (s.kind === \"caret\") return caret(clampAnchor(doc, s.at));\n return range(clampAnchor(doc, s.anchor), clampAnchor(doc, s.focus));\n}\n\n// ---------------------------------------------------------------------------\n// End-of-doc convenience — used by the input pipeline as an initial cursor.\n// ---------------------------------------------------------------------------\n\nexport function endOfDoc(doc: DocState): Anchor {\n const lastId = doc.order[doc.order.length - 1];\n if (lastId == null) return { blockId: \"\", path: [0], offset: 0 };\n const last = doc.byId.get(lastId)!;\n if (isTextBearing(last)) {\n const len = blockTextLength(last as TextBearingBlock);\n return caretAt(lastId, len);\n }\n if (isAtomicBlockType(last.type)) {\n return { blockId: lastId, path: [1], offset: 1 };\n }\n if (last.type === \"columns\") {\n const cb = last as ColumnsBlock;\n const c = cb.cols - 1;\n const cell = cb.cells[c] ?? [];\n const len = cell.reduce((n, run) => n + run.text.length, 0);\n return { blockId: lastId, path: [c, len], offset: len };\n }\n // table — bottom-right cell, end of cell text.\n const t = last as TableBlock;\n const r = t.rows - 1;\n const c = t.cols - 1;\n const cell = t.cells[r]?.[c] ?? [];\n const cellLen = cell.reduce((n, run) => n + run.text.length, 0);\n return { blockId: lastId, path: [r, c, cellLen], offset: cellLen };\n}\n",
|
|
11
|
+
"import {\n blockTextLength,\n isTextBearing,\n type TextBearingBlock,\n} from \"../model/blockText\";\nimport { findPos, getBlock } from \"../model/doc\";\nimport { isAtomicBlockType } from \"../plugin/atomic\";\nimport type {\n Anchor,\n ColumnsBlock,\n DocState,\n InlineRun,\n TableBlock,\n} from \"../model/types\";\nimport { anchorOffset, caretAt, withCharOffset } from \"./selection\";\nimport { nextWordOffset, prevWordOffset } from \"./wordBoundary\";\n\n// ---------------------------------------------------------------------------\n// Block-edge anchors\n// ---------------------------------------------------------------------------\n\nfunction startAnchorOfBlock(doc: DocState, blockId: string): Anchor | null {\n const b = getBlock(doc, blockId);\n if (!b) return null;\n if (isTextBearing(b)) return caretAt(blockId, 0);\n if (isAtomicBlockType(b.type)) return { blockId, path: [0], offset: 0 };\n if (b.type === \"columns\") return { blockId, path: [0, 0], offset: 0 };\n // table — top-left cell, offset 0\n return { blockId, path: [0, 0, 0], offset: 0 };\n}\n\nfunction endAnchorOfBlock(doc: DocState, blockId: string): Anchor | null {\n const b = getBlock(doc, blockId);\n if (!b) return null;\n if (isTextBearing(b)) {\n return caretAt(blockId, blockTextLength(b as TextBearingBlock));\n }\n if (isAtomicBlockType(b.type)) return { blockId, path: [1], offset: 1 };\n if (b.type === \"columns\") {\n const cb = b as ColumnsBlock;\n const c = cb.cols - 1;\n const cell = cb.cells[c] ?? [];\n const len = cell.reduce((n, run) => n + run.text.length, 0);\n return { blockId, path: [c, len], offset: len };\n }\n // table — bottom-right cell, end of cell text\n const t = b as TableBlock;\n const r = t.rows - 1;\n const c = t.cols - 1;\n const cell = t.cells[r]?.[c] ?? [];\n const cellLen = cell.reduce((n, run) => n + run.text.length, 0);\n return { blockId, path: [r, c, cellLen], offset: cellLen };\n}\n\nfunction blockMaxOffset(doc: DocState, blockId: string): number {\n const b = getBlock(doc, blockId);\n if (!b) return 0;\n if (isTextBearing(b)) return blockTextLength(b as TextBearingBlock);\n if (isAtomicBlockType(b.type)) return 1;\n // table cell offset extracted from path[2]\n return 0;\n}\n\n// ---------------------------------------------------------------------------\n// Char-level navigation (handles cross-block movement)\n// ---------------------------------------------------------------------------\n\n/**\n * Move one character to the right. Crosses block boundaries: from the end of\n * block i to the start of block i+1. At end-of-doc, returns the same anchor.\n */\nexport function nextAnchor(doc: DocState, a: Anchor): Anchor {\n const block = getBlock(doc, a.blockId);\n if (!block) return a;\n const off = anchorOffset(a);\n // Tables — handle cell-internal motion first.\n if (block.type === \"table\") {\n return nextInTable(doc, block as TableBlock, a);\n }\n if (isAtomicBlockType(block.type)) {\n if (off === 0) return { blockId: a.blockId, path: [1], offset: 1 };\n // past the atomic block — step into next block\n return stepIntoNextBlock(doc, a.blockId);\n }\n if (block.type === \"columns\") {\n return nextInColumns(doc, block as ColumnsBlock, a);\n }\n // text-bearing\n const max = blockTextLength(block as TextBearingBlock);\n if (off < max) return withCharOffset(a, off + 1);\n return stepIntoNextBlock(doc, a.blockId);\n}\n\n/**\n * Move one character to the left. Crosses block boundaries the same way.\n */\nexport function prevAnchor(doc: DocState, a: Anchor): Anchor {\n const block = getBlock(doc, a.blockId);\n if (!block) return a;\n const off = anchorOffset(a);\n if (block.type === \"table\") {\n return prevInTable(doc, block as TableBlock, a);\n }\n if (isAtomicBlockType(block.type)) {\n if (off === 1) return { blockId: a.blockId, path: [0], offset: 0 };\n return stepIntoPrevBlock(doc, a.blockId);\n }\n if (block.type === \"columns\") {\n return prevInColumns(doc, block as ColumnsBlock, a);\n }\n if (off > 0) return withCharOffset(a, off - 1);\n return stepIntoPrevBlock(doc, a.blockId);\n}\n\nfunction stepIntoNextBlock(doc: DocState, blockId: string): Anchor {\n const i = findPos(doc, blockId);\n const nextId = doc.order[i + 1];\n if (nextId == null) return endAnchorOfBlock(doc, blockId)!;\n return startAnchorOfBlock(doc, nextId)!;\n}\n\nfunction stepIntoPrevBlock(doc: DocState, blockId: string): Anchor {\n const i = findPos(doc, blockId);\n const prevId = doc.order[i - 1];\n if (prevId == null) return startAnchorOfBlock(doc, blockId)!;\n return endAnchorOfBlock(doc, prevId)!;\n}\n\nfunction nextInTable(doc: DocState, t: TableBlock, a: Anchor): Anchor {\n const r = a.path[0] ?? 0;\n const c = a.path[1] ?? 0;\n const off = a.path[2] ?? 0;\n const cell = t.cells[r]?.[c] ?? [];\n const cellLen = cell.reduce((n, run) => n + run.text.length, 0);\n if (off < cellLen) {\n return { blockId: t.id, path: [r, c, off + 1], offset: off + 1 };\n }\n // end of cell — advance to next cell or step out of the table.\n if (c + 1 < t.cols) return { blockId: t.id, path: [r, c + 1, 0], offset: 0 };\n if (r + 1 < t.rows) return { blockId: t.id, path: [r + 1, 0, 0], offset: 0 };\n return stepIntoNextBlock(doc, t.id);\n}\n\nfunction nextInColumns(\n doc: DocState,\n cb: ColumnsBlock,\n a: Anchor,\n): Anchor {\n const c = a.path[0] ?? 0;\n const off = a.path[1] ?? 0;\n const cell = cb.cells[c] ?? [];\n const cellLen = cell.reduce((n, run) => n + run.text.length, 0);\n if (off < cellLen) {\n return { blockId: cb.id, path: [c, off + 1], offset: off + 1 };\n }\n if (c + 1 < cb.cols) return { blockId: cb.id, path: [c + 1, 0], offset: 0 };\n return stepIntoNextBlock(doc, cb.id);\n}\n\nfunction prevInColumns(\n doc: DocState,\n cb: ColumnsBlock,\n a: Anchor,\n): Anchor {\n const c = a.path[0] ?? 0;\n const off = a.path[1] ?? 0;\n if (off > 0) return { blockId: cb.id, path: [c, off - 1], offset: off - 1 };\n if (c > 0) {\n const prev = cb.cells[c - 1] ?? [];\n const len = prev.reduce((n, run) => n + run.text.length, 0);\n return { blockId: cb.id, path: [c - 1, len], offset: len };\n }\n return stepIntoPrevBlock(doc, cb.id);\n}\n\nfunction prevInTable(doc: DocState, t: TableBlock, a: Anchor): Anchor {\n const r = a.path[0] ?? 0;\n const c = a.path[1] ?? 0;\n const off = a.path[2] ?? 0;\n if (off > 0) {\n return { blockId: t.id, path: [r, c, off - 1], offset: off - 1 };\n }\n // start of cell — back into previous cell, or step out.\n if (c > 0) {\n const prevCell = t.cells[r]?.[c - 1] ?? [];\n const len = prevCell.reduce((n, run) => n + run.text.length, 0);\n return { blockId: t.id, path: [r, c - 1, len], offset: len };\n }\n if (r > 0) {\n const lastCol = t.cols - 1;\n const prevCell = t.cells[r - 1]?.[lastCol] ?? [];\n const len = prevCell.reduce((n, run) => n + run.text.length, 0);\n return {\n blockId: t.id,\n path: [r - 1, lastCol, len],\n offset: len,\n };\n }\n return stepIntoPrevBlock(doc, t.id);\n}\n\n// ---------------------------------------------------------------------------\n// Block-edge: Home / End\n// ---------------------------------------------------------------------------\n\nexport function homeOfBlock(doc: DocState, a: Anchor): Anchor {\n return startAnchorOfBlock(doc, a.blockId) ?? a;\n}\n\nexport function endOfBlock(doc: DocState, a: Anchor): Anchor {\n return endAnchorOfBlock(doc, a.blockId) ?? a;\n}\n\n// ---------------------------------------------------------------------------\n// Doc edges\n// ---------------------------------------------------------------------------\n\nexport function homeOfDoc(doc: DocState): Anchor {\n const id = doc.order[0];\n if (id == null) return { blockId: \"\", path: [0], offset: 0 };\n return startAnchorOfBlock(doc, id)!;\n}\n\nexport function endOfDocAnchor(doc: DocState): Anchor {\n const id = doc.order[doc.order.length - 1];\n if (id == null) return { blockId: \"\", path: [0], offset: 0 };\n return endAnchorOfBlock(doc, id)!;\n}\n\n// ---------------------------------------------------------------------------\n// Block-jumps (used as a fallback for ArrowUp/Down when measurement is\n// unavailable — e.g. headless tests or blocks that haven't laid out yet).\n// ---------------------------------------------------------------------------\n\nexport function blockAbove(doc: DocState, a: Anchor): Anchor {\n // For tables, vertical motion stays inside the table — move to the cell\n // directly above in the same column.\n const block = getBlock(doc, a.blockId);\n if (block?.type === \"table\") {\n const t = block as TableBlock;\n const r = a.path[0] ?? 0;\n const c = a.path[1] ?? 0;\n if (r > 0) {\n const cell = t.cells[r - 1]?.[c] ?? [];\n const len = runsLen(cell);\n const off = Math.min(a.path[2] ?? 0, len);\n return { blockId: t.id, path: [r - 1, c, off], offset: off };\n }\n // First row — exit upward to whatever block precedes the table.\n return stepIntoPrevBlock(doc, t.id);\n }\n const i = findPos(doc, a.blockId);\n if (i <= 0) return a;\n const prevId = doc.order[i - 1]!;\n const off = Math.min(anchorOffset(a), blockMaxOffset(doc, prevId));\n return { blockId: prevId, path: [off], offset: off };\n}\n\nexport function blockBelow(doc: DocState, a: Anchor): Anchor {\n const block = getBlock(doc, a.blockId);\n if (block?.type === \"table\") {\n const t = block as TableBlock;\n const r = a.path[0] ?? 0;\n const c = a.path[1] ?? 0;\n if (r < t.rows - 1) {\n const cell = t.cells[r + 1]?.[c] ?? [];\n const len = runsLen(cell);\n const off = Math.min(a.path[2] ?? 0, len);\n return { blockId: t.id, path: [r + 1, c, off], offset: off };\n }\n return stepIntoNextBlock(doc, t.id);\n }\n const i = findPos(doc, a.blockId);\n if (i < 0 || i >= doc.order.length - 1) return a;\n const nextId = doc.order[i + 1]!;\n const off = Math.min(anchorOffset(a), blockMaxOffset(doc, nextId));\n return { blockId: nextId, path: [off], offset: off };\n}\n\nfunction runsLen(runs: InlineRun[]): number {\n let n = 0;\n for (const r of runs) n += r.text.length;\n return n;\n}\n\n// ---------------------------------------------------------------------------\n// Word-level navigation — Cmd/Ctrl + Arrow on macOS / Windows.\n// ---------------------------------------------------------------------------\n\n/** Concatenate runs into a single string for word-boundary scanning. */\nfunction runsText(runs: InlineRun[]): string {\n let s = \"\";\n for (const r of runs) s += r.text;\n return s;\n}\n\nfunction blockText(doc: DocState, blockId: string): string | null {\n const b = getBlock(doc, blockId);\n if (!b) return null;\n if (isTextBearing(b)) return runsText((b as TextBearingBlock).runs);\n if (b.type === \"table\") {\n // Word nav inside a table operates on the current cell only.\n return null;\n }\n return null;\n}\n\nfunction tableCellText(t: TableBlock, r: number, c: number): string {\n const cell = t.cells[r]?.[c] ?? [];\n return runsText(cell);\n}\n\nexport function nextWord(doc: DocState, a: Anchor): Anchor {\n const block = getBlock(doc, a.blockId);\n if (!block) return a;\n if (block.type === \"table\") {\n const t = block as TableBlock;\n const r = a.path[0] ?? 0;\n const c = a.path[1] ?? 0;\n const off = a.path[2] ?? 0;\n const text = tableCellText(t, r, c);\n if (off < text.length) {\n const nx = nextWordOffset(text, off);\n return { blockId: t.id, path: [r, c, nx], offset: nx };\n }\n return nextAnchor(doc, a); // step into next cell / block\n }\n const text = blockText(doc, a.blockId);\n if (text == null) return nextAnchor(doc, a);\n const off = anchorOffset(a);\n if (off < text.length) {\n const nx = nextWordOffset(text, off);\n return withCharOffset(a, nx);\n }\n // At end of block — cross into next block at offset 0.\n return stepIntoNextBlock(doc, a.blockId);\n}\n\nexport function prevWord(doc: DocState, a: Anchor): Anchor {\n const block = getBlock(doc, a.blockId);\n if (!block) return a;\n if (block.type === \"table\") {\n const t = block as TableBlock;\n const r = a.path[0] ?? 0;\n const c = a.path[1] ?? 0;\n const off = a.path[2] ?? 0;\n if (off > 0) {\n const text = tableCellText(t, r, c);\n const px = prevWordOffset(text, off);\n return { blockId: t.id, path: [r, c, px], offset: px };\n }\n return prevAnchor(doc, a);\n }\n const text = blockText(doc, a.blockId);\n if (text == null) return prevAnchor(doc, a);\n const off = anchorOffset(a);\n if (off > 0) {\n const px = prevWordOffset(text, off);\n return withCharOffset(a, px);\n }\n return stepIntoPrevBlock(doc, a.blockId);\n}\n",
|
|
12
|
+
"import type { Store } from \"creo\";\nimport {\n blockAbove,\n blockBelow,\n endOfBlock,\n endOfDocAnchor,\n homeOfBlock,\n homeOfDoc,\n nextAnchor,\n nextWord,\n prevAnchor,\n prevWord,\n} from \"../controller/navigation\";\nimport {\n caret,\n range,\n selectionEnd,\n selectionStart,\n} from \"../controller/selection\";\nimport type { Anchor, DocState, Selection } from \"../model/types\";\n\nexport type NavStores = {\n docStore: Store<DocState>;\n selStore: Store<Selection>;\n};\n\nexport type AnchorStep = (doc: DocState, a: Anchor) => Anchor;\n\n/**\n * Move the cursor by applying `step` to the current focus side.\n * - `extend === false` → collapse to the new anchor.\n * - `extend === true` → keep the original anchor, move the focus.\n */\nexport function moveBy(\n { docStore, selStore }: NavStores,\n step: AnchorStep,\n extend: boolean,\n): void {\n const doc = docStore.get();\n const sel = selStore.get();\n const focus = step(doc, selectionEnd(sel));\n if (!extend) {\n selStore.set(caret(focus));\n return;\n }\n const anchor = selectionStart(sel);\n if (sameAnchor(anchor, focus)) {\n selStore.set(caret(focus));\n } else {\n selStore.set(range(anchor, focus));\n }\n}\n\nexport function moveTo(\n { selStore }: NavStores,\n anchor: Anchor,\n extend: boolean,\n): void {\n if (!extend) {\n selStore.set(caret(anchor));\n return;\n }\n const cur = selStore.get();\n const start = selectionStart(cur);\n if (sameAnchor(start, anchor)) {\n selStore.set(caret(anchor));\n } else {\n selStore.set(range(start, anchor));\n }\n}\n\nfunction sameAnchor(a: Anchor, b: Anchor): boolean {\n if (a.blockId !== b.blockId) return false;\n if (a.path.length !== b.path.length) return false;\n for (let i = 0; i < a.path.length; i++) {\n if (a.path[i] !== b.path[i]) return false;\n }\n return true;\n}\n\n// Pre-bound steppers for keymap convenience.\nexport const STEP = {\n next: nextAnchor,\n prev: prevAnchor,\n nextWord,\n prevWord,\n up: blockAbove,\n down: blockBelow,\n home: homeOfBlock,\n end: endOfBlock,\n docHome: (doc: DocState, _a: Anchor) => homeOfDoc(doc),\n docEnd: (doc: DocState, _a: Anchor) => endOfDocAnchor(doc),\n} satisfies Record<string, AnchorStep>;\n",
|
|
13
|
+
"import type { Store } from \"creo\";\nimport {\n concatRuns,\n deleteRange,\n isTextBearing,\n splitRunsAt,\n type TextBearingBlock,\n} from \"../model/blockText\";\nimport {\n findPos,\n getBlock,\n insertManyAt,\n newBlockId,\n removeBlock,\n removeBlocks,\n updateBlock,\n} from \"../model/doc\";\nimport {\n anchorOffset,\n caret,\n caretAt,\n isCaret,\n orderedRange,\n} from \"../controller/selection\";\nimport type {\n Block,\n BlockSpec,\n DocState,\n ListItemBlock,\n Selection,\n} from \"../model/types\";\nimport type { TextBearingBlock as TBB } from \"../model/blockText\";\n\nexport type Stores = {\n docStore: Store<DocState>;\n selStore: Store<Selection>;\n};\n\n/**\n * Insert a list of pre-parsed blocks at the current caret. If the selection\n * is a range, it is collapsed first.\n *\n * Splice rules (matches every consumer rich-text editor I'm aware of):\n * - Single text-bearing block: inline-merge into the current block.\n * - Multiple blocks: split the current block at the caret; the first\n * pasted block's runs join the LEFT half, the last pasted block's runs\n * are followed by the RIGHT half (in a new block of the last one's\n * type), and any blocks in between are inserted as new blocks.\n * - Non-text blocks (img / table): always become a separate block, with\n * the surrounding paragraph split if needed.\n */\nexport function insertBlocks(stores: Stores, blocks: BlockSpec[]): boolean {\n if (blocks.length === 0) return false;\n\n // Collapse ranges first by deleting them.\n if (stores.selStore.get().kind === \"range\") {\n if (!collapseRange(stores)) return false;\n }\n\n const doc = stores.docStore.get();\n const sel = stores.selStore.get();\n if (!isCaret(sel)) return false;\n const at = sel.at;\n const cur = getBlock(doc, at.blockId);\n if (!cur) return false;\n\n // Caret must be inside a text-bearing block to splice cleanly. If it's an\n // image / table block, paste produces blocks AFTER the current block.\n if (!isTextBearing(cur)) {\n return insertBlocksAfter(stores, at.blockId, blocks);\n }\n\n // ---- Fast path: single text-bearing block → inline merge ----\n if (blocks.length === 1) {\n const only = blocks[0]!;\n if (isTextBearing(only as Block)) {\n return inlineMerge(stores, cur as TBB, anchorOffset(at), only);\n }\n }\n\n // ---- General path ----\n return splitAndInsert(stores, cur as TBB, anchorOffset(at), blocks);\n}\n\nfunction inlineMerge(\n stores: Stores,\n cur: TBB,\n off: number,\n insertedSpec: BlockSpec,\n): boolean {\n const inserted = ensureBlock(insertedSpec);\n if (!isTextBearing(inserted)) return false;\n const insertedRuns = (inserted as TBB).runs;\n const [left, right] = splitRunsAt(cur.runs, off);\n const merged = concatRuns(concatRuns(left, insertedRuns), right);\n const newBlock: Block = { ...cur, runs: merged } as Block;\n stores.docStore.set(updateBlock(stores.docStore.get(), newBlock));\n let totalInserted = 0;\n for (const r of insertedRuns) totalInserted += r.text.length;\n stores.selStore.set(caret(caretAt(cur.id, off + totalInserted)));\n return true;\n}\n\nfunction splitAndInsert(\n stores: Stores,\n cur: TBB,\n off: number,\n blocks: BlockSpec[],\n): boolean {\n const [leftRuns, rightRuns] = splitRunsAt(cur.runs, off);\n const first = blocks[0]!;\n const last = blocks[blocks.length - 1]!;\n // If the current block is completely empty (no runs at all), let the\n // first pasted block's TYPE win: pasting a heading into an empty paragraph\n // should leave a heading, not a paragraph with the heading's text.\n const curIsEmpty = leftRuns.length === 0 && rightRuns.length === 0;\n\n let workingDoc = stores.docStore.get();\n if (isTextBearingSpec(first)) {\n const firstRuns = (first as Extract<BlockSpec, { runs: unknown }> & {\n runs: TBB[\"runs\"];\n }).runs;\n const newCurRuns = concatRuns(leftRuns, firstRuns);\n if (curIsEmpty) {\n // Replace current block in place, adopting the first block's type.\n const replacement = upgradeBlockToSpec(cur, first, newCurRuns);\n workingDoc = updateBlock(workingDoc, replacement);\n } else {\n workingDoc = updateBlock(workingDoc, {\n ...cur,\n runs: newCurRuns,\n } as Block);\n }\n } else {\n // First inserted block is non-text (img / table) — keep current block's\n // left runs as-is, then we'll insert `first` as a new block right after.\n workingDoc = updateBlock(workingDoc, { ...cur, runs: leftRuns } as Block);\n }\n\n // Build the list of NEW blocks to insert after `cur`. That includes:\n // - `first` as its own block IF non-text.\n // - Every middle block as-is.\n // - `last` as its own block, with rightRuns appended if last is text.\n const newBlocks: BlockSpec[] = [];\n if (!isTextBearingSpec(first)) {\n newBlocks.push(first);\n }\n for (let i = 1; i < blocks.length - 1; i++) {\n newBlocks.push(blocks[i]!);\n }\n if (blocks.length > 1) {\n if (isTextBearingSpec(last)) {\n newBlocks.push(\n appendRunsToTextSpec(last, rightRuns, /*newId*/ true),\n );\n } else {\n newBlocks.push(last);\n // The rightRuns need their own block since the non-text last can't\n // hold them.\n if (rightRuns.length) {\n newBlocks.push({\n id: newBlockId(),\n type: \"p\",\n runs: rightRuns,\n });\n }\n }\n } else {\n // Single non-text block: rightRuns go into a new paragraph after it.\n if (rightRuns.length) {\n newBlocks.push({\n id: newBlockId(),\n type: \"p\",\n runs: rightRuns,\n });\n }\n }\n\n const curPos = findPos(workingDoc, cur.id);\n workingDoc = insertManyAt(workingDoc, curPos + 1, newBlocks);\n stores.docStore.set(workingDoc);\n\n // Place caret at the END of the last inserted block's \"logical content\"\n // — that's the end of `last`'s runs (before rightRuns are appended).\n const lastInsertedBlock = (() => {\n if (blocks.length > 1 && isTextBearingSpec(last)) {\n // Find the new block id we created via appendRunsToTextSpec.\n // We pushed it last in newBlocks (or second-to-last for non-text last).\n return newBlocks[newBlocks.length - 1]!;\n }\n if (blocks.length === 1 && !isTextBearingSpec(last)) {\n // Single non-text block — caret right after it.\n return newBlocks[0]!;\n }\n // Default: caret stays at end of cur's new text.\n return null;\n })();\n\n if (lastInsertedBlock && isTextBearingSpec(lastInsertedBlock)) {\n const lastSpec = lastInsertedBlock as Extract<BlockSpec, { runs: unknown }>;\n let originalLen = 0;\n if (isTextBearingSpec(last)) {\n const lastRuns = (last as Extract<BlockSpec, { runs: unknown }> & {\n runs: TBB[\"runs\"];\n }).runs;\n for (const r of lastRuns) originalLen += r.text.length;\n } else {\n originalLen = 0;\n }\n void lastSpec;\n stores.selStore.set(\n caret(caretAt(lastInsertedBlock.id!, originalLen)),\n );\n } else if (blocks.length === 1 && !isTextBearingSpec(first)) {\n // Caret after the inserted non-text block — sit at start of next block.\n const newCurEnd = (cur.runs ? sumRuns(leftRuns) : 0);\n stores.selStore.set(caret(caretAt(cur.id, newCurEnd)));\n } else if (blocks.length === 1 && isTextBearingSpec(first)) {\n // Already handled by inlineMerge fast path; defensive default:\n stores.selStore.set(caret(caretAt(cur.id, off)));\n }\n\n return true;\n}\n\nfunction insertBlocksAfter(\n stores: Stores,\n afterId: string,\n blocks: BlockSpec[],\n): boolean {\n const doc = stores.docStore.get();\n const pos = findPos(doc, afterId) + 1;\n const next = insertManyAt(doc, pos, blocks);\n stores.docStore.set(next);\n // Caret to start of last inserted block.\n const lastId = blocks[blocks.length - 1]!.id ?? \"\";\n if (lastId) stores.selStore.set(caret(caretAt(lastId, 0)));\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// insertImage / insertTable convenience shims (used by M8/M9)\n// ---------------------------------------------------------------------------\n\nexport function insertImage(\n stores: Stores,\n payload: { src: string; alt?: string; width?: number; height?: number },\n): boolean {\n const block: BlockSpec = {\n id: newBlockId(),\n type: \"img\",\n src: payload.src,\n alt: payload.alt,\n width: payload.width,\n height: payload.height,\n };\n return insertBlocks(stores, [block]);\n}\n\nexport function insertColumns(\n stores: Stores,\n payload: { cols: number },\n): boolean {\n const cells: { text: string }[][] = [];\n for (let c = 0; c < payload.cols; c++) cells.push([]);\n const block: BlockSpec = {\n id: newBlockId(),\n type: \"columns\",\n cols: payload.cols,\n cells,\n };\n return insertBlocks(stores, [block]);\n}\n\nexport function insertTable(\n stores: Stores,\n payload: { rows: number; cols: number },\n): boolean {\n const cells: { text: string }[][][] = [];\n for (let r = 0; r < payload.rows; r++) {\n const row: { text: string }[][] = [];\n for (let c = 0; c < payload.cols; c++) row.push([]);\n cells.push(row);\n }\n const block: BlockSpec = {\n id: newBlockId(),\n type: \"table\",\n rows: payload.rows,\n cols: payload.cols,\n cells,\n };\n return insertBlocks(stores, [block]);\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Build a block that keeps `cur`'s id + index but takes its TYPE / extra\n * fields from `spec`. Used when pasting into an empty block — we want the\n * pasted block's type to win.\n */\nfunction upgradeBlockToSpec(\n cur: TBB,\n spec: BlockSpec,\n runs: TBB[\"runs\"],\n): Block {\n switch (spec.type) {\n case \"p\":\n case \"h1\":\n case \"h2\":\n case \"h3\":\n case \"h4\":\n case \"h5\":\n case \"h6\":\n return { id: cur.id, index: cur.index, type: spec.type, runs } as Block;\n case \"li\":\n return {\n id: cur.id,\n index: cur.index,\n type: \"li\",\n ordered: (spec as ListItemBlock).ordered,\n depth: (spec as ListItemBlock).depth ?? 0,\n runs,\n } as Block;\n default:\n return { ...cur, runs } as Block;\n }\n}\n\nfunction isTextBearingSpec(spec: BlockSpec): boolean {\n return (\n spec.type === \"p\" ||\n spec.type === \"h1\" ||\n spec.type === \"h2\" ||\n spec.type === \"h3\" ||\n spec.type === \"h4\" ||\n spec.type === \"h5\" ||\n spec.type === \"h6\" ||\n spec.type === \"li\"\n );\n}\n\nfunction ensureBlock(spec: BlockSpec): Block {\n // `BlockSpec` lacks `index`; the doc layer assigns one when actually\n // inserting via insertManyAt. For helpers that just need to inspect runs\n // we cast — the index field is never read here.\n return spec as unknown as Block;\n}\n\nfunction sumRuns(runs: TBB[\"runs\"]): number {\n let n = 0;\n for (const r of runs) n += r.text.length;\n return n;\n}\n\nfunction appendRunsToTextSpec(\n spec: BlockSpec,\n rightRuns: TBB[\"runs\"],\n newId: boolean,\n): BlockSpec {\n const id = newId ? newBlockId() : spec.id;\n const baseRuns = (spec as Extract<BlockSpec, { runs: unknown }> & {\n runs: TBB[\"runs\"];\n }).runs;\n const merged = concatRuns(baseRuns, rightRuns);\n switch (spec.type) {\n case \"p\":\n case \"h1\":\n case \"h2\":\n case \"h3\":\n case \"h4\":\n case \"h5\":\n case \"h6\":\n return { id, type: spec.type, runs: merged };\n case \"li\":\n return {\n id,\n type: \"li\",\n ordered: (spec as ListItemBlock).ordered,\n depth: (spec as ListItemBlock).depth ?? 0,\n runs: merged,\n };\n default:\n return spec;\n }\n}\n\nfunction collapseRange(stores: Stores): boolean {\n const doc = stores.docStore.get();\n const sel = stores.selStore.get();\n if (sel.kind === \"caret\") return true;\n const { start, end } = orderedRange(doc, sel);\n if (start.blockId === end.blockId) {\n const block = getBlock(doc, start.blockId);\n if (!block || !isTextBearing(block)) return false;\n const sOff = anchorOffset(start);\n const eOff = anchorOffset(end);\n if (sOff === eOff) {\n stores.selStore.set(caret(start));\n return true;\n }\n const newRuns = deleteRange((block as TBB).runs, sOff, eOff);\n stores.docStore.set(\n updateBlock(doc, {\n ...(block as TBB),\n runs: newRuns,\n } as Block),\n );\n stores.selStore.set(caret(caretAt(block.id, sOff)));\n return true;\n }\n // Multi-block range: lean on structuralCommands' helper logic by\n // delegating through mergeBackward/mergeForward semantics is messy here,\n // so we re-implement a slim version inline.\n const startBlock = getBlock(doc, start.blockId);\n const endBlock = getBlock(doc, end.blockId);\n if (\n !startBlock ||\n !endBlock ||\n !isTextBearing(startBlock) ||\n !isTextBearing(endBlock)\n ) {\n return false;\n }\n const sOff = anchorOffset(start);\n const eOff = anchorOffset(end);\n const [leftRuns] = splitRunsAt((startBlock as TBB).runs, sOff);\n const [, rightRuns] = splitRunsAt((endBlock as TBB).runs, eOff);\n const merged = concatRuns(leftRuns, rightRuns);\n const startI = findPos(doc, start.blockId);\n const endI = findPos(doc, end.blockId);\n let working = updateBlock(doc, {\n ...(startBlock as TBB),\n runs: merged,\n } as Block);\n const idsToRemove: string[] = [];\n for (let i = startI + 1; i <= endI; i++) idsToRemove.push(doc.order[i]!);\n working = removeBlocks(working, idsToRemove);\n stores.docStore.set(working);\n stores.selStore.set(caret(caretAt(start.blockId, sOff)));\n return true;\n}\n",
|
|
14
|
+
"import type { Store } from \"creo\";\nimport { insertImage as cmdInsertImage } from \"./insertCommands\";\nimport { removeBlock } from \"../model/doc\";\nimport { caret, isCaret } from \"../controller/selection\";\nimport { isAtomicBlockType } from \"../plugin/atomic\";\nimport type { DocState, Selection } from \"../model/types\";\n\nexport type Stores = {\n docStore: Store<DocState>;\n selStore: Store<Selection>;\n};\n\nexport type UploadFn = (file: File) => Promise<string>;\n\n/**\n * Pick an image source for a File. If `upload` is provided, await its URL;\n * otherwise fall back to `URL.createObjectURL`.\n */\nexport async function fileToImageSrc(\n file: File,\n upload?: UploadFn,\n): Promise<string> {\n if (upload) return upload(file);\n return URL.createObjectURL(file);\n}\n\n/**\n * Drop / paste a single File into the editor as an image block. Async\n * (must await an upload when configured).\n */\nexport async function insertImageFile(\n stores: Stores,\n file: File,\n upload?: UploadFn,\n): Promise<boolean> {\n if (!file.type.startsWith(\"image/\")) return false;\n const src = await fileToImageSrc(file, upload);\n return cmdInsertImage(stores, { src, alt: file.name });\n}\n\n/**\n * Process a FileList (from paste or drop). Each image becomes its own block;\n * non-image files are ignored.\n */\nexport async function insertImageFiles(\n stores: Stores,\n files: FileList | File[],\n upload?: UploadFn,\n): Promise<boolean> {\n let any = false;\n const list = Array.from(files);\n for (const f of list) {\n if (!f.type.startsWith(\"image/\")) continue;\n if (await insertImageFile(stores, f, upload)) any = true;\n }\n return any;\n}\n\n/**\n * Delete the atomic block currently under the caret. Backspace / Delete\n * routes here whenever the caret sits on any atomic block (image, calendar,\n * or any plugin block flagged `isAtomic`). The caret lands at the start of\n * whatever block survives in that slot — preferring the next sibling, then\n * the previous, then the first remaining block.\n */\nexport function deleteSelectedAtomic(stores: Stores): boolean {\n const sel = stores.selStore.get();\n if (!isCaret(sel)) return false;\n const doc = stores.docStore.get();\n const block = doc.byId.get(sel.at.blockId);\n if (!block || !isAtomicBlockType(block.type)) return false;\n // Find adjacent block to land caret on.\n const i = doc.order.indexOf(block.id);\n const next = removeBlock(doc, block.id);\n stores.docStore.set(next);\n const newId = next.order[i] ?? next.order[i - 1] ?? next.order[0];\n if (newId == null) {\n stores.selStore.set(caret({ blockId: \"\", path: [0], offset: 0 }));\n } else {\n stores.selStore.set(caret({ blockId: newId, path: [0], offset: 0 }));\n }\n return true;\n}\n\n/** Backwards-compatible alias — img used to be the only atomic block. */\nexport const deleteSelectedImage = deleteSelectedAtomic;\n",
|
|
15
|
+
"import type { Store } from \"creo\";\nimport {\n insertImageFiles,\n type UploadFn,\n} from \"../commands/imageCommands\";\nimport type { DocState, Selection } from \"../model/types\";\n\nexport type DropStores = {\n docStore: Store<DocState>;\n selStore: Store<Selection>;\n};\n\nexport type DropHandle = { destroy: () => void };\n\n/**\n * Wire dragover + drop on the editor root so dragged image files become\n * image blocks. We only swallow the drop when at least one image file is\n * present; other drops fall through to the browser's default behaviour\n * (so dragging text from elsewhere keeps working).\n */\nexport function attachDrop(\n root: HTMLElement,\n stores: DropStores,\n upload?: UploadFn,\n): DropHandle {\n const onDragOver = (e: Event) => {\n const ev = e as DragEvent;\n if (!ev.dataTransfer) return;\n // Allow drop only when there's at least one image item.\n const items = ev.dataTransfer.items;\n let hasImage = false;\n if (items) {\n for (const it of Array.from(items)) {\n if (it.kind === \"file\" && it.type.startsWith(\"image/\")) {\n hasImage = true;\n break;\n }\n }\n }\n if (hasImage) {\n ev.preventDefault();\n ev.dataTransfer.dropEffect = \"copy\";\n }\n };\n\n const onDrop = (e: Event) => {\n const ev = e as DragEvent;\n const files = ev.dataTransfer?.files;\n if (!files || files.length === 0) return;\n let hasImage = false;\n for (const f of Array.from(files)) {\n if (f.type.startsWith(\"image/\")) {\n hasImage = true;\n break;\n }\n }\n if (!hasImage) return;\n ev.preventDefault();\n void insertImageFiles(stores, files, upload);\n };\n\n root.addEventListener(\"dragover\", onDragOver);\n root.addEventListener(\"drop\", onDrop);\n\n return {\n destroy() {\n root.removeEventListener(\"dragover\", onDragOver);\n root.removeEventListener(\"drop\", onDrop);\n },\n };\n}\n",
|
|
16
|
+
"// ---------------------------------------------------------------------------\n// HTML codec registry — paste-in / copy-out per block kind.\n//\n// Two indexes:\n// - parserByTag: HTML tag → parser fn (first plugin registered wins)\n// - serializerByType: block.type → serialize fn\n//\n// The HTML parser walks fragment children and calls the parser for the\n// first matched tag, falling through to the generic walkers for unknown\n// elements (block-element-wrap-into-paragraph, etc.). Serialization is\n// fully driven by registry entries — every built-in block kind registers a\n// serializer so docToHtml / selectionToClipboard need no per-kind switch.\n// ---------------------------------------------------------------------------\n\nimport type { Block, BlockSpec } from \"../model/types\";\nimport type { HtmlBlockCodec, HtmlParseCtx } from \"./types\";\n\ntype ParserFn = (el: HTMLElement, ctx: HtmlParseCtx) => BlockSpec | null;\ntype SerializerFn = (b: Block) => string;\n\nconst parserByTag = new Map<string, ParserFn>();\nconst serializerByType = new Map<string, SerializerFn>();\n\nexport function registerHtmlBlockCodec(type: string, codec: HtmlBlockCodec): void {\n if (codec.parseHTML && codec.matchHTML) {\n for (const tag of codec.matchHTML) {\n // First registration wins — built-ins land before user plugins.\n if (!parserByTag.has(tag)) parserByTag.set(tag, codec.parseHTML);\n }\n }\n if (codec.serializeHTML) {\n serializerByType.set(type, codec.serializeHTML);\n }\n}\n\nexport function getHtmlParserForTag(tag: string): ParserFn | null {\n return parserByTag.get(tag) ?? null;\n}\n\nexport function getHtmlSerializer(type: string): SerializerFn | null {\n return serializerByType.get(type) ?? null;\n}\n",
|
|
17
|
+
"// ---------------------------------------------------------------------------\n// HTML parser — sanitize + walk into BlockSpec[] for `setDocFromHTML` and\n// paste handling.\n//\n// Per-block tag parsers live in plugins (registered via `BlockDef.htmlCodec`).\n// This file owns:\n// - sanitization (strip script/style/on* attrs, neutralize javascript:)\n// - structural walking (recurse into block-element wrappers like\n// <div>/<section>/<article>, group <li> by their <ul>/<ol> ancestor and\n// track nested-list depth)\n// - the bare-text-into-paragraph fallback so unknown HTML still produces\n// something usable\n//\n// Note: <ul>/<ol> handling stays here because depth + ordered-flag are\n// derived from ancestor list elements, not from the <li> alone.\n// ---------------------------------------------------------------------------\n\nimport { newBlockId } from \"../model/doc\";\nimport { getHtmlParserForTag } from \"../plugin/htmlCodec\";\nimport type { BlockSpec, InlineRun, Mark } from \"../model/types\";\n\n/**\n * Parse a fragment of HTML into a sanitized list of BlockSpec.\n *\n * Sanitization rules:\n * - `<script>`, `<style>`, `<link>`, `<meta>` content is dropped entirely.\n * - All `on*` attributes are stripped.\n * - `javascript:` URLs become \"#\".\n * - Unknown elements become inline (their text content is preserved, marks\n * of any ancestor mark elements still apply).\n * - Block elements outside our model (article, section, etc.) become\n * paragraphs (recursing into their children when those are themselves\n * block-level).\n *\n * Falls back to a single paragraph if no block-level structure is present.\n */\nexport function parseHTML(html: string): BlockSpec[] {\n const sanitized = sanitize(html);\n const tpl = document.createElement(\"template\");\n tpl.innerHTML = sanitized;\n const frag = tpl.content;\n const out: BlockSpec[] = [];\n for (const node of Array.from(frag.childNodes)) {\n walkBlock(node, [], out);\n }\n if (out.length === 0) {\n const text = collectText(frag);\n if (text.trim().length) {\n out.push({\n id: newBlockId(),\n type: \"p\",\n runs: [{ text }],\n });\n }\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Sanitization — drop dangerous tags / URLs before parsing into a Document.\n// ---------------------------------------------------------------------------\n\nfunction sanitize(html: string): string {\n let s = html;\n s = s.replace(/<\\s*(script|style|link|meta)\\b[^>]*>[\\s\\S]*?<\\s*\\/\\s*\\1\\s*>/gi, \"\");\n s = s.replace(/<\\s*(script|style|link|meta)\\b[^>]*\\/?>/gi, \"\");\n s = s.replace(/\\s+on[a-z]+\\s*=\\s*(\"[^\"]*\"|'[^']*'|[^\\s>]+)/gi, \"\");\n s = s.replace(/(href|src)\\s*=\\s*(\"\\s*javascript:[^\"]*\"|'\\s*javascript:[^']*')/gi, \"$1=\\\"#\\\"\");\n return s;\n}\n\n// ---------------------------------------------------------------------------\n// Block walker — delegates per-tag work to plugin-registered parsers.\n// ---------------------------------------------------------------------------\n\nconst PARAGRAPH_WRAPPER_TAGS = new Set([\n \"div\",\n \"section\",\n \"article\",\n \"aside\",\n \"header\",\n \"footer\",\n \"main\",\n \"blockquote\",\n]);\n\nfunction walkBlock(node: Node, marks: Mark[], out: BlockSpec[]): void {\n if (node.nodeType === 3) {\n const t = (node as Text).data;\n if (t.trim().length === 0) return;\n out.push({\n id: newBlockId(),\n type: \"p\",\n runs: [{ text: t, ...(marks.length ? { marks: new Set(marks) } : {}) }],\n });\n return;\n }\n if (node.nodeType !== 1) return;\n const el = node as HTMLElement;\n const tag = el.tagName.toLowerCase();\n\n // List handling — ul/ol drive the walker recursively, accumulating depth.\n if (tag === \"ul\" || tag === \"ol\") {\n walkList(el, tag === \"ol\", 0, marks, out);\n return;\n }\n\n // Bare <br/> outside any block — empty paragraph.\n if (tag === \"br\") {\n out.push({ id: newBlockId(), type: \"p\", runs: [] });\n return;\n }\n\n // Plugin-registered parser for this tag wins.\n const parser = getHtmlParserForTag(tag);\n if (parser) {\n const block = parser(el, { marks });\n if (block) out.push(block);\n return;\n }\n\n // Unknown wrapper — recurse into block children, otherwise flatten as a\n // paragraph.\n if (PARAGRAPH_WRAPPER_TAGS.has(tag) || tag === \"html\" || tag === \"body\") {\n if (hasBlockChild(el)) {\n for (const c of Array.from(el.childNodes)) walkBlock(c, marks, out);\n return;\n }\n const runs = collectRuns(el, marks);\n if (runs.length === 0 && el.childElementCount === 0) return;\n out.push({ id: newBlockId(), type: \"p\", runs: runs.length ? runs : [] });\n return;\n }\n\n // Truly unknown element with mixed content — flatten or recurse.\n if (hasBlockChild(el)) {\n for (const c of Array.from(el.childNodes)) walkBlock(c, marks, out);\n return;\n }\n const runs = collectRuns(el, marks);\n if (runs.length) out.push({ id: newBlockId(), type: \"p\", runs });\n}\n\nfunction walkList(\n listEl: HTMLElement,\n ordered: boolean,\n depth: 0 | 1 | 2 | 3,\n marks: Mark[],\n out: BlockSpec[],\n): void {\n for (const child of Array.from(listEl.children)) {\n if (child.tagName.toLowerCase() !== \"li\") continue;\n const li = child as HTMLElement;\n const runs: InlineRun[] = [];\n for (const c of Array.from(li.childNodes)) {\n if (c.nodeType === 1) {\n const t = (c as HTMLElement).tagName.toLowerCase();\n if (t === \"ul\" || t === \"ol\") continue;\n }\n runs.push(...runsFor(c, marks));\n }\n out.push({\n id: newBlockId(),\n type: \"li\",\n ordered,\n depth,\n runs,\n });\n for (const c of Array.from(li.children)) {\n const t = c.tagName.toLowerCase();\n if (t === \"ul\" || t === \"ol\") {\n const nested = c as HTMLElement;\n const nestedOrdered = t === \"ol\";\n const nextDepth = (Math.min(3, depth + 1) as 0 | 1 | 2 | 3);\n walkList(nested, nestedOrdered, nextDepth, marks, out);\n }\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Inline-runs collection — kept here so the structural walker (lists,\n// fallbacks) can build runs without going through the plugin registry.\n// ---------------------------------------------------------------------------\n\nconst MARK_TAGS: Record<string, Mark> = {\n b: \"b\",\n strong: \"b\",\n i: \"i\",\n em: \"i\",\n u: \"u\",\n s: \"s\",\n strike: \"s\",\n del: \"s\",\n code: \"code\",\n};\n\nfunction runsFor(node: Node, marks: Mark[]): InlineRun[] {\n if (node.nodeType === 3) {\n const t = (node as Text).data;\n if (t.length === 0) return [];\n return [\n {\n text: t,\n ...(marks.length ? { marks: new Set(marks) } : {}),\n },\n ];\n }\n if (node.nodeType !== 1) return [];\n const el = node as HTMLElement;\n const tag = el.tagName.toLowerCase();\n if (tag === \"br\") {\n return [{ text: \"\\n\", ...(marks.length ? { marks: new Set(marks) } : {}) }];\n }\n const additional = MARK_TAGS[tag];\n const nextMarks = additional ? [...marks, additional] : marks;\n const out: InlineRun[] = [];\n for (const c of Array.from(el.childNodes)) {\n out.push(...runsFor(c, nextMarks));\n }\n return out;\n}\n\nfunction collectRuns(el: HTMLElement, marks: Mark[]): InlineRun[] {\n const out: InlineRun[] = [];\n for (const c of Array.from(el.childNodes)) {\n out.push(...runsFor(c, marks));\n }\n return out.filter((r) => r.text.length > 0);\n}\n\nfunction collectText(node: Node): string {\n let s = \"\";\n const walk = (n: Node) => {\n if (n.nodeType === 3) s += (n as Text).data;\n for (const c of Array.from(n.childNodes)) walk(c);\n };\n walk(node);\n return s;\n}\n\nfunction hasBlockChild(el: HTMLElement): boolean {\n for (const c of Array.from(el.children)) {\n const tag = c.tagName.toLowerCase();\n if (\n tag === \"p\" ||\n tag === \"div\" ||\n tag === \"section\" ||\n tag === \"article\" ||\n tag === \"aside\" ||\n tag === \"header\" ||\n tag === \"footer\" ||\n tag === \"main\" ||\n tag === \"blockquote\" ||\n tag === \"ul\" ||\n tag === \"ol\" ||\n tag === \"li\" ||\n tag === \"table\" ||\n tag === \"h1\" ||\n tag === \"h2\" ||\n tag === \"h3\" ||\n tag === \"h4\" ||\n tag === \"h5\" ||\n tag === \"h6\"\n ) return true;\n }\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Plain text → blocks\n// ---------------------------------------------------------------------------\n\nexport function parsePlainText(text: string): BlockSpec[] {\n const normalized = text.replace(/\\r\\n?/g, \"\\n\");\n const paragraphs = normalized.split(/\\n+/);\n return paragraphs.map((para) => ({\n id: newBlockId(),\n type: \"p\",\n runs: para.length ? [{ text: para }] : [],\n }));\n}\n",
|
|
18
|
+
"import type { Store } from \"creo\";\nimport type { DocState, Selection } from \"../model/types\";\n\n// ---------------------------------------------------------------------------\n// Coarse-pointer detection — true on phones / tablets, false on desktop.\n// Runtime-checked once and cached.\n// ---------------------------------------------------------------------------\n\nlet __coarsePointer: boolean | null = null;\nexport function isCoarsePointer(): boolean {\n if (__coarsePointer != null) return __coarsePointer;\n if (typeof window === \"undefined\" || !window.matchMedia) {\n __coarsePointer = false;\n return false;\n }\n __coarsePointer = window.matchMedia(\"(pointer: coarse)\").matches;\n return __coarsePointer;\n}\n\n/** Test-only override (clears the cache so the next read re-detects). */\nexport function __resetCoarsePointerCache(): void {\n __coarsePointer = null;\n}\n\n// ---------------------------------------------------------------------------\n// Visual viewport tracking\n//\n// When the soft keyboard opens, iOS shrinks the *visual* viewport without\n// changing the *layout* viewport. We listen to `visualViewport.resize` and\n// keep the editor's caret block in the upper third of whatever space is\n// still visible. Also exposes `--creo-vv-height` / `--creo-vv-top` CSS\n// custom properties so host pages can react (e.g. position floating UI\n// above the keyboard).\n// ---------------------------------------------------------------------------\n\nexport type ViewportStores = {\n selStore: Store<Selection>;\n docStore: Store<DocState>;\n};\n\nexport type ViewportHandle = { destroy: () => void };\n\nexport function attachVisualViewport(\n root: HTMLElement,\n stores: ViewportStores,\n): ViewportHandle {\n if (typeof window === \"undefined\") return { destroy: () => {} };\n const vv = (window as Window & {\n visualViewport?: VisualViewport;\n }).visualViewport;\n if (!vv) return { destroy: () => {} };\n\n const apply = () => {\n root.style.setProperty(\"--creo-vv-height\", `${vv.height}px`);\n root.style.setProperty(\"--creo-vv-top\", `${vv.offsetTop}px`);\n scrollCaretIntoUpperThird(root, stores);\n };\n\n apply();\n vv.addEventListener(\"resize\", apply);\n vv.addEventListener(\"scroll\", apply);\n\n return {\n destroy() {\n vv.removeEventListener(\"resize\", apply);\n vv.removeEventListener(\"scroll\", apply);\n },\n };\n}\n\nfunction scrollCaretIntoUpperThird(\n root: HTMLElement,\n stores: ViewportStores,\n): void {\n const sel = stores.selStore.get();\n const at = sel.kind === \"caret\" ? sel.at : sel.focus;\n const blockEl = root.querySelector(\n `[data-block-id=\"${at.blockId.replace(/\"/g, '\\\\\"')}\"]`,\n ) as HTMLElement | null;\n if (!blockEl) return;\n const rect = blockEl.getBoundingClientRect();\n const vv = (window as Window & { visualViewport?: VisualViewport })\n .visualViewport;\n if (!vv) return;\n const vvTop = vv.offsetTop;\n const vvBottom = vvTop + vv.height;\n if (rect.top >= vvTop && rect.bottom <= vvBottom) return;\n const desiredTop = vvTop + vv.height / 3;\n const dy = rect.top - desiredTop;\n const scrollEl = findScrollableAncestor(root);\n if (scrollEl === window) {\n window.scrollTo({ top: window.scrollY + dy, behavior: \"smooth\" });\n } else {\n (scrollEl as HTMLElement).scrollTop += dy;\n }\n}\n\nfunction findScrollableAncestor(el: HTMLElement): HTMLElement | Window {\n let cur: HTMLElement | null = el;\n while (cur) {\n const style = window.getComputedStyle(cur);\n if (\n /(auto|scroll|overlay)/.test(\n style.overflowY + style.overflowX + style.overflow,\n )\n ) {\n return cur;\n }\n cur = cur.parentElement;\n }\n return window;\n}\n",
|
|
19
|
+
"import type { Store } from \"creo\";\nimport { isTextBearing, type TextBearingBlock } from \"../model/blockText\";\nimport { findPos, getBlock, updateBlock } from \"../model/doc\";\nimport { isCaret, orderedRange } from \"../controller/selection\";\nimport type {\n Block,\n DocState,\n ListItemBlock,\n Selection,\n} from \"../model/types\";\n\nexport type Stores = {\n docStore: Store<DocState>;\n selStore: Store<Selection>;\n};\n\n/**\n * Toggle whether the touched blocks are list items of the given `ordered`\n * kind.\n * - If every touched text block is already a list item with that ordering,\n * convert them back to paragraphs (and reset depth to 0).\n * - Otherwise convert them to `li ordered=...` (preserving depth where\n * possible, defaulting to 0).\n */\nexport function toggleList(\n { docStore, selStore }: Stores,\n ordered: boolean,\n): boolean {\n const sel = selStore.get();\n const doc = docStore.get();\n const touchedIds = collectTouchedBlockIds(doc, sel);\n if (touchedIds.length === 0) return false;\n\n let allListed = true;\n for (const id of touchedIds) {\n const b = getBlock(doc, id)!;\n if (b.type !== \"li\" || (b as ListItemBlock).ordered !== ordered) {\n allListed = false;\n break;\n }\n }\n\n let working = doc;\n for (const id of touchedIds) {\n const b = getBlock(working, id);\n if (!b || !isTextBearing(b)) continue;\n if (allListed) {\n // Demote to paragraph.\n working = updateBlock(working, {\n id: b.id,\n index: b.index,\n type: \"p\",\n runs: (b as TextBearingBlock).runs,\n } as Block);\n } else {\n const li: ListItemBlock = {\n id: b.id,\n index: b.index,\n type: \"li\",\n ordered,\n depth:\n b.type === \"li\" ? (b as ListItemBlock).depth : 0,\n runs: (b as TextBearingBlock).runs,\n };\n working = updateBlock(working, li);\n }\n }\n docStore.set(working);\n return true;\n}\n\n/** Tab — increase list depth (max 3). No-op for non-list blocks. */\nexport function indentList({ docStore, selStore }: Stores): boolean {\n const ids = collectTouchedBlockIds(docStore.get(), selStore.get());\n let working = docStore.get();\n let changed = false;\n for (const id of ids) {\n const b = getBlock(working, id);\n if (!b || b.type !== \"li\") continue;\n const li = b as ListItemBlock;\n if (li.depth >= 3) continue;\n working = updateBlock(working, {\n ...li,\n depth: (li.depth + 1) as 0 | 1 | 2 | 3,\n });\n changed = true;\n }\n if (changed) docStore.set(working);\n return changed;\n}\n\n/** Shift+Tab — decrease list depth. At depth 0, convert back to paragraph. */\nexport function outdentList({ docStore, selStore }: Stores): boolean {\n const ids = collectTouchedBlockIds(docStore.get(), selStore.get());\n let working = docStore.get();\n let changed = false;\n for (const id of ids) {\n const b = getBlock(working, id);\n if (!b || b.type !== \"li\") continue;\n const li = b as ListItemBlock;\n if (li.depth > 0) {\n working = updateBlock(working, {\n ...li,\n depth: (li.depth - 1) as 0 | 1 | 2 | 3,\n });\n changed = true;\n } else {\n working = updateBlock(working, {\n id: li.id,\n index: li.index,\n type: \"p\",\n runs: li.runs,\n } as Block);\n changed = true;\n }\n }\n if (changed) docStore.set(working);\n return changed;\n}\n\nfunction collectTouchedBlockIds(\n doc: DocState,\n sel: Selection,\n): string[] {\n if (isCaret(sel)) {\n return doc.byId.has(sel.at.blockId) ? [sel.at.blockId] : [];\n }\n const { start, end } = orderedRange(doc, sel);\n const startI = findPos(doc, start.blockId);\n const endI = findPos(doc, end.blockId);\n if (startI < 0 || endI < 0) return [];\n const out: string[] = [];\n for (let i = startI; i <= endI; i++) out.push(doc.order[i]!);\n return out;\n}\n",
|
|
20
|
+
"import type { Store } from \"creo\";\nimport {\n isTextBearing,\n normalizeRuns,\n splitRunsAt,\n type TextBearingBlock,\n} from \"../model/blockText\";\nimport { findPos, getBlock, updateBlock } from \"../model/doc\";\nimport {\n anchorOffset,\n isCaret,\n orderedRange,\n} from \"../controller/selection\";\nimport type {\n Block,\n DocState,\n InlineRun,\n Mark,\n Selection,\n} from \"../model/types\";\n\nexport type Stores = {\n docStore: Store<DocState>;\n selStore: Store<Selection>;\n};\n\n/**\n * Toggle a mark over the current selection.\n *\n * Behaviour:\n * - Caret-only: no-op (real editors track a \"pending mark\" that biases the\n * next character; we don't ship that in M6 to keep the API minimal).\n * - Single-block range: if every character in [start, end) already has the\n * mark, REMOVE it; otherwise ADD it everywhere in the range.\n * - Cross-block range: same rule applied per-block to the slice that\n * intersects the range.\n *\n * Run merging happens via `normalizeRuns`, so toggling repeatedly never\n * fragments runs unbounded.\n */\nexport function toggleMark({ docStore, selStore }: Stores, mark: Mark): boolean {\n const sel = selStore.get();\n if (isCaret(sel)) return false;\n const doc = docStore.get();\n const { start, end } = orderedRange(doc, sel);\n\n const startI = findPos(doc, start.blockId);\n const endI = findPos(doc, end.blockId);\n if (startI < 0 || endI < 0) return false;\n\n // First pass: figure out whether the entire selection already has the mark\n // (so we know whether to add or remove). We must inspect every char in the\n // covered slices.\n let allHave = true;\n let touchedAny = false;\n for (let i = startI; i <= endI; i++) {\n const id = doc.order[i]!;\n const block = getBlock(doc, id);\n if (!block || !isTextBearing(block)) continue;\n const sOff = i === startI ? anchorOffset(start) : 0;\n const eOff =\n i === endI ? anchorOffset(end) : runsLength((block as TextBearingBlock).runs);\n if (sOff === eOff) continue;\n touchedAny = true;\n const runs = (block as TextBearingBlock).runs;\n if (!sliceAllHasMark(runs, sOff, eOff, mark)) {\n allHave = false;\n break;\n }\n }\n if (!touchedAny) return false;\n\n const add = !allHave;\n\n // Second pass: write the change.\n let working = doc;\n for (let i = startI; i <= endI; i++) {\n const id = doc.order[i]!;\n const block = getBlock(working, id);\n if (!block || !isTextBearing(block)) continue;\n const blockLen = runsLength((block as TextBearingBlock).runs);\n const sOff = i === startI ? anchorOffset(start) : 0;\n const eOff = i === endI ? anchorOffset(end) : blockLen;\n if (sOff === eOff) continue;\n const runs = (block as TextBearingBlock).runs;\n const newRuns = applyMarkToSlice(runs, sOff, eOff, mark, add);\n working = updateBlock(working, {\n ...(block as TextBearingBlock),\n runs: newRuns,\n } as Block);\n }\n docStore.set(working);\n return true;\n}\n\nfunction runsLength(runs: InlineRun[]): number {\n let n = 0;\n for (const r of runs) n += r.text.length;\n return n;\n}\n\nfunction sliceAllHasMark(\n runs: InlineRun[],\n start: number,\n end: number,\n mark: Mark,\n): boolean {\n let prefix = 0;\n for (const r of runs) {\n const rs = prefix;\n const re = prefix + r.text.length;\n prefix = re;\n if (re <= start || rs >= end) continue;\n if (!r.marks || !r.marks.has(mark)) return false;\n }\n return true;\n}\n\nfunction applyMarkToSlice(\n runs: InlineRun[],\n start: number,\n end: number,\n mark: Mark,\n add: boolean,\n): InlineRun[] {\n const [left, midRight] = splitRunsAt(runs, start);\n const [middle, right] = splitRunsAt(midRight, end - start);\n const newMiddle = middle.map((r) => withMark(r, mark, add));\n return normalizeRuns([...left, ...newMiddle, ...right]);\n}\n\nfunction withMark(run: InlineRun, mark: Mark, add: boolean): InlineRun {\n const cur = run.marks ?? new Set<Mark>();\n const next = new Set<Mark>(cur);\n if (add) next.add(mark);\n else next.delete(mark);\n if (next.size === 0) return { text: run.text };\n return { text: run.text, marks: next };\n}\n",
|
|
21
|
+
"// ---------------------------------------------------------------------------\n// runsAt registry — pluggable lookup for the \"runs slot at this anchor\"\n// abstraction that every text command goes through.\n//\n// Hot path: called on every keystroke, so we avoid an if/else chain by going\n// through a Map<type, fn>. The default fallback handles text-bearing blocks\n// (anything with a `runs: InlineRun[]` field at the top level), so plugins\n// only need to register `runsAt` for blocks with nested cells.\n//\n// This module is the single seam that `model/cellAccess.ts` re-exports from\n// — keeping the public `runsAt(block, anchor)` callable signature unchanged\n// for every text command in the codebase.\n// ---------------------------------------------------------------------------\n\nimport type { Anchor, Block, InlineRun } from \"../model/types\";\nimport type { RunsCtx } from \"./types\";\n\ntype RunsAtFn = (b: Block, a: Anchor) => RunsCtx | null;\n\nconst fnByType = new Map<string, RunsAtFn>();\n\nexport function registerRunsAt(type: string, fn: RunsAtFn): void {\n fnByType.set(type, fn);\n}\n\n/** Default for any block exposing a top-level `runs` array. */\nfunction defaultTextBearing(b: Block, _a: Anchor): RunsCtx | null {\n if (\"runs\" in b && Array.isArray((b as { runs?: InlineRun[] }).runs)) {\n const tb = b as Block & { runs: InlineRun[] };\n return {\n runs: tb.runs,\n setRuns: (newRuns) => ({ ...tb, runs: newRuns } as Block),\n };\n }\n return null;\n}\n\nexport function runsAt(block: Block, anchor: Anchor): RunsCtx | null {\n const fn = fnByType.get(block.type);\n if (fn) return fn(block, anchor);\n return defaultTextBearing(block, anchor);\n}\n\n/** Total length of the runs container at `anchor` — convenience helper used\n * by both text commands and the IME composition diff. */\nexport function runsLengthAt(block: Block, anchor: Anchor): number {\n const ctx = runsAt(block, anchor);\n if (!ctx) return 0;\n let n = 0;\n for (const r of ctx.runs) n += r.text.length;\n return n;\n}\n",
|
|
22
|
+
"import type { Store } from \"creo\";\nimport {\n blockTextLength,\n concatRuns,\n deleteRange,\n insertText as insertTextRuns,\n isTextBearing,\n splitRunsAt,\n type TextBearingBlock,\n} from \"../model/blockText\";\nimport { runsAt } from \"../model/cellAccess\";\nimport {\n findPos,\n getBlock,\n insertAfter,\n insertAt,\n newBlockId,\n removeBlock,\n removeBlocks,\n updateBlock,\n} from \"../model/doc\";\nimport { isAtomicBlockType } from \"../plugin/atomic\";\nimport {\n anchorOffset,\n caret,\n caretAt,\n isCaret,\n orderedRange,\n withCharOffset,\n} from \"../controller/selection\";\nimport type {\n Block,\n BlockSpec,\n BlockType,\n CodeBlock,\n DocState,\n HeadingBlock,\n ListItemBlock,\n ParagraphBlock,\n Selection,\n} from \"../model/types\";\n\nexport type Stores = {\n docStore: Store<DocState>;\n selStore: Store<Selection>;\n};\n\n// ---------------------------------------------------------------------------\n// Split\n// ---------------------------------------------------------------------------\n\n/**\n * Split the current block at the caret. The right half becomes a NEW block\n * placed immediately after the current one. Headings split into a paragraph\n * (the convention every consumer-grade editor uses — pressing Enter at the\n * end of a heading shouldn't create another heading by default). List items\n * split into another list item of the same kind & depth.\n */\nexport function splitBlock({ docStore, selStore }: Stores): boolean {\n const sel = selStore.get();\n if (!isCaret(sel)) {\n // Range split: collapse the range first by deleting it, then split.\n const collapsed = collapseRangeForStructuralOp(docStore, selStore);\n if (collapsed === false) return false;\n }\n const doc = docStore.get();\n const cur = selStore.get();\n if (!isCaret(cur)) return false;\n\n const block = getBlock(doc, cur.at.blockId);\n if (!block) return false;\n const off = anchorOffset(cur.at);\n\n // Columns cells behave like code blocks for Enter — the column is a single\n // multi-line region holding inline runs, so Enter inserts a newline into\n // the targeted column's runs rather than splitting the columns block.\n if (block.type === \"columns\") {\n const ctx = runsAt(block, cur.at);\n if (!ctx) return false;\n const newRuns = insertTextRuns(ctx.runs, off, \"\\n\");\n docStore.set(updateBlock(doc, ctx.setRuns(newRuns)));\n selStore.set(caret(withCharOffset(cur.at, off + 1)));\n return true;\n }\n\n if (!isTextBearing(block)) return false;\n\n // Code blocks are single multi-line regions — Enter inserts a newline\n // character instead of splitting into two blocks. The block keeps any\n // existing runs and their marks; the new \\n inherits surrounding marks\n // via insertTextRuns()'s normal logic.\n if (block.type === \"code\") {\n const newRuns = insertTextRuns(block.runs, off, \"\\n\");\n docStore.set(\n updateBlock(doc, { ...(block as CodeBlock), runs: newRuns } as Block),\n );\n selStore.set(caret(withCharOffset(cur.at, off + 1)));\n return true;\n }\n\n const [left, right] = splitRunsAt(block.runs, off);\n\n // Same-id keeps the first half (cheap reuse). New id for the right half.\n const newId = newBlockId();\n const updatedLeft = {\n ...(block as TextBearingBlock),\n runs: left,\n } as Block;\n\n let nextBlock: BlockSpec;\n switch (block.type) {\n case \"li\": {\n const li = block as ListItemBlock;\n nextBlock = {\n id: newId,\n type: \"li\",\n ordered: li.ordered,\n depth: li.depth,\n runs: right,\n };\n break;\n }\n case \"h1\":\n case \"h2\":\n case \"h3\":\n case \"h4\":\n case \"h5\":\n case \"h6\":\n // Heading → paragraph after split.\n nextBlock = { id: newId, type: \"p\", runs: right };\n break;\n case \"p\":\n default:\n nextBlock = { id: newId, type: \"p\", runs: right };\n break;\n }\n\n const d1 = updateBlock(doc, updatedLeft);\n const d2 = insertAfter(d1, block.id, nextBlock);\n docStore.set(d2);\n selStore.set(caret(caretAt(newId, 0)));\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// Merge backward (Backspace at offset 0)\n// ---------------------------------------------------------------------------\n\nexport function mergeBackward({ docStore, selStore }: Stores): boolean {\n const sel = selStore.get();\n if (!isCaret(sel)) {\n return collapseRangeForStructuralOp(docStore, selStore) ?? false;\n }\n const doc = docStore.get();\n const at = sel.at;\n if (anchorOffset(at) !== 0) return false;\n const i = findPos(doc, at.blockId);\n if (i <= 0) return false;\n const prevId = doc.order[i - 1]!;\n const prev = getBlock(doc, prevId)!;\n const cur = getBlock(doc, at.blockId)!;\n\n if (!isTextBearing(prev) || !isTextBearing(cur)) {\n // Image / table on either side — collapse caret to end of prev block\n // instead of deleting (deferred to image/table handling).\n return false;\n }\n\n const prevLen = blockTextLength(prev as TextBearingBlock);\n const merged: TextBearingBlock = {\n ...(prev as TextBearingBlock),\n runs: concatRuns(\n (prev as TextBearingBlock).runs,\n (cur as TextBearingBlock).runs,\n ),\n };\n const d1 = updateBlock(doc, merged as Block);\n const d2 = removeBlock(d1, at.blockId);\n docStore.set(d2);\n selStore.set(caret(caretAt(prevId, prevLen)));\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// Merge forward (Delete at end of block)\n// ---------------------------------------------------------------------------\n\nexport function mergeForward({ docStore, selStore }: Stores): boolean {\n const sel = selStore.get();\n if (!isCaret(sel)) {\n return collapseRangeForStructuralOp(docStore, selStore) ?? false;\n }\n const doc = docStore.get();\n const at = sel.at;\n const block = getBlock(doc, at.blockId);\n if (!block || !isTextBearing(block)) return false;\n const off = anchorOffset(at);\n const len = blockTextLength(block as TextBearingBlock);\n if (off !== len) return false;\n const i = findPos(doc, at.blockId);\n const nextId = doc.order[i + 1];\n if (nextId == null) return false;\n const next = getBlock(doc, nextId)!;\n if (!isTextBearing(next)) return false;\n const merged: TextBearingBlock = {\n ...(block as TextBearingBlock),\n runs: concatRuns(\n (block as TextBearingBlock).runs,\n (next as TextBearingBlock).runs,\n ),\n };\n const d1 = updateBlock(doc, merged as Block);\n const d2 = removeBlock(d1, nextId);\n docStore.set(d2);\n // Caret stays at the merge boundary.\n selStore.set(caret(withCharOffset(at, len)));\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// setBlockType — change the type of the current block (or the block holding\n// the start of a range). Preserves runs.\n// ---------------------------------------------------------------------------\n\nexport type SetBlockTypePayload = {\n type: BlockType;\n ordered?: boolean;\n depth?: 0 | 1 | 2 | 3;\n};\n\nexport function setBlockType(\n { docStore, selStore }: Stores,\n payload: SetBlockTypePayload,\n): boolean {\n const doc = docStore.get();\n const sel = selStore.get();\n const startId = isCaret(sel) ? sel.at.blockId : sel.anchor.blockId;\n const block = getBlock(doc, startId);\n if (!block) return false;\n if (!isTextBearing(block)) return false;\n const runs = (block as TextBearingBlock).runs;\n let next: Block;\n switch (payload.type) {\n case \"p\":\n next = {\n id: block.id,\n index: block.index,\n type: \"p\",\n runs,\n } satisfies ParagraphBlock;\n break;\n case \"h1\":\n case \"h2\":\n case \"h3\":\n case \"h4\":\n case \"h5\":\n case \"h6\":\n next = {\n id: block.id,\n index: block.index,\n type: payload.type,\n runs,\n } satisfies HeadingBlock;\n break;\n case \"li\":\n next = {\n id: block.id,\n index: block.index,\n type: \"li\",\n ordered: payload.ordered ?? false,\n depth: payload.depth ?? 0,\n runs,\n } satisfies ListItemBlock;\n break;\n case \"code\":\n next = {\n id: block.id,\n index: block.index,\n type: \"code\",\n runs,\n } satisfies CodeBlock;\n break;\n default:\n // img / table / columns can't be reached from text — payload misuse, skip.\n return false;\n }\n docStore.set(updateBlock(doc, next));\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// Range collapse helper — used by structural ops when the user has a range\n// selected. Deletes the range across (potentially) multiple blocks first,\n// leaving a caret at the start of the range, then returns true.\n// Returns false (no-op) if the range can't be collapsed (e.g. spans an\n// image block — handled in M9).\n// ---------------------------------------------------------------------------\n\nfunction collapseRangeForStructuralOp(\n docStore: Store<DocState>,\n selStore: Store<Selection>,\n): boolean | null {\n const doc = docStore.get();\n const sel = selStore.get();\n if (sel.kind === \"caret\") return true;\n const { start, end } = orderedRange(doc, sel);\n if (start.blockId === end.blockId) {\n const block = getBlock(doc, start.blockId);\n if (!block || !isTextBearing(block)) return false;\n const sOff = anchorOffset(start);\n const eOff = anchorOffset(end);\n if (sOff === eOff) {\n selStore.set(caret(start));\n return true;\n }\n const newRuns = deleteRange((block as TextBearingBlock).runs, sOff, eOff);\n docStore.set(\n updateBlock(doc, {\n ...(block as TextBearingBlock),\n runs: newRuns,\n } as Block),\n );\n selStore.set(caret(caretAt(block.id, sOff)));\n return true;\n }\n // Multi-block range delete: keep the part of the start-block before sOff\n // and the part of the end-block after eOff, then merge them, and remove\n // every block in between.\n //\n // Atomic blocks (e.g. calendar / date-marker) appear at either endpoint\n // when the user runs Select-All across a doc whose first or last block is\n // non-editable. They contribute no runs to merge — the whole atomic block\n // is consumed by the deletion. Cmd+A → Backspace must still wipe the doc\n // and leave a fresh paragraph for the caret.\n const startBlock = getBlock(doc, start.blockId);\n const endBlock = getBlock(doc, end.blockId);\n if (!startBlock || !endBlock) return false;\n const startTB = isTextBearing(startBlock);\n const endTB = isTextBearing(endBlock);\n const startAtomic = isAtomicBlockType(startBlock.type);\n const endAtomic = isAtomicBlockType(endBlock.type);\n if ((!startTB && !startAtomic) || (!endTB && !endAtomic)) {\n // Tables / columns as a range endpoint aren't supported here.\n return false;\n }\n const sOff = anchorOffset(start);\n const eOff = anchorOffset(end);\n const startI = findPos(doc, start.blockId);\n const endI = findPos(doc, end.blockId);\n const leftRuns = startTB\n ? splitRunsAt((startBlock as TextBearingBlock).runs, sOff)[0]\n : [];\n const rightRuns = endTB\n ? splitRunsAt((endBlock as TextBearingBlock).runs, eOff)[1]\n : [];\n const merged = concatRuns(leftRuns, rightRuns);\n\n let working = doc;\n let resultId: string;\n let resultOff: number;\n if (startTB) {\n working = updateBlock(working, {\n ...(startBlock as TextBearingBlock),\n runs: merged,\n } as Block);\n const idsToRemove: string[] = [];\n for (let i = startI + 1; i <= endI; i++) idsToRemove.push(doc.order[i]!);\n if (idsToRemove.length > 0) working = removeBlocks(working, idsToRemove);\n resultId = start.blockId;\n resultOff = sOff;\n } else if (endTB) {\n working = updateBlock(working, {\n ...(endBlock as TextBearingBlock),\n runs: merged,\n } as Block);\n const idsToRemove: string[] = [];\n for (let i = startI; i < endI; i++) idsToRemove.push(doc.order[i]!);\n if (idsToRemove.length > 0) working = removeBlocks(working, idsToRemove);\n resultId = end.blockId;\n resultOff = 0;\n } else {\n const idsToRemove: string[] = [];\n for (let i = startI; i <= endI; i++) idsToRemove.push(doc.order[i]!);\n working = removeBlocks(working, idsToRemove);\n if (working.order.length === 0) {\n const freshId = newBlockId();\n working = insertAt(working, 0, {\n id: freshId,\n type: \"p\",\n runs: [],\n } as BlockSpec);\n resultId = freshId;\n } else {\n const newIdx = Math.min(startI, working.order.length - 1);\n resultId = working.order[newIdx]!;\n }\n resultOff = 0;\n }\n docStore.set(working);\n selStore.set(caret(caretAt(resultId, resultOff)));\n return true;\n}\n",
|
|
23
|
+
"import { getBlock, updateBlock } from \"../model/doc\";\nimport {\n deleteRange,\n insertText as insertTextRuns,\n} from \"../model/blockText\";\nimport { mergeBackward } from \"./structuralCommands\";\nimport { runsAt, runsLengthAt } from \"../model/cellAccess\";\nimport {\n anchorOffset,\n caret,\n caretAt,\n clampAnchor,\n isCaret,\n orderedRange,\n withCharOffset,\n} from \"../controller/selection\";\nimport type { DocState, Selection } from \"../model/types\";\nimport type { Store } from \"creo\";\n\n// ---------------------------------------------------------------------------\n// Public command runners — each takes the docStore + selStore and mutates\n// them. Returns true if anything changed (so callers can decide whether to\n// schedule autosave / push undo).\n// ---------------------------------------------------------------------------\n\nexport type Stores = {\n docStore: Store<DocState>;\n selStore: Store<Selection>;\n};\n\n/**\n * Insert plain text at the current selection. If the selection is a range,\n * the range is deleted first and the text is inserted at the start.\n *\n * Cross-block ranges are deferred to mergeBackward (M5) — this only handles\n * the single-cell / single-block case.\n */\nexport function insertText({ docStore, selStore }: Stores, text: string): boolean {\n if (text.length === 0) return false;\n const doc = docStore.get();\n const sel = selStore.get();\n\n if (sel.kind === \"range\") {\n const { start, end } = orderedRange(doc, sel);\n if (\n start.blockId === end.blockId &&\n samePathPrefix(start, end)\n ) {\n const block = getBlock(doc, start.blockId);\n if (!block) return false;\n const ctx = runsAt(block, start);\n if (!ctx) return false;\n const sOff = anchorOffset(start);\n const eOff = anchorOffset(end);\n const newRuns = insertTextRuns(\n deleteRange(ctx.runs, sOff, eOff),\n sOff,\n text,\n );\n docStore.set(updateBlock(doc, ctx.setRuns(newRuns)));\n selStore.set(caret(withCharOffset(start, sOff + text.length)));\n return true;\n }\n // Cross-block / cross-cell range: collapse first, then re-enter so\n // the caret-path below inserts at the resulting collapsed anchor.\n // mergeBackward() with a range routes through the structural-merge\n // collapse helper (which handles multi-block ranges + tables/columns)\n // and leaves a caret selection at the start of the deleted range.\n const collapsed = mergeBackward({ docStore, selStore });\n if (!collapsed) return false;\n return insertText({ docStore, selStore }, text);\n }\n\n const at = clampAnchor(doc, sel.at);\n const block = getBlock(doc, at.blockId);\n if (!block) return false;\n const ctx = runsAt(block, at);\n if (!ctx) return false;\n const off = anchorOffset(at);\n const newRuns = insertTextRuns(ctx.runs, off, text);\n docStore.set(updateBlock(doc, ctx.setRuns(newRuns)));\n selStore.set(caret(withCharOffset(at, off + text.length)));\n return true;\n}\n\n/** Delete one character backward, or collapse a range. */\nexport function deleteBackward({ docStore, selStore }: Stores): boolean {\n const doc = docStore.get();\n const sel = selStore.get();\n\n if (sel.kind === \"range\") {\n return deleteSelectionRange({ docStore, selStore }, doc, sel);\n }\n\n const at = clampAnchor(doc, sel.at);\n const block = getBlock(doc, at.blockId);\n if (!block) return false;\n const ctx = runsAt(block, at);\n if (!ctx) return false;\n const off = anchorOffset(at);\n if (off === 0) return false;\n const newRuns = deleteRange(ctx.runs, off - 1, off);\n docStore.set(updateBlock(doc, ctx.setRuns(newRuns)));\n selStore.set(caret(withCharOffset(at, off - 1)));\n return true;\n}\n\n/** Delete one character forward, or collapse a range. */\nexport function deleteForward({ docStore, selStore }: Stores): boolean {\n const doc = docStore.get();\n const sel = selStore.get();\n\n if (sel.kind === \"range\") {\n return deleteSelectionRange({ docStore, selStore }, doc, sel);\n }\n\n const at = clampAnchor(doc, sel.at);\n const block = getBlock(doc, at.blockId);\n if (!block) return false;\n const ctx = runsAt(block, at);\n if (!ctx) return false;\n const off = anchorOffset(at);\n const len = runsLengthAt(block, at);\n if (off >= len) return false;\n const newRuns = deleteRange(ctx.runs, off, off + 1);\n docStore.set(updateBlock(doc, ctx.setRuns(newRuns)));\n return true;\n}\n\nfunction deleteSelectionRange(\n stores: Stores,\n doc: DocState,\n sel: Selection,\n): boolean {\n if (isCaret(sel)) return false;\n const { start, end } = orderedRange(doc, sel);\n if (start.blockId !== end.blockId || !samePathPrefix(start, end)) {\n // Cross-block / cross-cell — block-merge owns this in M5.\n return false;\n }\n const block = getBlock(doc, start.blockId);\n if (!block) return false;\n const ctx = runsAt(block, start);\n if (!ctx) return false;\n const sOff = anchorOffset(start);\n const eOff = anchorOffset(end);\n if (sOff === eOff) return false;\n const newRuns = deleteRange(ctx.runs, sOff, eOff);\n stores.docStore.set(updateBlock(doc, ctx.setRuns(newRuns)));\n // Place caret at start; preserve table path prefix.\n if (start.path.length >= 3) {\n stores.selStore.set(caret(withCharOffset(start, sOff)));\n } else {\n stores.selStore.set(caret(caretAt(block.id, sOff)));\n }\n return true;\n}\n\n/**\n * For range selections, both anchors must point into the SAME runs\n * container (same row/col for tables, both top-level for text blocks).\n */\nfunction samePathPrefix(a: { path: number[] }, b: { path: number[] }): boolean {\n if (a.path.length !== b.path.length) {\n // text-bearing path is [offset]; table path is [row,col,offset]. Must match.\n return false;\n }\n if (a.path.length >= 3) {\n return a.path[0] === b.path[0] && a.path[1] === b.path[1];\n }\n return true;\n}\n",
|
|
24
|
+
"import type { Store } from \"creo\";\nimport type { DocState, Selection } from \"../model/types\";\n\n/**\n * Snapshot-based undo/redo. We don't synthesize inverse commands — we just\n * stash the previous (doc, sel) before each mutation and let undo restore\n * it.\n *\n * Coalescing rule: consecutive `insertText` / `deleteBackward` ops within\n * 500ms collapse into a single undo entry. This matches Notion / Google\n * Docs UX — typing a sentence then hitting Cmd+Z removes the whole sentence,\n * not the last character.\n */\n\nexport type HistoryEntry = {\n doc: DocState;\n sel: Selection;\n // Tag of the action that produced this entry — used to decide if the\n // *next* action coalesces with it.\n tag: string;\n ts: number;\n};\n\nexport type HistoryStores = {\n docStore: Store<DocState>;\n selStore: Store<Selection>;\n};\n\nexport const COALESCE_MS = 500;\nexport const HISTORY_CAP = 200;\n\nexport function createHistory(stores: HistoryStores) {\n const undoStack: HistoryEntry[] = [];\n const redoStack: HistoryEntry[] = [];\n let pinned = false;\n\n /**\n * Record the CURRENT state with the given action tag. Call BEFORE\n * mutating. If the tag matches the previous entry and the time gap is\n * small, the previous entry is reused (no new undo step).\n */\n const record = (tag: string): void => {\n if (pinned) return;\n redoStack.length = 0; // any new edit invalidates the redo trail\n const top = undoStack[undoStack.length - 1];\n const now = Date.now();\n const coalesce =\n top != null &&\n top.tag === tag &&\n tag.startsWith(\"text:\") &&\n now - top.ts < COALESCE_MS;\n if (coalesce) {\n // Don't push another entry — the existing one's snapshot pre-dates\n // the keystroke chain.\n top.ts = now;\n return;\n }\n undoStack.push({\n doc: stores.docStore.get(),\n sel: stores.selStore.get(),\n tag,\n ts: now,\n });\n if (undoStack.length > HISTORY_CAP) undoStack.shift();\n };\n\n const undo = (): boolean => {\n const entry = undoStack.pop();\n if (!entry) return false;\n pinned = true;\n redoStack.push({\n doc: stores.docStore.get(),\n sel: stores.selStore.get(),\n tag: entry.tag,\n ts: Date.now(),\n });\n stores.docStore.set(entry.doc);\n stores.selStore.set(entry.sel);\n pinned = false;\n return true;\n };\n\n const redo = (): boolean => {\n const entry = redoStack.pop();\n if (!entry) return false;\n pinned = true;\n undoStack.push({\n doc: stores.docStore.get(),\n sel: stores.selStore.get(),\n tag: entry.tag,\n ts: Date.now(),\n });\n stores.docStore.set(entry.doc);\n stores.selStore.set(entry.sel);\n pinned = false;\n return true;\n };\n\n /** Reset everything — used after a wholesale doc replacement. */\n const reset = (): void => {\n undoStack.length = 0;\n redoStack.length = 0;\n };\n\n return { record, undo, redo, reset };\n}\n\nexport type History = ReturnType<typeof createHistory>;\n",
|
|
25
|
+
"import type { Store } from \"creo\";\nimport { maybeRebalance } from \"./doc\";\nimport type { DocState } from \"./types\";\n\n/**\n * Watch a docStore and schedule a microtask rebalance whenever any\n * fractional index grows past the soft threshold.\n *\n * Rebalance assigns fresh, evenly-spaced indices to every block (preserving\n * order). It's O(n) and runs at most once per microtask, so worst-case a\n * 600k-block doc rebalances in ~50ms — and only ever triggers under\n * adversarial insertion patterns.\n */\nexport function attachAutoRebalance(\n docStore: Store<DocState>,\n): () => void {\n let scheduled = false;\n const schedule = () => {\n if (scheduled) return;\n scheduled = true;\n queueMicrotask(() => {\n scheduled = false;\n const cur = docStore.get();\n const next = maybeRebalance(cur);\n if (next !== cur) docStore.set(next);\n });\n };\n return docStore.subscribe(schedule);\n}\n",
|
|
26
|
+
"import type { Mark } from \"../model/types\";\nimport type { SetBlockTypePayload } from \"../commands/structuralCommands\";\n\n/**\n * Cross-platform \"mod\" key — ⌘ on macOS, Ctrl elsewhere.\n *\n * The detection is conservative: we look at navigator.platform first; in\n * test / SSR environments (no navigator) we default to non-mac.\n */\nexport function isMac(): boolean {\n if (typeof navigator === \"undefined\") return false;\n const p = (navigator as { platform?: string; userAgent?: string });\n if (p.platform) return /Mac|iPhone|iPod|iPad/i.test(p.platform);\n if (p.userAgent) return /Mac|iPhone|iPod|iPad/i.test(p.userAgent);\n return false;\n}\n\nexport type KeymapHit =\n | { kind: \"toggleMark\"; mark: Mark }\n | { kind: \"setBlockType\"; payload: SetBlockTypePayload }\n | { kind: \"indent\" }\n | { kind: \"outdent\" }\n | { kind: \"undo\" }\n | { kind: \"redo\" }\n | { kind: \"selectAll\" }\n // Word + line + doc navigation chords. extend = shift held.\n | { kind: \"moveWord\"; direction: -1 | 1; extend: boolean }\n | { kind: \"moveLineEdge\"; direction: -1 | 1; extend: boolean }\n | { kind: \"moveDocEdge\"; direction: -1 | 1; extend: boolean };\n\n/**\n * Match a keyboard event against the default chord table. Returns the hit if\n * the key is a known chord, else `null` so the caller can fall through to\n * navigation / text editing.\n *\n * The matcher is intentionally event-oriented rather than string-oriented;\n * it sidesteps the \"Ctrl+Shift+K\" parsing rabbit-hole.\n */\nexport function matchKeymap(e: KeyboardEvent): KeymapHit | null {\n const mod = isMac() ? e.metaKey : e.ctrlKey;\n const key = e.key;\n const lower = key.length === 1 ? key.toLowerCase() : key;\n\n if (mod && !e.altKey && !e.shiftKey) {\n switch (lower) {\n case \"b\":\n return { kind: \"toggleMark\", mark: \"b\" };\n case \"i\":\n return { kind: \"toggleMark\", mark: \"i\" };\n case \"u\":\n return { kind: \"toggleMark\", mark: \"u\" };\n case \"z\":\n return { kind: \"undo\" };\n case \"a\":\n return { kind: \"selectAll\" };\n }\n }\n if (mod && e.shiftKey && !e.altKey) {\n switch (lower) {\n case \"s\":\n return { kind: \"toggleMark\", mark: \"s\" };\n case \"z\":\n return { kind: \"redo\" };\n }\n }\n // Cmd+Alt+1..6 → headings (matches Notion / Google Docs).\n if (mod && e.altKey && !e.shiftKey) {\n if (key >= \"1\" && key <= \"6\") {\n const lvl = Number(key) as 1 | 2 | 3 | 4 | 5 | 6;\n return {\n kind: \"setBlockType\",\n payload: { type: (`h${lvl}` as `h${1 | 2 | 3 | 4 | 5 | 6}`) },\n };\n }\n if (lower === \"0\") {\n return { kind: \"setBlockType\", payload: { type: \"p\" } };\n }\n }\n // Tab / Shift-Tab — list indent / outdent. Pure key, no modifier.\n if (!mod && !e.altKey) {\n if (key === \"Tab\") {\n return e.shiftKey ? { kind: \"outdent\" } : { kind: \"indent\" };\n }\n }\n\n // -----------------------------------------------------------------------\n // Arrow / Home / End chord variants\n // -----------------------------------------------------------------------\n // macOS conventions:\n // Option+Left/Right → word\n // Cmd+Left/Right → line edge (Home/End)\n // Cmd+Up/Down → doc edge\n // Windows / Linux conventions:\n // Ctrl+Left/Right → word\n // Home/End → line edge (already handled in pipeline)\n // Ctrl+Home/End → doc edge (already handled in pipeline)\n // Ctrl+Up/Down → paragraph (we treat same as block-jump default)\n if (isMac()) {\n if (e.altKey && !e.metaKey && !e.ctrlKey) {\n if (key === \"ArrowLeft\") return { kind: \"moveWord\", direction: -1, extend: e.shiftKey };\n if (key === \"ArrowRight\") return { kind: \"moveWord\", direction: 1, extend: e.shiftKey };\n }\n if (e.metaKey && !e.altKey && !e.ctrlKey) {\n if (key === \"ArrowLeft\") return { kind: \"moveLineEdge\", direction: -1, extend: e.shiftKey };\n if (key === \"ArrowRight\") return { kind: \"moveLineEdge\", direction: 1, extend: e.shiftKey };\n if (key === \"ArrowUp\") return { kind: \"moveDocEdge\", direction: -1, extend: e.shiftKey };\n if (key === \"ArrowDown\") return { kind: \"moveDocEdge\", direction: 1, extend: e.shiftKey };\n }\n } else {\n if (e.ctrlKey && !e.altKey && !e.metaKey) {\n if (key === \"ArrowLeft\") return { kind: \"moveWord\", direction: -1, extend: e.shiftKey };\n if (key === \"ArrowRight\") return { kind: \"moveWord\", direction: 1, extend: e.shiftKey };\n // Ctrl+Up/Down: jump to paragraph above/below — handled by the\n // pipeline's plain ArrowUp/Down already (block-jump fallback). No\n // distinct chord needed here.\n }\n }\n\n return null;\n}\n",
|
|
27
|
+
"// ---------------------------------------------------------------------------\n// Anchor codec registry — DOM ↔ Anchor mapping per block kind.\n//\n// Text-bearing blocks (p/h*/li/code) share a default codec that walks visible\n// text by character offset; blocks with nested cells (table, columns, future\n// custom containers) register their own. The default also handles the\n// code-block special case (implicit \\n at every line break).\n//\n// This module is the single seam that `dom/anchorMap.ts` reads from. The\n// public `domToAnchor` / `anchorToDom` keep the same call signature; lookups\n// switch from a hardcoded if/else on `kind` to a Map.\n// ---------------------------------------------------------------------------\n\nimport type { Anchor } from \"../model/types\";\nimport type { AnchorCodec, DomPoint } from \"./types\";\n\nconst codecByType = new Map<string, AnchorCodec>();\n\nexport function registerAnchorCodec(type: string, codec: AnchorCodec): void {\n codecByType.set(type, codec);\n}\n\nexport function getAnchorCodec(type: string): AnchorCodec | null {\n return codecByType.get(type) ?? null;\n}\n\n// ---------------------------------------------------------------------------\n// Default text-bearing codec — walks visible chars under the block element.\n// Plugins can register the same codec for their own text-bearing blocks\n// (or omit anchorCodec entirely; the consumer falls back to this default).\n// ---------------------------------------------------------------------------\n\nconst ZWSP = \"\";\n\n/** Sum of text-node lengths inside `el`, treating ZWSP placeholders as 0. */\nfunction visibleTextLength(el: HTMLElement): number {\n let n = 0;\n const walk = (node: Node): void => {\n if (node.nodeType === 3) {\n const t = (node as Text).data;\n if (t !== ZWSP) n += t.length;\n return;\n }\n for (const c of Array.from(node.childNodes)) walk(c);\n };\n walk(el);\n return n;\n}\n\n/** Visible-character offset from start of `scopeEl` to (hitNode, localOffset). */\nexport function offsetWithinScope(\n scopeEl: HTMLElement,\n hitNode: Node,\n localOffset: number,\n): number {\n if (!scopeEl.contains(hitNode) && hitNode !== scopeEl) {\n const cmp = scopeEl.compareDocumentPosition(hitNode);\n if (cmp & Node.DOCUMENT_POSITION_FOLLOWING) return visibleTextLength(scopeEl);\n return 0;\n }\n const range = document.createRange();\n try {\n range.selectNodeContents(scopeEl);\n range.setEnd(hitNode, Math.max(0, localOffset));\n const text = range.toString();\n return text.replace(new RegExp(ZWSP, \"g\"), \"\").length;\n } catch {\n return 0;\n } finally {\n range.detach?.();\n }\n}\n\n/** Walk descendant text nodes to find the (node, offset) at `charOffset`. */\nexport function findTextPoint(scopeEl: HTMLElement, charOffset: number): DomPoint {\n let remaining = charOffset;\n let last: DomPoint | null = null;\n const walk = (node: Node): DomPoint | null => {\n if (node.nodeType === 3) {\n const text = node as Text;\n const data = text.data;\n const len = data === ZWSP ? 0 : data.length;\n if (remaining <= len) {\n return { node: text, offset: data === ZWSP ? 0 : remaining };\n }\n remaining -= len;\n last = { node: text, offset: data === ZWSP ? 0 : data.length };\n return null;\n }\n for (const child of Array.from(node.childNodes)) {\n const hit = walk(child);\n if (hit) return hit;\n }\n return null;\n };\n const direct = walk(scopeEl);\n if (direct) return direct;\n if (last) return last;\n return { node: scopeEl, offset: 0 };\n}\n\n/** Default codec — text-bearing blocks land here when they don't register\n * their own. Path encoding: [charOffset]. */\nexport const defaultTextCodec: AnchorCodec = {\n domToAnchor(blockEl, hit, off) {\n const blockId = blockEl.getAttribute(\"data-block-id\");\n if (!blockId) return null;\n const charOff = offsetWithinScope(blockEl, hit, off);\n return { blockId, path: [charOff], offset: charOff };\n },\n anchorToDom(blockEl, a) {\n const charOff = a.path[0] ?? 0;\n return findTextPoint(blockEl, charOff);\n },\n domScope(blockEl, _a) {\n return blockEl;\n },\n};\n\n// Code-block flavor — model treats `\\n` as a real char at end of every\n// non-last line, but the DOM uses one <div class=\"ce-code-line\"> per line\n// with no actual `\\n` text. Walk lines manually + add 1 per implicit \\n.\nexport const codeBlockCodec: AnchorCodec = {\n domToAnchor(blockEl, hit, off) {\n const blockId = blockEl.getAttribute(\"data-block-id\");\n if (!blockId) return null;\n const lines = blockEl.querySelectorAll<HTMLElement>(\".ce-code-line\");\n if (lines.length === 0) {\n const charOff = offsetWithinScope(blockEl, hit, off);\n return { blockId, path: [charOff], offset: charOff };\n }\n let total = 0;\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n if (line === hit || line.contains(hit)) {\n const inLine = total + offsetWithinScope(line, hit, off);\n return { blockId, path: [inLine], offset: inLine };\n }\n total += visibleTextLength(line);\n if (i < lines.length - 1) total += 1;\n }\n return { blockId, path: [total], offset: total };\n },\n anchorToDom(blockEl, a) {\n const lines = blockEl.querySelectorAll<HTMLElement>(\".ce-code-line\");\n const charOffset = a.path[0] ?? 0;\n if (lines.length === 0) return findTextPoint(blockEl, charOffset);\n let remaining = charOffset;\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const lineLen = visibleTextLength(line);\n if (remaining <= lineLen) return findTextPoint(line, remaining);\n remaining -= lineLen;\n if (i < lines.length - 1) {\n if (remaining === 0) return findTextPoint(lines[i + 1]!, 0);\n remaining -= 1;\n }\n }\n const last = lines[lines.length - 1]!;\n return findTextPoint(last, visibleTextLength(last));\n },\n domScope(blockEl, _a) {\n return blockEl;\n },\n};\n\n// Generic atomic-block codec — used by any non-editable block whose only\n// valid caret positions are \"before\" (side 0) and \"after\" (side 1). The\n// block view should render `contenteditable=\"false\"` so the browser places\n// the native caret around the block, not inside.\n//\n// Plugins can mark explicit before/after slots with sentinel elements\n// (`<span data-side=\"0\">`/`<span data-side=\"1\">`) — useful when you need\n// the browser to land the caret at a precise visual position, e.g. on a\n// new line below the block. When no sentinels are present we fall back to\n// \"first half / second half\" of the block bounds: hits where the offset is\n// past the midpoint of the block element become side 1, otherwise side 0.\nexport const atomicCodec: AnchorCodec = {\n domToAnchor(blockEl, node, offset) {\n const blockId = blockEl.getAttribute(\"data-block-id\");\n if (!blockId) return null;\n let side: 0 | 1 = 0;\n // Walk up from the hit looking for an explicit data-side marker.\n let cur: Node | null = node;\n while (cur && cur !== blockEl) {\n if (cur.nodeType === 1) {\n const el = cur as HTMLElement;\n const sideAttr = el.getAttribute(\"data-side\");\n if (sideAttr === \"0\" || sideAttr === \"1\") {\n side = sideAttr === \"1\" ? 1 : 0;\n return { blockId, path: [side], offset: side };\n }\n }\n cur = cur.parentNode;\n }\n // Fallback: compare against block's child count midpoint when the hit\n // is the block element itself, or sniff by getBoundingClientRect for\n // hits inside child content (rare under contenteditable=false).\n if (node === blockEl) {\n const childCount = blockEl.childNodes.length;\n side = offset >= Math.ceil(childCount / 2) ? 1 : 0;\n } else {\n // For hits inside the block, side is decided by which half of the\n // block bounds the hit-node sits in. This handles cases where the\n // browser places the selection on a child element.\n try {\n const blockRect = blockEl.getBoundingClientRect();\n const targetEl =\n node.nodeType === 1 ? (node as HTMLElement) : node.parentElement;\n if (targetEl) {\n const r = targetEl.getBoundingClientRect();\n const midY = blockRect.top + blockRect.height / 2;\n side = r.top + r.height / 2 >= midY ? 1 : 0;\n }\n } catch {\n // happy-dom / non-laid-out nodes — leave side at 0.\n }\n }\n return { blockId, path: [side], offset: side };\n },\n anchorToDom(blockEl, a) {\n const side = a.path[0] === 1 ? 1 : 0;\n const marker = blockEl.querySelector<HTMLElement>(`[data-side=\"${side}\"]`);\n if (marker) return { node: marker, offset: 0 };\n // Fallback: anchor outside the block (parent before/after the block).\n // Putting the caret on `blockEl` itself with offset 0/childCount is\n // less reliable because contenteditable=false blocks the caret from\n // landing there in some browsers.\n const parent = blockEl.parentNode;\n if (parent) {\n const idx = Array.from(parent.childNodes).indexOf(blockEl);\n if (idx >= 0) return { node: parent, offset: side === 0 ? idx : idx + 1 };\n }\n return { node: blockEl, offset: side === 1 ? blockEl.childNodes.length : 0 };\n },\n domScope(blockEl, _a) {\n return blockEl;\n },\n};\n\n// Image codec — the caret only has two valid positions: side 0 (before)\n// or side 1 (after). The block element is contenteditable=false, so the\n// browser already declines to put the caret inside it.\n//\n// Kept as a separate export (instead of dropping into atomicCodec) because\n// ImageView doesn't emit data-side sentinels — the codec falls back to the\n// `<img>` tag's index in the block's child list.\nexport const imageCodec: AnchorCodec = {\n domToAnchor(blockEl, node, offset) {\n const blockId = blockEl.getAttribute(\"data-block-id\");\n if (!blockId) return null;\n let side: 0 | 1 = 0;\n if (node === blockEl) {\n const children = Array.from(blockEl.childNodes);\n const imgIdx = children.findIndex(\n (c) =>\n c.nodeType === 1 &&\n (c as HTMLElement).tagName.toLowerCase() === \"img\",\n );\n side = imgIdx >= 0 && offset > imgIdx ? 1 : 0;\n } else {\n let cur: Node | null = node;\n while (cur && cur !== blockEl) {\n if (cur.nodeType === 1) {\n const el = cur as HTMLElement;\n const sideAttr = el.getAttribute(\"data-side\");\n if (sideAttr === \"0\" || sideAttr === \"1\") {\n side = sideAttr === \"1\" ? 1 : 0;\n break;\n }\n if (el.tagName.toLowerCase() === \"img\") {\n side = 0;\n break;\n }\n }\n cur = cur.parentNode;\n }\n }\n return { blockId, path: [side], offset: side };\n },\n anchorToDom(blockEl, a) {\n const side = a.path[0] === 1 ? 1 : 0;\n const marker = blockEl.querySelector<HTMLElement>(`[data-side=\"${side}\"]`);\n if (marker) return { node: marker, offset: 0 };\n const children = Array.from(blockEl.childNodes);\n const imgIdx = children.findIndex(\n (c) =>\n c.nodeType === 1 && (c as HTMLElement).tagName.toLowerCase() === \"img\",\n );\n if (imgIdx < 0) return { node: blockEl, offset: 0 };\n return { node: blockEl, offset: side === 1 ? imgIdx + 1 : imgIdx };\n },\n domScope(blockEl, _a) {\n return blockEl;\n },\n};\n\n// ---------------------------------------------------------------------------\n// findOwningBlockEl — hoisted here so the registry-driven anchorMap can\n// share the same walk that the table / columns codecs use.\n// ---------------------------------------------------------------------------\n\nexport function findOwningBlockEl(node: Node): HTMLElement | null {\n let cur: Node | null = node;\n while (cur && cur.nodeType !== 1) cur = cur.parentNode;\n while (cur && cur.nodeType === 1) {\n const el = cur as HTMLElement;\n if (el.hasAttribute(\"data-block-kind\")) return el;\n cur = el.parentElement;\n }\n return null;\n}\n\n/** Pluggable anchor → which is just looking up the registered codec.\n * Centralized here so anchorMap.ts and other consumers share one path. */\nexport function lookupAnchorCodec(kind: string): AnchorCodec | null {\n return getAnchorCodec(kind);\n}\n\n// Re-export for external/internal types that used to import DomPoint from\n// dom/anchorMap directly.\nexport type { DomPoint };\n",
|
|
28
|
+
"// ---------------------------------------------------------------------------\n// DOM ↔ Anchor mapping\n//\n// Public entry points (`domToAnchor`, `anchorToDom`, `findBlockElementById`)\n// are unchanged for callers. Internally, per-kind path encoding and DOM\n// walking has moved to per-block AnchorCodec entries registered via the\n// plugin system (src/plugin/anchorCodec.ts and src/plugin/builtin.ts).\n//\n// This file is responsible for finding the outer block element for a given\n// hit / id, then delegating the visible-character math to the codec\n// registered for that block kind. Text-bearing blocks (p/h*/li) fall through\n// to a shared default codec that handles the \"[charOffset]\" path encoding.\n// ---------------------------------------------------------------------------\n\nimport type { Anchor, BlockId } from \"../model/types\";\nimport {\n defaultTextCodec,\n findOwningBlockEl,\n lookupAnchorCodec,\n} from \"../plugin/anchorCodec\";\n\nexport type BlockKind =\n | \"p\"\n | \"h1\"\n | \"h2\"\n | \"h3\"\n | \"h4\"\n | \"h5\"\n | \"h6\"\n | \"li\"\n | \"code\"\n | \"img\"\n | \"table\"\n | \"columns\";\n\n/**\n * Find the OUTER block element with the given block id, scoped under `root`.\n *\n * Required filter: both `data-block-id` and `data-block-kind` — the latter\n * disambiguates the block container from inner cells (table cells / column\n * cells share the owning block's `data-block-id`).\n */\nexport function findBlockElementById(\n root: HTMLElement,\n blockId: BlockId,\n): HTMLElement | null {\n return root.querySelector(\n `[data-block-kind][data-block-id=\"${cssEscape(blockId)}\"]`,\n ) as HTMLElement | null;\n}\n\nfunction cssEscape(s: string): string {\n return s.replace(/([\"\\\\])/g, \"\\\\$1\");\n}\n\n// ---------------------------------------------------------------------------\n// DOM → Anchor (forward)\n// ---------------------------------------------------------------------------\n\n/**\n * Convert a (DOM node, offset) selection point into an editor Anchor.\n *\n * Returns null when the node is outside any block element (e.g. user clicked\n * editor chrome). Coarse but never crashes.\n */\nexport function domToAnchor(\n node: Node,\n offset: number,\n root: HTMLElement,\n): Anchor | null {\n if (!root.contains(node) && node !== root) return null;\n const blockEl = findOwningBlockEl(node);\n if (!blockEl) return null;\n const kind = blockEl.getAttribute(\"data-block-kind\");\n if (!kind) return null;\n // Plugin codec wins; default text-bearing codec is the fallback for any\n // block kind that doesn't register one explicitly.\n const codec = lookupAnchorCodec(kind) ?? defaultTextCodec;\n return codec.domToAnchor(blockEl, node, offset);\n}\n\n// ---------------------------------------------------------------------------\n// Anchor → DOM (reverse)\n// ---------------------------------------------------------------------------\n\nexport type DomPoint = { node: Node; offset: number };\n\n/**\n * Convert an editor Anchor into a (DOM node, offset) pair suitable for\n * `Range.setStart` / `Selection.collapse`. Returns null when the block can't\n * be found in the DOM (not yet rendered, virtualized off-screen, etc.).\n */\nexport function anchorToDom(\n anchor: Anchor,\n root: HTMLElement,\n): DomPoint | null {\n const blockEl = findBlockElementById(root, anchor.blockId);\n if (!blockEl) return null;\n const kind = blockEl.getAttribute(\"data-block-kind\");\n if (!kind) return null;\n const codec = lookupAnchorCodec(kind) ?? defaultTextCodec;\n return codec.anchorToDom(blockEl, anchor);\n}\n",
|
|
29
|
+
"// ---------------------------------------------------------------------------\n// HTML serialization — plugin-driven per-block, with list grouping handled\n// here because <ul>/<ol> open/close spans across multiple `li` blocks.\n//\n// Per-block serializeHTML lives in the BlockDef the plugin registered. We\n// look it up via getHtmlSerializer(block.type) and prepend a list-open or\n// list-close prefix as needed.\n// ---------------------------------------------------------------------------\n\nimport { iterBlocks } from \"../model/doc\";\nimport {\n blockTextLength,\n isTextBearing,\n splitRunsAt,\n type TextBearingBlock,\n} from \"../model/blockText\";\nimport {\n anchorOffset,\n orderedRange,\n} from \"../controller/selection\";\nimport { getHtmlSerializer } from \"../plugin/htmlCodec\";\nimport type {\n Block,\n ColumnsBlock,\n DocState,\n InlineRun,\n ListItemBlock,\n Selection,\n TableBlock,\n} from \"../model/types\";\n\nfunction escapePlain(s: string): string {\n return s.replace(//g, \"\");\n}\n\nfunction blockToHtml(block: Block, listOpen: { tag: string | null }): string {\n let prefix = \"\";\n if (block.type === \"li\") {\n const li = block as ListItemBlock;\n const wantTag = li.ordered ? \"ol\" : \"ul\";\n if (listOpen.tag !== wantTag) {\n if (listOpen.tag) prefix += `</${listOpen.tag}>`;\n prefix += `<${wantTag}>`;\n listOpen.tag = wantTag;\n }\n } else if (listOpen.tag) {\n prefix += `</${listOpen.tag}>`;\n listOpen.tag = null;\n }\n const ser = getHtmlSerializer(block.type);\n if (!ser) return prefix;\n return prefix + ser(block);\n}\n\n/** Whole-doc serialization (used by toJSON-ish helpers and copy-all). */\nexport function docToHtml(doc: DocState): string {\n const listOpen = { tag: null as string | null };\n let html = \"\";\n for (const b of iterBlocks(doc)) html += blockToHtml(b, listOpen);\n if (listOpen.tag) html += `</${listOpen.tag}>`;\n return html;\n}\n\nexport function docToPlain(doc: DocState): string {\n const lines: string[] = [];\n for (const b of iterBlocks(doc)) {\n if (isTextBearing(b)) {\n lines.push(escapePlain(runsText((b as TextBearingBlock).runs)));\n } else if (b.type === \"img\") {\n lines.push(b.alt ?? \"[image]\");\n } else if (b.type === \"table\") {\n const t = b as TableBlock;\n for (let r = 0; r < t.rows; r++) {\n const cols: string[] = [];\n for (let c = 0; c < t.cols; c++) {\n cols.push(escapePlain(runsText(t.cells[r]?.[c] ?? [])));\n }\n lines.push(cols.join(\"\\t\"));\n }\n } else if (b.type === \"columns\") {\n const cb = b as ColumnsBlock;\n const cols: string[] = [];\n for (let c = 0; c < cb.cols; c++) {\n cols.push(escapePlain(runsText(cb.cells[c] ?? [])));\n }\n lines.push(cols.join(\"\\t\"));\n }\n }\n return lines.join(\"\\n\");\n}\n\nfunction runsText(runs: InlineRun[]): string {\n let s = \"\";\n for (const r of runs) s += r.text;\n return s;\n}\n\n// ---------------------------------------------------------------------------\n// Selection serialization — produce HTML + plain text for the OS clipboard.\n// ---------------------------------------------------------------------------\n\nexport type ClipboardPayload = {\n html: string;\n plain: string;\n};\n\nexport function selectionToClipboard(\n doc: DocState,\n sel: Selection,\n): ClipboardPayload {\n if (sel.kind === \"caret\") return { html: \"\", plain: \"\" };\n const { start, end } = orderedRange(doc, sel);\n if (start.blockId === end.blockId) {\n const block = doc.byId.get(start.blockId);\n if (!block || !isTextBearing(block)) return { html: \"\", plain: \"\" };\n const sOff = anchorOffset(start);\n const eOff = anchorOffset(end);\n const [, midRight] = splitRunsAt(\n (block as TextBearingBlock).runs,\n sOff,\n );\n const [middle] = splitRunsAt(midRight, eOff - sOff);\n const slice: TextBearingBlock = {\n ...(block as TextBearingBlock),\n runs: middle,\n };\n const listOpen = { tag: null as string | null };\n let html = blockToHtml(slice as Block, listOpen);\n if (listOpen.tag) html += `</${listOpen.tag}>`;\n return { html, plain: runsText(middle) };\n }\n // Multi-block.\n const startI = doc.order.indexOf(start.blockId);\n const endI = doc.order.indexOf(end.blockId);\n if (startI < 0 || endI < 0) return { html: \"\", plain: \"\" };\n const listOpen = { tag: null as string | null };\n let html = \"\";\n const lines: string[] = [];\n for (let i = startI; i <= endI; i++) {\n const b = doc.byId.get(doc.order[i]!)!;\n let slice: Block = b;\n if (isTextBearing(b)) {\n let runs = (b as TextBearingBlock).runs;\n if (i === startI) {\n const [, right] = splitRunsAt(runs, anchorOffset(start));\n runs = right;\n }\n if (i === endI) {\n const len = blockTextLength({\n ...(b as TextBearingBlock),\n runs,\n } as TextBearingBlock);\n const eOff = anchorOffset(end) - (i === startI ? anchorOffset(start) : 0);\n const [left] = splitRunsAt(runs, Math.min(len, eOff));\n runs = left;\n }\n slice = { ...(b as TextBearingBlock), runs } as Block;\n lines.push(runsText(runs));\n } else {\n lines.push(\n b.type === \"img\"\n ? (b.alt ?? \"[image]\")\n : b.type === \"columns\"\n ? \"[columns]\"\n : \"[table]\",\n );\n }\n html += blockToHtml(slice, listOpen);\n }\n if (listOpen.tag) html += `</${listOpen.tag}>`;\n return { html, plain: lines.join(\"\\n\") };\n}\n",
|
|
30
|
+
"// ---------------------------------------------------------------------------\n// Plugin keymap matcher — evaluates KeymapDef[] against a keyboard event in\n// registration order. The first entry whose chord matches AND whose `when`\n// predicate (if any) returns true wins.\n//\n// Chord syntax:\n// tokens joined by \"+\", e.g. \"Tab\", \"Shift+Tab\", \"Mod+B\", \"Mod+Shift+S\".\n// Modifiers: Mod (Cmd on Mac, Ctrl elsewhere), Shift, Alt, Ctrl, Meta.\n// Final token = e.key value (case-insensitive for single chars).\n//\n// Matching is STRICT on modifiers: \"Tab\" matches only when no modifier is\n// held; \"Shift+Tab\" matches only when Shift (and only Shift) is held. This\n// avoids ambiguous overlaps when a plugin registers both.\n// ---------------------------------------------------------------------------\n\nimport type { CommandCtx, KeymapDef } from \"./types\";\nimport { isMac } from \"../input/keymap\";\n\ntype ParsedChord = {\n key: string;\n shift: boolean;\n alt: boolean;\n // After resolving Mod → meta on Mac / ctrl elsewhere.\n meta: boolean;\n ctrl: boolean;\n};\n\nfunction parseChord(chord: string): ParsedChord {\n const parts = chord.split(\"+\");\n const last = parts[parts.length - 1] ?? \"\";\n let shift = false;\n let alt = false;\n let meta = false;\n let ctrl = false;\n for (let i = 0; i < parts.length - 1; i++) {\n const m = parts[i] ?? \"\";\n if (m === \"Shift\") shift = true;\n else if (m === \"Alt\") alt = true;\n else if (m === \"Mod\") {\n if (isMac()) meta = true;\n else ctrl = true;\n } else if (m === \"Meta\" || m === \"Cmd\") meta = true;\n else if (m === \"Ctrl\" || m === \"Control\") ctrl = true;\n }\n return { key: last, shift, alt, meta, ctrl };\n}\n\nfunction eqKey(eventKey: string, chordKey: string): boolean {\n if (eventKey === chordKey) return true;\n if (eventKey.length === 1 && chordKey.length === 1) {\n return eventKey.toLowerCase() === chordKey.toLowerCase();\n }\n return false;\n}\n\nfunction chordMatches(e: KeyboardEvent, c: ParsedChord): boolean {\n if (!eqKey(e.key, c.key)) return false;\n if (e.shiftKey !== c.shift) return false;\n if (e.altKey !== c.alt) return false;\n if (e.metaKey !== c.meta) return false;\n if (e.ctrlKey !== c.ctrl) return false;\n return true;\n}\n\nconst cache = new Map<string, ParsedChord>();\nfunction chordOf(s: string): ParsedChord {\n let p = cache.get(s);\n if (!p) {\n p = parseChord(s);\n cache.set(s, p);\n }\n return p;\n}\n\nexport function matchPluginKeymap(\n e: KeyboardEvent,\n entries: KeymapDef[],\n ctx: CommandCtx,\n): KeymapDef | null {\n for (const entry of entries) {\n if (!chordMatches(e, chordOf(entry.chord))) continue;\n if (entry.when && !entry.when(ctx)) continue;\n return entry;\n }\n return null;\n}\n",
|
|
31
|
+
"// ---------------------------------------------------------------------------\n// Native (contentEditable) input pipeline\n//\n// The contentEditable migration replaces the hidden-textarea approach with\n// the browser's native selection + IME, while keeping the editor in full\n// control of mutations: every `beforeinput` event is preventDefaulted and\n// translated into an editor command. The browser writes to the DOM only\n// during IME composition, which is reconciled on `compositionend` (Phase 3).\n//\n// Phase 1+2 scope (this file):\n// ✓ Bidirectional selection sync (Anchor ↔ native Range)\n// ✓ beforeinput → command dispatch for the basic inputTypes\n// ✓ Keyboard chord matching via the existing keymap module\n// ✓ Clipboard wiring (copy / cut / paste) on the editor root\n// ✗ IME composition reconciliation — deferred to Phase 3 (browser default\n// fires for now; model will diverge during composition)\n// ✗ Multi-cell table selection — deferred to Phase 4\n// ✗ Per-cell contenteditable=false islands — deferred to Phase 4\n// ---------------------------------------------------------------------------\n\nimport type { Store } from \"creo\";\nimport type {\n Anchor,\n DocState,\n Selection,\n Mark,\n} from \"../model/types\";\nimport type { DispatchableCommand } from \"../createEditor\";\nimport { caret as caretSel, range as rangeSel } from \"../controller/selection\";\nimport { matchKeymap } from \"./keymap\";\nimport { anchorToDom, domToAnchor, findBlockElementById } from \"../dom/anchorMap\";\nimport { parseHTML, parsePlainText } from \"../clipboard/htmlParser\";\nimport { selectionToClipboard } from \"../clipboard/htmlSerializer\";\nimport { insertBlocks } from \"../commands/insertCommands\";\nimport {\n insertImageFiles,\n type UploadFn,\n} from \"../commands/imageCommands\";\nimport { deleteSelectedAtomic } from \"../commands/imageCommands\";\nimport { isAtomicBlockType } from \"../plugin/atomic\";\nimport { lookupAnchorCodec } from \"../plugin/anchorCodec\";\nimport { runsLengthAt } from \"../plugin/runsAt\";\nimport { matchPluginKeymap } from \"../plugin/keymapMatch\";\nimport type { Registry } from \"../plugin/registry\";\nimport type { TriggerManager } from \"../plugin/triggers\";\n\nconst ZWSP = \"\";\n\n/**\n * Schedule `cb` after the current render flush. Production: requestAnimationFrame\n * runs after Creo's microtask scheduler. Test (happy-dom): rAF isn't exposed\n * as a global; queueMicrotask is the closest equivalent and runs in the same\n * tick so we don't lose timing.\n */\nconst scheduleAfterRender = (cb: () => void): void => {\n if (typeof requestAnimationFrame !== \"undefined\") {\n requestAnimationFrame(cb);\n } else {\n queueMicrotask(cb);\n }\n};\n\nexport type NativeInputStores = {\n docStore: Store<DocState>;\n selStore: Store<Selection>;\n};\n\nexport type NativeInputOptions = {\n dispatch: (cmd: DispatchableCommand) => void;\n undo: () => void;\n redo: () => void;\n selectAll: () => void;\n /** Optional upload hook for pasted / dropped image files. */\n uploadImage?: UploadFn;\n /** Plugin registry — keymap matching, command dispatch for plugin chords. */\n registry: Registry;\n /** Trigger manager — watches text insertion + key events for plugin\n * triggers (slash commands, mentions, etc.). */\n triggers: TriggerManager;\n};\n\nexport type NativeInputHandle = {\n destroy: () => void;\n};\n\n// ---------------------------------------------------------------------------\n// Selection sync — bidirectional\n//\n// We use a sequence number rather than a boolean \"suppressing\" flag because\n// selectionchange fires asynchronously after a programmatic write; a boolean\n// would race with subsequent user-driven changes.\n// ---------------------------------------------------------------------------\n\nexport function attachNativeInput(\n root: HTMLElement,\n stores: NativeInputStores,\n options: NativeInputOptions,\n): NativeInputHandle {\n const { docStore, selStore } = stores;\n\n // Make the root editable. Browser default = false, so we set it explicitly.\n // We also set spellcheck off for now — can be exposed as an option later.\n root.setAttribute(\"contenteditable\", \"true\");\n root.setAttribute(\"spellcheck\", \"false\");\n\n // -------------------------------------------------------------------------\n // Selection sync: native ↔ Anchor\n //\n // Two coordination devices keep the loop free of feedback bugs:\n //\n // 1. `programmaticSeq` / `lastObservedSeq` — a sequence-number guard.\n // Every programmatic write to native selection bumps `programmaticSeq`;\n // the next selectionchange event is the echo of that write and is\n // ignored (we advance `lastObservedSeq` to match). User-driven\n // changes (where seqs already match) are forwarded to selStore.\n //\n // 2. `renderPending` — a render-window flag. When the renderer replaces\n // text nodes for a mutated block, native selection collapses onto\n // detached nodes and the browser fires a SECOND selectionchange that\n // would otherwise corrupt selStore (typing one char would jump the\n // caret to start of doc). On every docStore change we set the flag,\n // and clear it in the next rAF after re-applying native selection\n // from the (correct) selStore. selectionchange events that fire\n // while pending are dropped.\n // -------------------------------------------------------------------------\n\n let programmaticSeq = 0;\n let lastObservedSeq = 0;\n let renderPending = false;\n\n // -------------------------------------------------------------------------\n // IME composition state (Phase 3)\n //\n // During an active composition, the browser writes intermediate (and final)\n // text directly into the DOM. The model is held frozen until compositionend,\n // at which point we diff the affected scope's textContent against the\n // pre-composition snapshot and dispatch a single `insertText` command — this\n // keeps the entire composition under a single undo step and preserves marks\n // outside the composition range automatically.\n // -------------------------------------------------------------------------\n\n let composing = false;\n let compositionSnapshot: {\n anchor: Anchor;\n /** Text length of the relevant scope (block / table cell / column cell). */\n preLength: number;\n } | null = null;\n\n /** Convert the current native selection to an editor Selection. */\n const readNativeSelection = (): Selection | null => {\n const native = document.getSelection();\n if (!native || native.rangeCount === 0) return null;\n const a = native.anchorNode;\n const ao = native.anchorOffset;\n const f = native.focusNode;\n const fo = native.focusOffset;\n if (!a || !f) return null;\n // Reject selections that escape the editor.\n if (!root.contains(a) || !root.contains(f)) return null;\n const anchor = domToAnchor(a, ao, root);\n const focus = domToAnchor(f, fo, root);\n if (!anchor || !focus) return null;\n if (\n anchor.blockId === focus.blockId &&\n anchor.offset === focus.offset &&\n anchor.path.length === focus.path.length &&\n anchor.path.every((v, i) => v === focus.path[i])\n ) {\n return caretSel(anchor);\n }\n return rangeSel(anchor, focus);\n };\n\n /** Apply an editor Selection to native window.getSelection(). */\n const applyNativeSelection = (sel: Selection): void => {\n const native = document.getSelection();\n if (!native) return;\n const anchorPoint =\n sel.kind === \"caret\"\n ? anchorToDom(sel.at, root)\n : anchorToDom(sel.anchor, root);\n const focusPoint =\n sel.kind === \"caret\"\n ? anchorPoint\n : anchorToDom(sel.focus, root);\n // Virtualization escape hatch: when a range endpoint lives in a block\n // that isn't currently mounted (Cmd+A across a 7,500-paragraph doc, only\n // ~60 viewport blocks in the DOM), neither setBaseAndExtent nor a\n // hand-rolled root-edge Range reliably renders a visible highlight\n // (browsers collapse on cross-tree containment quirks). Fall back to\n // selectAllChildren(root) — it always selects the mounted content. The\n // model selection stays canonical for commands.\n if (sel.kind === \"range\" && (!anchorPoint || !focusPoint)) {\n try {\n programmaticSeq++;\n native.removeAllRanges();\n native.selectAllChildren(root);\n } catch {\n // Headless environments may throw; nothing more to do.\n }\n return;\n }\n if (!anchorPoint || !focusPoint) return;\n // Don't bump programmaticSeq when writing the same selection the\n // browser already has — `setBaseAndExtent(...)` to the current\n // position is a no-op and fires no `selectionchange`. If we bump\n // anyway, the next user-driven selectionchange is mistakenly\n // consumed as the \"missing\" echo and the user's click is dropped.\n if (\n native.anchorNode === anchorPoint.node &&\n native.anchorOffset === anchorPoint.offset &&\n native.focusNode === focusPoint.node &&\n native.focusOffset === focusPoint.offset\n ) {\n return;\n }\n try {\n native.setBaseAndExtent(\n anchorPoint.node,\n anchorPoint.offset,\n focusPoint.node,\n focusPoint.offset,\n );\n } catch {\n // happy-dom / older browsers may throw on cross-tree ranges; fall back\n // to collapsed caret at the anchor.\n try {\n native.removeAllRanges();\n const range = document.createRange();\n range.setStart(anchorPoint.node, anchorPoint.offset);\n range.collapse(true);\n native.addRange(range);\n } catch {\n // Truly headless — nothing more we can do.\n }\n }\n // Bump programmaticSeq ONLY if the write actually moved the native\n // selection. If the call was a no-op (target nodes detached, or the\n // browser silently rejected the write), `selectionchange` won't\n // fire — bumping the seq anyway would consume the next user-driven\n // event as a phantom echo.\n if (\n native.anchorNode !== anchorPoint.node ||\n native.anchorOffset !== anchorPoint.offset ||\n native.focusNode !== focusPoint.node ||\n native.focusOffset !== focusPoint.offset\n ) {\n // Selection didn't actually move — don't expect an echo.\n return;\n }\n programmaticSeq++;\n };\n\n const onSelectionChange = (): void => {\n // Drop while composing — the IME advances native selection through\n // intermediate positions; we only care about the final state, captured\n // on compositionend.\n if (composing) return;\n // Drop selectionchange while a render is pending — the browser will fire\n // an extra event when the mutated block's text nodes get replaced, and\n // it points at detached nodes that map to bogus offsets.\n if (renderPending) return;\n // The first selectionchange after a programmatic write is the echo;\n // advance lastObservedSeq and ignore. Subsequent events (user-driven,\n // when seqs match) are forwarded.\n if (programmaticSeq !== lastObservedSeq) {\n lastObservedSeq = programmaticSeq;\n return;\n }\n // Logical-only range guard: if selStore currently holds a range with at\n // least one endpoint in an unmounted block (e.g. Cmd+A across a\n // virtualized doc), native selection can never fully represent it.\n // Render-induced selectionchange events would otherwise collapse the\n // model range to a caret in the visible portion every time VirtualDoc\n // re-mounts. We treat the model as canonical in that state.\n const current = selStore.get();\n if (current.kind === \"range\") {\n const anchorMounted = !!anchorToDom(current.anchor, root);\n const focusMounted = !!anchorToDom(current.focus, root);\n if (!anchorMounted || !focusMounted) return;\n }\n const sel = readNativeSelection();\n if (sel) selStore.set(sel);\n };\n\n document.addEventListener(\"selectionchange\", onSelectionChange);\n\n // Sync the initial selection on mount.\n applyNativeSelection(selStore.get());\n\n // selStore-only changes (user drag, programmatic selection without doc\n // mutation): apply native selection synchronously. NO deferred re-apply\n // here — re-applying via setBaseAndExtent during an in-progress user\n // drag-selection in the browser disturbs the drag, breaking selection\n // entirely. The deferred path is only needed when the model holds a\n // logical-only range (one endpoint in an unmounted block) AND VirtualDoc\n // is about to re-render and collapse our selectAllChildren fallback.\n const unsubSel = selStore.subscribe(() => {\n if (composing) return;\n if (renderPending) return;\n const current = readNativeSelection();\n const target = selStore.get();\n if (current && selectionsEqual(current, target)) return;\n applyNativeSelection(target);\n // Targeted deferred re-apply for the logical-only case.\n if (target.kind === \"range\") {\n const aOK = !!anchorToDom(target.anchor, root);\n const fOK = !!anchorToDom(target.focus, root);\n if (!aOK || !fOK) {\n renderPending = true;\n scheduleAfterRender(() => {\n applyNativeSelection(selStore.get());\n renderPending = false;\n });\n }\n }\n });\n\n // docStore changes mean the renderer is about to replace the touched\n // block's text nodes. Native selection collapses onto the detached nodes;\n // restore it from the canonical selStore on the next animation frame, by\n // which time the reconciler has produced fresh nodes.\n const unsubDoc = docStore.subscribe(() => {\n if (composing) return;\n if (renderPending) return;\n renderPending = true;\n scheduleAfterRender(() => {\n applyNativeSelection(selStore.get());\n renderPending = false;\n });\n });\n\n // -------------------------------------------------------------------------\n // beforeinput → command dispatch\n //\n // Every inputType is preventDefaulted and translated. The browser is not\n // allowed to mutate the DOM (except during IME composition — see below).\n // -------------------------------------------------------------------------\n\n // Backspace / Delete need to choose between within-block delete and block\n // merging at boundaries. The split: a caret at offset 0 of a non-first\n // text-bearing block, or a range that crosses block boundaries, dispatches\n // mergeBackward; otherwise plain deleteBackward. (mergeBackward also\n // collapses cross-block ranges via its own range-collapse logic.) Symmetric\n // pair for deleteForward / mergeForward at end-of-block.\n const handleBackspace = (): void => {\n const sel = selStore.get();\n if (sel.kind === \"range\") {\n if (sel.anchor.blockId !== sel.focus.blockId) {\n options.dispatch({ t: \"mergeBackward\" });\n return;\n }\n options.dispatch({ t: \"deleteBackward\" });\n return;\n }\n const at = sel.at;\n // Caret on an atomic (non-editable) block: delete the whole block.\n const block = docStore.get().byId.get(at.blockId);\n if (block && isAtomicBlockType(block.type)) {\n deleteSelectedAtomic({ docStore, selStore });\n return;\n }\n const lastPathEntry = at.path[at.path.length - 1] ?? 0;\n if (lastPathEntry === 0 && at.path.length === 1) {\n // Top-level text-bearing block at offset 0 — try merge with prior block.\n const doc = docStore.get();\n const idx = doc.order.indexOf(at.blockId);\n if (idx > 0) {\n options.dispatch({ t: \"mergeBackward\" });\n return;\n }\n }\n options.dispatch({ t: \"deleteBackward\" });\n };\n\n const handleDelete = (): void => {\n const sel = selStore.get();\n if (sel.kind === \"range\") {\n if (sel.anchor.blockId !== sel.focus.blockId) {\n options.dispatch({ t: \"mergeForward\" });\n return;\n }\n options.dispatch({ t: \"deleteForward\" });\n return;\n }\n const at = sel.at;\n // Caret on an atomic block: forward-delete just removes the block.\n const block = docStore.get().byId.get(at.blockId);\n if (block && isAtomicBlockType(block.type)) {\n deleteSelectedAtomic({ docStore, selStore });\n return;\n }\n if (at.path.length === 1) {\n const doc = docStore.get();\n const tb = doc.byId.get(at.blockId);\n if (tb && \"runs\" in tb) {\n const len = tb.runs.reduce((n, r) => n + r.text.length, 0);\n const off = at.path[0] ?? 0;\n const idx = doc.order.indexOf(at.blockId);\n if (off === len && idx >= 0 && idx < doc.order.length - 1) {\n options.dispatch({ t: \"mergeForward\" });\n return;\n }\n }\n }\n options.dispatch({ t: \"deleteForward\" });\n };\n\n const onBeforeInput = (e: InputEvent): void => {\n const t = e.inputType;\n\n // IME composition — let the browser write into the DOM. Phase 3 will\n // reconcile on compositionend; for now this means the model diverges\n // during active composition. Acceptable temporary breakage.\n if (\n t === \"insertCompositionText\" ||\n t === \"insertFromComposition\" ||\n t === \"deleteCompositionText\"\n ) {\n return;\n }\n\n e.preventDefault();\n\n switch (t) {\n case \"insertText\": {\n if (e.data) {\n options.dispatch({ t: \"insertText\", text: e.data });\n // Notify trigger manager AFTER the text has been spliced into\n // the model — slash menus / mentions match against the just-\n // inserted character(s).\n options.triggers.onTextInserted(e.data);\n }\n return;\n }\n case \"insertParagraph\":\n options.dispatch({ t: \"splitBlock\" });\n return;\n case \"insertLineBreak\":\n // Inside a code block this should insert \"\\n\"; in other text-bearing\n // blocks it should split. Phase 4 refines code-block handling. For\n // now: always split.\n options.dispatch({ t: \"splitBlock\" });\n return;\n case \"deleteContentBackward\":\n case \"deleteWordBackward\":\n case \"deleteSoftLineBackward\":\n case \"deleteHardLineBackward\":\n handleBackspace();\n return;\n case \"deleteContentForward\":\n case \"deleteWordForward\":\n case \"deleteSoftLineForward\":\n case \"deleteHardLineForward\":\n handleDelete();\n return;\n case \"formatBold\":\n options.dispatch({ t: \"toggleMark\", mark: \"b\" });\n return;\n case \"formatItalic\":\n options.dispatch({ t: \"toggleMark\", mark: \"i\" });\n return;\n case \"formatUnderline\":\n options.dispatch({ t: \"toggleMark\", mark: \"u\" });\n return;\n case \"formatStrikeThrough\":\n options.dispatch({ t: \"toggleMark\", mark: \"s\" });\n return;\n case \"historyUndo\":\n options.undo();\n return;\n case \"historyRedo\":\n options.redo();\n return;\n case \"insertReplacementText\": {\n // iOS autocorrect — replace targetRanges with new text.\n if (!e.data) return;\n const ranges = (e as InputEvent & {\n getTargetRanges?: () => StaticRange[];\n }).getTargetRanges?.();\n if (ranges && ranges.length > 0) {\n const target = ranges[0]!;\n const startA = domToAnchor(\n target.startContainer,\n target.startOffset,\n root,\n );\n const endA = domToAnchor(\n target.endContainer,\n target.endOffset,\n root,\n );\n if (startA && endA) {\n // Move selection over the replaced range, then delete and\n // re-insert. Avoids needing a dedicated replaceRange command.\n selStore.set(rangeSel(startA, endA));\n options.dispatch({ t: \"deleteBackward\" });\n options.dispatch({ t: \"insertText\", text: e.data });\n return;\n }\n }\n // Fallback: replace at current selection.\n options.dispatch({ t: \"insertText\", text: e.data });\n return;\n }\n case \"insertFromPaste\":\n case \"insertFromPasteAsQuotation\":\n case \"insertFromYank\":\n case \"insertFromDrop\": {\n // Paste / drop are routed through their dedicated event handlers\n // (paste / drop), where we have access to the clipboard payload.\n // beforeinput here arrives WITHOUT data on most browsers, so the\n // dedicated handlers are authoritative.\n return;\n }\n default:\n // Unknown formatting commands are swallowed silently. Logging here\n // would be noisy on browsers that fire vendor-specific inputTypes.\n return;\n }\n };\n\n root.addEventListener(\"beforeinput\", onBeforeInput as EventListener);\n\n // -------------------------------------------------------------------------\n // keydown → keymap chords\n //\n // beforeinput covers most editing operations on modern browsers, but\n // chord matching for navigation extensions (Cmd+ArrowLeft, Option+Arrow,\n // etc.) and feature shortcuts (Cmd+Shift+S for strikethrough on macOS)\n // still flow through keydown.\n // -------------------------------------------------------------------------\n\n const onKeyDown = (e: KeyboardEvent): void => {\n // Active trigger (slash menu, @-mention, etc.) consumes keys first —\n // arrow nav, Enter pick, Escape cancel are all owned by the trigger UI.\n if (options.triggers.handleKeyDown(e)) return;\n\n // Plugin keymap entries get the next shot — table cell navigation and\n // any user-registered chord. The matcher checks chord + `when`\n // predicate; the command may still no-op (return false), in which case\n // we fall through to the built-in keymap and browser default.\n const ctx = { docStore, selStore };\n const hit = matchPluginKeymap(e, options.registry.keymap, ctx);\n if (hit) {\n const ok = options.registry.runCommand(\n hit.command.t,\n hit.command.payload,\n ctx,\n );\n if (ok) {\n e.preventDefault();\n return;\n }\n // Plugin command was a no-op (e.g. ArrowLeft at start of cell with\n // no previous cell) — fall through so the browser handles natively.\n // We intentionally do NOT preventDefault here.\n }\n\n const builtin = matchKeymap(e);\n if (!builtin) return;\n switch (builtin.kind) {\n case \"toggleMark\":\n e.preventDefault();\n options.dispatch({ t: \"toggleMark\", mark: builtin.mark as Mark });\n return;\n case \"setBlockType\":\n e.preventDefault();\n options.dispatch({ t: \"setBlockType\", payload: builtin.payload });\n return;\n case \"indent\":\n e.preventDefault();\n options.dispatch({ t: \"indentList\" });\n return;\n case \"outdent\":\n e.preventDefault();\n options.dispatch({ t: \"outdentList\" });\n return;\n case \"undo\":\n e.preventDefault();\n options.undo();\n return;\n case \"redo\":\n e.preventDefault();\n options.redo();\n return;\n case \"selectAll\":\n e.preventDefault();\n options.selectAll();\n return;\n case \"moveWord\":\n case \"moveLineEdge\":\n case \"moveDocEdge\":\n // Let the browser handle these natively; selectionchange syncs to\n // selStore. We trust the browser's word-boundary and line-edge\n // logic to match the platform.\n return;\n }\n };\n\n root.addEventListener(\"keydown\", onKeyDown);\n\n // -------------------------------------------------------------------------\n // IME composition handlers\n //\n // Strategy: snapshot the current caret + scope text length on\n // compositionstart, allow the browser to mutate the DOM during composition,\n // then on compositionend diff the scope's textContent against the snapshot\n // and dispatch ONE `insertText` command with the inserted text. Coalesces\n // into a single undo step; preserves marks outside the composition range\n // because the existing insertText command splices into runs correctly.\n //\n // Range-selection-as-composition-start: if the user had a range selected\n // when composition began, we collapse it to the start anchor first and\n // delete the range, so the composition snapshot is always taken against a\n // caret in a known state. Edge-case for v1; matches Slate / ProseMirror.\n // -------------------------------------------------------------------------\n\n /** Length of the model text that owns `anchor` (block / cell / column).\n * Routed through the plugin runsAt registry so blocks with nested runs\n * containers (table cells, columns cells, future plugin blocks) work\n * without per-kind branches here. */\n const modelScopeLength = (a: Anchor): number | null => {\n const block = docStore.get().byId.get(a.blockId);\n if (!block) return null;\n return runsLengthAt(block, a);\n };\n\n /** DOM scope (element + visible textContent) for the given anchor.\n * Pulls the scope via the AnchorCodec.domScope hook (table → <td>,\n * columns → <div data-col>, default → block element itself). */\n const domScope = (\n a: Anchor,\n ): { scope: HTMLElement; text: string } | null => {\n const blockEl = findBlockElementById(root, a.blockId);\n if (!blockEl) return null;\n const kind = blockEl.getAttribute(\"data-block-kind\") ?? \"\";\n const codec = lookupAnchorCodec(kind);\n const scope = codec?.domScope?.(blockEl, a) ?? blockEl;\n const text = (scope.textContent ?? \"\").replace(new RegExp(ZWSP, \"g\"), \"\");\n return { scope, text };\n };\n\n const onCompositionStart = (): void => {\n const sel = selStore.get();\n // If a range was selected, delete it first — we want a caret-only start\n // so the post-composition diff is unambiguous.\n if (sel.kind === \"range\") {\n options.dispatch({ t: \"deleteBackward\" });\n }\n const after = selStore.get();\n if (after.kind !== \"caret\") return;\n // Snapshot length from the MODEL, not the DOM. We may have just\n // dispatched a range-delete and the renderer is async — DOM still shows\n // the pre-delete text. The model is canonical.\n const preLength = modelScopeLength(after.at);\n if (preLength === null) return;\n composing = true;\n compositionSnapshot = { anchor: after.at, preLength };\n };\n\n const onCompositionEnd = (): void => {\n composing = false;\n const snap = compositionSnapshot;\n compositionSnapshot = null;\n if (!snap) return;\n // For the post-composition read we use the DOM, because the browser\n // wrote IME output directly into it (the model is still pre-composition).\n const scope = domScope(snap.anchor);\n if (!scope) {\n docStore.set(docStore.get()); // force render to reconcile\n return;\n }\n const newLen = scope.text.length;\n const insertedLen = newLen - snap.preLength;\n if (insertedLen <= 0) {\n // Cancelled or no-op composition — re-render reconciles DOM to model.\n docStore.set(docStore.get());\n return;\n }\n const offsetInScope =\n snap.anchor.path.length === 1\n ? snap.anchor.path[0] ?? 0\n : snap.anchor.path[snap.anchor.path.length - 1] ?? 0;\n const insertedText = scope.text.slice(\n offsetInScope,\n offsetInScope + insertedLen,\n );\n // Move selStore back to the snapshot anchor so insertText splices at the\n // right position (the live native selection is at end-of-composition,\n // but the model still has pre-composition text).\n selStore.set(caretSel(snap.anchor));\n options.dispatch({ t: \"insertText\", text: insertedText });\n };\n\n root.addEventListener(\"compositionstart\", onCompositionStart);\n root.addEventListener(\"compositionend\", onCompositionEnd);\n\n // -------------------------------------------------------------------------\n // Clipboard: copy / cut / paste\n //\n // The clipboard event fires on the contenteditable root rather than a\n // hidden textarea. Selection is read from selStore (which is in sync via\n // the selectionchange listener), so the existing serializer/parser modules\n // work unchanged.\n // -------------------------------------------------------------------------\n\n /** True when the native selection (or its anchor/focus) lives inside our\n * editor root. Used to gate document-level clipboard listeners so we\n * don't intercept events targeted at other inputs on the page. */\n const selectionInRoot = (): boolean => {\n const sel = document.getSelection();\n if (!sel) return false;\n const a = sel.anchorNode;\n const f = sel.focusNode;\n if (a && root.contains(a)) return true;\n if (f && root.contains(f)) return true;\n return false;\n };\n\n const onCopy = (e: ClipboardEvent): void => {\n if (!selectionInRoot()) return;\n const sel = selStore.get();\n if (sel.kind === \"caret\") return;\n e.preventDefault();\n const payload = selectionToClipboard(docStore.get(), sel);\n e.clipboardData?.setData(\"text/html\", payload.html);\n e.clipboardData?.setData(\"text/plain\", payload.plain);\n };\n\n const onCut = (e: ClipboardEvent): void => {\n if (!selectionInRoot()) return;\n const sel = selStore.get();\n if (sel.kind === \"caret\") return;\n e.preventDefault();\n const payload = selectionToClipboard(docStore.get(), sel);\n e.clipboardData?.setData(\"text/html\", payload.html);\n e.clipboardData?.setData(\"text/plain\", payload.plain);\n options.dispatch({ t: \"deleteBackward\" });\n };\n\n // Shift state side-channel — many browsers don't expose `shiftKey` on\n // ClipboardEvent, so we observe keydown/up to know whether the user held\n // Shift while initiating the paste (forces plain-text insertion).\n let pasteShiftHeld = false;\n const onShiftKey = (e: KeyboardEvent): void => {\n pasteShiftHeld = e.shiftKey === true;\n };\n\n const onPaste = (e: ClipboardEvent): void => {\n if (!selectionInRoot()) return;\n const data = e.clipboardData;\n if (!data) return;\n e.preventDefault();\n // Image files take priority over text — copy-image-from-browser sets\n // both, but the user clearly wants the image when one is available.\n if (data.files && data.files.length > 0) {\n let hasImage = false;\n for (const f of Array.from(data.files)) {\n if (f.type.startsWith(\"image/\")) {\n hasImage = true;\n break;\n }\n }\n if (hasImage) {\n void insertImageFiles(\n { docStore, selStore },\n data.files,\n options.uploadImage,\n );\n return;\n }\n }\n const forcePlain = pasteShiftHeld;\n const html = data.getData(\"text/html\");\n if (!forcePlain && html) {\n const blocks = parseHTML(html);\n if (blocks.length) {\n insertBlocks({ docStore, selStore }, blocks);\n return;\n }\n }\n const plain = data.getData(\"text/plain\");\n if (plain) {\n const blocks = parsePlainText(plain);\n if (blocks.length) insertBlocks({ docStore, selStore }, blocks);\n }\n };\n\n // Listen at document level so clipboard events from the browser's\n // OS context menu (right-click → Cut / Copy / Paste) reach us. The\n // browser dispatches those on the document, not on the contenteditable\n // root, so a root-level listener would miss them. The handlers gate by\n // `selectionInRoot()` to ignore events targeted at other inputs on the\n // page.\n document.addEventListener(\"copy\", onCopy);\n document.addEventListener(\"cut\", onCut);\n document.addEventListener(\"paste\", onPaste);\n root.addEventListener(\"keydown\", onShiftKey, true);\n root.addEventListener(\"keyup\", onShiftKey, true);\n\n // -------------------------------------------------------------------------\n // Cleanup\n // -------------------------------------------------------------------------\n\n return {\n destroy: () => {\n document.removeEventListener(\"selectionchange\", onSelectionChange);\n root.removeEventListener(\"beforeinput\", onBeforeInput as EventListener);\n root.removeEventListener(\"keydown\", onKeyDown);\n root.removeEventListener(\"compositionstart\", onCompositionStart);\n root.removeEventListener(\"compositionend\", onCompositionEnd);\n document.removeEventListener(\"copy\", onCopy);\n document.removeEventListener(\"cut\", onCut);\n document.removeEventListener(\"paste\", onPaste);\n root.removeEventListener(\"keydown\", onShiftKey, true);\n root.removeEventListener(\"keyup\", onShiftKey, true);\n unsubSel();\n unsubDoc();\n root.removeAttribute(\"contenteditable\");\n root.removeAttribute(\"spellcheck\");\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Selection equality — used to short-circuit redundant native writes.\n// ---------------------------------------------------------------------------\n\nfunction selectionsEqual(a: Selection, b: Selection): boolean {\n if (a.kind !== b.kind) return false;\n if (a.kind === \"caret\" && b.kind === \"caret\") {\n return anchorsEq(a.at, b.at);\n }\n if (a.kind === \"range\" && b.kind === \"range\") {\n return anchorsEq(a.anchor, b.anchor) && anchorsEq(a.focus, b.focus);\n }\n return false;\n}\n\nfunction anchorsEq(a: Anchor, b: Anchor): boolean {\n if (a.blockId !== b.blockId) return false;\n if (a.offset !== b.offset) return false;\n if (a.path.length !== b.path.length) return false;\n for (let i = 0; i < a.path.length; i++) {\n if (a.path[i] !== b.path[i]) return false;\n }\n return true;\n}\n",
|
|
32
|
+
"import { _ } from \"creo\";\nimport { ol, ul, view } from \"creo\";\nimport type { Block, DocState, ListItemBlock } from \"../model/types\";\nimport { getView } from \"../plugin/registry\";\n\n/**\n * BlockView — single dispatch view, looks the renderer up by `block.type`\n * in the plugin view registry. The previous switch statement is gone;\n * registering a new block kind is a `registerView` call from a plugin.\n *\n * `shouldUpdate` is an identity check on `block`. Because doc updates produce\n * a fresh top-level DocState but reuse references for unchanged blocks, this\n * lets the reconciler skip every block that wasn't touched.\n */\nconst BlockView = view<{ block: Block }>(({ props }) => ({\n shouldUpdate(next) {\n return next.block !== props().block;\n },\n render() {\n const b = props().block;\n const v = getView(b.type);\n if (!v) return; // Unknown block kind — silently skip; plugin missing.\n v({ block: b, key: b.id });\n },\n}));\n\n/**\n * Group consecutive `li` blocks of the same `ordered` flag into a single\n * `<ul>`/`<ol>`. Returns spans `[start, end)` over `doc.order`.\n */\ntype Span = { kind: \"single\"; pos: number } | {\n kind: \"list\";\n ordered: boolean;\n start: number;\n end: number;\n};\n\nfunction planSpans(doc: DocState): Span[] {\n const out: Span[] = [];\n let i = 0;\n while (i < doc.order.length) {\n const block = doc.byId.get(doc.order[i]!)!;\n if (block.type === \"li\") {\n const ordered = (block as ListItemBlock).ordered;\n let j = i + 1;\n while (j < doc.order.length) {\n const b2 = doc.byId.get(doc.order[j]!)!;\n if (b2.type !== \"li\") break;\n if ((b2 as ListItemBlock).ordered !== ordered) break;\n j++;\n }\n out.push({ kind: \"list\", ordered, start: i, end: j });\n i = j;\n } else {\n out.push({ kind: \"single\", pos: i });\n i++;\n }\n }\n return out;\n}\n\nexport const DocView = view<{ doc: DocState }>(({ props }) => ({\n shouldUpdate(next) {\n return next.doc !== props().doc;\n },\n render() {\n const doc = props().doc;\n const spans = planSpans(doc);\n for (const span of spans) {\n if (span.kind === \"single\") {\n const b = doc.byId.get(doc.order[span.pos]!)!;\n BlockView({ block: b, key: b.id });\n } else {\n // Group key spans the included ids — stable as long as the same\n // contiguous run keeps the same start/end ids in order.\n const firstId = doc.order[span.start]!;\n const lastId = doc.order[span.end - 1]!;\n const groupKey = `list:${span.ordered ? \"o\" : \"u\"}:${firstId}:${lastId}`;\n const renderItems = () => {\n for (let i = span.start; i < span.end; i++) {\n const b = doc.byId.get(doc.order[i]!)!;\n BlockView({ block: b, key: b.id });\n }\n };\n if (span.ordered) {\n ol({ class: \"ce-list\", key: groupKey }, renderItems);\n } else {\n ul({ class: \"ce-list\", key: groupKey }, renderItems);\n }\n }\n }\n void _;\n },\n}));\n",
|
|
33
|
+
"// ---------------------------------------------------------------------------\n// JSON SerializedBlock codec registry — toJSON / setDoc round-trip per\n// block kind. The createEditor serializer/deserializer walks doc.order and\n// dispatches to the registered codec by `block.type`. Plugins must register\n// a codec for any block kind they want to survive setDoc / toJSON.\n// ---------------------------------------------------------------------------\n\nimport type { Block, BlockId, BlockSpec } from \"../model/types\";\nimport type { SerializeCodec } from \"./types\";\n\nconst codecByType = new Map<string, SerializeCodec>();\n\nexport function registerSerializeCodec(type: string, codec: SerializeCodec): void {\n codecByType.set(type, codec);\n}\n\nexport function getSerializeCodec(type: string): SerializeCodec | null {\n return codecByType.get(type) ?? null;\n}\n\nexport function serializeBlock(b: Block): unknown | null {\n const c = codecByType.get(b.type);\n if (!c) return null;\n return c.serialize(b);\n}\n\nexport function deserializeBlock(type: string, s: unknown, id: BlockId): BlockSpec | null {\n const c = codecByType.get(type);\n if (!c) return null;\n return c.deserialize(s, id);\n}\n",
|
|
34
|
+
"// ---------------------------------------------------------------------------\n// Plugin registry — per-editor state for command / keymap / trigger /\n// decoration dispatch.\n//\n// Block-level codecs (runsAt, anchorCodec, htmlCodec, serializeCodec) live\n// in module-global maps in their dedicated files (./runsAt, ./anchorCodec,\n// ./htmlCodec, ./serializeCodec). Those are additive and consistent across\n// editors — registering \"table\" once means every editor that mounts a table\n// block can find the codec. The Registry instance below holds only the\n// stateful per-editor pieces: a CommandRegistry the editor's dispatch calls\n// into, a keymap the input pipeline scans, and trigger/decoration lists for\n// the M3/M4 managers.\n// ---------------------------------------------------------------------------\n\nimport { atomicCodec, registerAnchorCodec } from \"./anchorCodec\";\nimport { registerAtomic } from \"./atomic\";\nimport { registerHtmlBlockCodec } from \"./htmlCodec\";\nimport { registerRunsAt } from \"./runsAt\";\nimport { registerSerializeCodec } from \"./serializeCodec\";\nimport type {\n CommandCtx,\n CommandDef,\n DecorationDef,\n EditorPlugin,\n KeymapDef,\n TriggerDef,\n} from \"./types\";\n\nexport class Registry {\n readonly commands = new Map<string, CommandDef<unknown>>();\n readonly keymap: KeymapDef[] = [];\n readonly triggers: TriggerDef[] = [];\n readonly decorations: DecorationDef[] = [];\n readonly coalescePrefixes = new Set<string>([\"text:\"]);\n /** Set of all known block type discriminators (for fast existence checks). */\n readonly knownBlockTypes = new Set<string>();\n\n install(plugin: EditorPlugin): void {\n if (plugin.blocks) {\n for (const def of plugin.blocks) {\n this.knownBlockTypes.add(def.type);\n if (def.runsAt) registerRunsAt(def.type, def.runsAt as never);\n // Atomic blocks default to the generic atomicCodec when the plugin\n // doesn't ship its own — covers the common case where a plugin just\n // wants \"non-editable rectangle\".\n if (def.anchorCodec) {\n registerAnchorCodec(def.type, def.anchorCodec);\n } else if (def.isAtomic) {\n registerAnchorCodec(def.type, atomicCodec);\n }\n if (def.isAtomic) registerAtomic(def.type);\n if (def.htmlCodec) registerHtmlBlockCodec(def.type, def.htmlCodec);\n if (def.serializeCodec) registerSerializeCodec(def.type, def.serializeCodec);\n // Note: view registration lives in viewRegistry (./viewRegistry).\n // We import-and-call there too so the renderer can resolve by type.\n registerView(def.type, def.view as never);\n }\n }\n if (plugin.commands) {\n for (const c of plugin.commands) this.commands.set(c.t, c);\n }\n if (plugin.keymap) this.keymap.push(...plugin.keymap);\n if (plugin.triggers) this.triggers.push(...plugin.triggers);\n if (plugin.decorations) this.decorations.push(...plugin.decorations);\n if (plugin.historyCoalescePrefixes) {\n for (const p of plugin.historyCoalescePrefixes) this.coalescePrefixes.add(p);\n }\n }\n\n /**\n * Look up a command by t and run it; returns false if the command is\n * unknown OR if the command itself returned false (signaling \"did not\n * apply\"). Used by both the editor dispatch path and the keymap matcher.\n */\n runCommand(t: string, payload: unknown, ctx: CommandCtx): boolean {\n const cmd = this.commands.get(t);\n if (!cmd) return false;\n const r = cmd.run(ctx, payload);\n return r !== false;\n }\n\n /** Should the given history tag coalesce with prior matching tags? */\n shouldCoalesce(tag: string): boolean {\n for (const prefix of this.coalescePrefixes) {\n if (tag.startsWith(prefix)) return true;\n }\n return false;\n }\n}\n\n// ---------------------------------------------------------------------------\n// View registry — module-global. The DocView reconciler resolves a block's\n// view by `block.type`. Multiple editors share this map (additive).\n// ---------------------------------------------------------------------------\n\nimport type { PublicView } from \"creo\";\nimport type { Block } from \"../model/types\";\n\nconst viewByType = new Map<string, PublicView<{ block: Block; key?: string }, void>>();\n\nexport function registerView(\n type: string,\n v: PublicView<{ block: Block; key?: string }, void>,\n): void {\n viewByType.set(type, v);\n}\n\nexport function getView(\n type: string,\n): PublicView<{ block: Block; key?: string }, void> | null {\n return viewByType.get(type) ?? null;\n}\n",
|
|
35
|
+
"import { _ } from \"creo\";\nimport { div, view } from \"creo\";\nimport type { Store } from \"creo\";\nimport type { BlockId, DocState, Selection } from \"../model/types\";\nimport { findPos } from \"../model/doc\";\nimport { selectionStart } from \"../controller/selection\";\nimport { getView } from \"../plugin/registry\";\nimport { HeightIndex } from \"./heightIndex\";\n\n/**\n * VirtualDoc — windowed renderer that mounts only the blocks intersecting\n * `[scrollTop − overscan, scrollTop + viewport + overscan]`.\n *\n * - Heights are measured per block via ResizeObserver and pushed into a\n * Fenwick tree (`HeightIndex`) for O(log n) y-position lookups.\n * - Top / bottom spacer divs absorb the off-screen height so the scrollbar\n * behaves as if the whole document is rendered.\n * - The block containing the caret is ALWAYS rendered, even when off-screen.\n * Without this guarantee the caret overlay (which queries DOM) would lose\n * its anchor when the user scrolls away with a selection.\n */\n\nexport type VirtualDocProps = {\n docStore: Store<DocState>;\n selStore: Store<Selection>;\n /** Estimated default height in px for unmeasured blocks. */\n estimatedHeight?: number;\n /** Overscan factor — multiplied by viewport height for top/bottom slack. */\n overscan?: number;\n /** Optional fixed viewport height (else read from window.innerHeight). */\n viewportHeight?: number;\n};\n\nconst DEFAULT_ESTIMATED = 32;\nconst DEFAULT_OVERSCAN = 1.5;\n\nexport const VirtualDoc = view<VirtualDocProps>(({ props, use }) => {\n const doc = use(props().docStore);\n const sel = use(props().selStore);\n const scrollTop = use(0);\n const viewport = use(props().viewportHeight ?? readViewportHeight());\n\n let heightIndex = new HeightIndex(\n doc.get().order.length,\n props().estimatedHeight ?? DEFAULT_ESTIMATED,\n );\n let resizeObserver: ResizeObserver | null = null;\n // BlockId → element so the ResizeObserver can find which index changed.\n const elByBlock = new Map<BlockId, HTMLElement>();\n\n // Sync the index size to the doc whenever the doc shape changes.\n const syncIndex = () => {\n const n = doc.get().order.length;\n if (heightIndex.size !== n) heightIndex.resize(n);\n };\n\n const measureAll = () => {\n const order = doc.get().order;\n for (let i = 0; i < order.length; i++) {\n const id = order[i]!;\n const el = elByBlock.get(id);\n if (el) {\n const h = el.getBoundingClientRect().height;\n if (h > 0) heightIndex.setHeight(i, h);\n }\n }\n };\n\n // Read the current scroll position from whichever element actually scrolls\n // — a custom overflow ancestor if there is one, else the window. We re-read\n // on every scroll event rather than trusting `e.target.scrollTop` because\n // (a) window scroll fires with e.target=document and document.scrollTop=0,\n // and (b) a synthetic dispatchEvent might land with e.target=window where\n // window.scrollTop is undefined.\n const readScrollPos = (): number => {\n const root = currentRoot();\n if (root) {\n const sc = scrollAncestor(root);\n if (sc) return sc.scrollTop;\n }\n return window.scrollY ?? document.documentElement.scrollTop ?? 0;\n };\n const onScroll = (): void => {\n scrollTop.set(readScrollPos());\n };\n\n const onResize = () => {\n viewport.set(props().viewportHeight ?? readViewportHeight());\n };\n\n // scrollToIndex — used by `editor.scrollToBlock` for blocks that aren't\n // currently mounted in the windowed renderer. We compute the target Y from\n // the height index, set scrollTop on the resolved container, and the\n // existing onScroll listener picks the new viewport up on the next render.\n const scrollToIndex = (\n i: number,\n opts?: { block?: \"start\" | \"center\" | \"end\" | \"nearest\"; behavior?: ScrollBehavior },\n ): void => {\n const root = currentRoot();\n if (!root) return;\n const sc = scrollAncestor(root);\n const vh = viewport.get();\n const blockTop = heightIndex.prefix(i);\n const blockH = i + 1 <= heightIndex.size\n ? heightIndex.prefix(i + 1) - blockTop\n : 0;\n const where = opts?.block ?? \"center\";\n let targetTop = blockTop;\n if (where === \"center\") targetTop = blockTop - Math.max(0, (vh - blockH) / 2);\n else if (where === \"end\") targetTop = blockTop - Math.max(0, vh - blockH);\n if (sc) {\n sc.scrollTo({ top: Math.max(0, targetTop), behavior: opts?.behavior ?? \"auto\" });\n } else {\n // Window scroll — translate by the editor root's offset, since\n // heightIndex measures relative to the spacer (root content origin).\n const rootRect = root.getBoundingClientRect();\n const rootTopAbs = (window.scrollY ?? 0) + rootRect.top;\n window.scrollTo({\n top: Math.max(0, rootTopAbs + targetTop),\n behavior: opts?.behavior ?? \"auto\",\n });\n }\n };\n\n return {\n onMount() {\n const root = currentRoot();\n if (!root) return;\n // Expose the scroll-to-index helper so `editor.scrollToBlock` can\n // jump to virtualized off-screen blocks. Hidden field — host code\n // should always go through the editor surface.\n (root as unknown as { __creoVirtual?: unknown }).__creoVirtual = {\n scrollToIndex,\n };\n // Listen for scroll on the nearest scroll ancestor (default: window).\n const target = scrollAncestor(root) ?? window;\n target.addEventListener(\"scroll\", onScroll, { passive: true } as never);\n window.addEventListener(\"resize\", onResize);\n // ResizeObserver per block container.\n if (typeof ResizeObserver !== \"undefined\") {\n resizeObserver = new ResizeObserver((entries) => {\n for (const e of entries) {\n const id = (e.target as HTMLElement).getAttribute(\"data-block-id\");\n if (!id) continue;\n const order = doc.get().order;\n const idx = order.indexOf(id);\n if (idx < 0) continue;\n const h = e.contentRect.height;\n if (h > 0) heightIndex.setHeight(idx, h);\n }\n });\n for (const el of elByBlock.values()) resizeObserver.observe(el);\n }\n measureAll();\n },\n onUpdateAfter() {\n syncIndex();\n measureAll();\n if (resizeObserver) {\n for (const el of elByBlock.values()) resizeObserver.observe(el);\n }\n },\n render() {\n syncIndex();\n const d = doc.get();\n const total = d.order.length;\n if (total === 0) return;\n const overscan = (props().overscan ?? DEFAULT_OVERSCAN) * viewport.get();\n const top = scrollTop.get();\n const bottom = top + viewport.get();\n const fromY = Math.max(0, top - overscan);\n const toY = bottom + overscan;\n const startIdx = heightIndex.findIndexAtY(fromY);\n let endIdx = heightIndex.findIndexAtY(toY);\n if (endIdx < startIdx) endIdx = startIdx;\n // The plan calls for \"always render the selection's block\". We leave\n // that optimization for M11 — naively extending the window with a\n // potentially-far-away selection breaks the spacer math (and\n // empirically, with selection at end-of-doc, mounts every block).\n // The caret overlay simply hides while its anchor is off-screen.\n void selectionStart;\n void findPos;\n const topSpacer = heightIndex.prefix(startIdx);\n const bottomSpacer = Math.max(\n 0,\n heightIndex.total() - heightIndex.prefix(endIdx + 1),\n );\n\n div(\n {\n class: \"creo-vroot\",\n style: \"position:relative;\",\n },\n () => {\n if (topSpacer > 0) {\n div({\n class: \"creo-vspacer-top\",\n key: \"top-spacer\",\n style: `height:${topSpacer}px;`,\n });\n }\n for (let i = startIdx; i <= endIdx; i++) {\n const id = d.order[i]!;\n const block = d.byId.get(id)!;\n // Resolve the view via the plugin registry — same dispatch as\n // DocView, so plugin-registered block kinds render identically\n // when virtualized.\n const v = getView(block.type);\n if (v) v({ block, key: id });\n }\n if (bottomSpacer > 0) {\n div({\n class: \"creo-vspacer-bottom\",\n key: \"bottom-spacer\",\n style: `height:${bottomSpacer}px;`,\n });\n }\n },\n );\n // Refresh the elByBlock map from the live DOM after the render call\n // unwinds. We do this in onUpdateAfter / onMount via measureAll +\n // resize observation.\n void _;\n },\n };\n});\n\nfunction readViewportHeight(): number {\n if (typeof window === \"undefined\") return 800;\n const vv = (window as Window & { visualViewport?: VisualViewport })\n .visualViewport;\n // Use `||` (not `??`) so a 0 from either source falls through to the next —\n // some preview / headless environments report innerHeight=0 transiently,\n // which would otherwise leave the virtualizer with a zero-sized viewport\n // and only one block ever mounted.\n const h = (vv?.height || 0) || window.innerHeight || 0;\n return h > 0 ? h : 800;\n}\n\nfunction currentRoot(): HTMLElement | null {\n // The VirtualDoc is mounted inside the editor root; we don't currently\n // pass that root in, so fall back to the first one in the document. Tests\n // mount one editor at a time, real apps too.\n return document.querySelector(\"[data-creo-edit]\") as HTMLElement | null;\n}\n\nfunction scrollAncestor(el: HTMLElement): HTMLElement | null {\n let cur: HTMLElement | null = el.parentElement;\n while (cur) {\n const style = window.getComputedStyle(cur);\n if (\n /(auto|scroll|overlay)/.test(\n style.overflowY + style.overflowX + style.overflow,\n )\n ) return cur;\n cur = cur.parentElement;\n }\n return null;\n}\n",
|
|
36
|
+
"/**\n * HeightIndex — a Fenwick (binary indexed) tree over per-block heights so\n * that:\n * - prefix(i) — sum of heights[0..i) in O(log n)\n * - setHeight(i, h) — replace heights[i] with h in O(log n)\n * - findIndexAtY(y) — first i s.t. prefix(i+1) > y in O(log n)\n *\n * Combined with an `estimatedHeight` for unmeasured blocks, this gives us\n * an O(log n) viewport-window resolver for arbitrary scroll positions even\n * before every block has been measured.\n */\nexport class HeightIndex {\n #n: number;\n #estimated: number;\n /** Fenwick tree of *delta* values (measured - estimated) per index. */\n #bit: Float64Array;\n /** Whether each index has been measured. */\n #measured: Uint8Array;\n /** Last measured height per index (used to maintain the BIT). */\n #measuredHeights: Float64Array;\n\n constructor(count: number, estimatedHeight: number) {\n this.#n = count;\n this.#estimated = estimatedHeight;\n this.#bit = new Float64Array(count + 1);\n this.#measured = new Uint8Array(count);\n this.#measuredHeights = new Float64Array(count);\n }\n\n get size(): number {\n return this.#n;\n }\n\n /** Replace the height at `i` with `h`. O(log n). */\n setHeight(i: number, h: number): void {\n if (i < 0 || i >= this.#n) return;\n const prev = this.#measured[i] ? this.#measuredHeights[i]! : this.#estimated;\n if (h === prev) {\n // No-op — but still mark as measured so subsequent estimated-fallback\n // queries don't double-count.\n this.#measured[i] = 1;\n this.#measuredHeights[i] = h;\n return;\n }\n const delta = h - prev;\n this.#measured[i] = 1;\n this.#measuredHeights[i] = h;\n // Update BIT: maintain prefix sums of (h_i - estimated).\n const prevDelta = (this.#measured[i] ? prev : this.#estimated) - this.#estimated;\n void prevDelta;\n // Easier: maintain BIT of *measured-or-zero* deltas. We added \"delta\"\n // relative to old contribution.\n this.#bitAdd(i + 1, delta);\n }\n\n /** Prefix sum of heights for indices [0, i). */\n prefix(i: number): number {\n if (i <= 0) return 0;\n if (i > this.#n) i = this.#n;\n return i * this.#estimated + this.#bitQuery(i);\n }\n\n /** Total height of all blocks. */\n total(): number {\n return this.prefix(this.#n);\n }\n\n /**\n * Find the smallest index i such that prefix(i+1) > y. Returns the\n * floor index for y in [0, total()); for y >= total() returns n - 1.\n * For empty trees returns 0 (caller should also check size).\n */\n findIndexAtY(y: number): number {\n if (this.#n === 0) return 0;\n if (y <= 0) return 0;\n if (y >= this.total()) return this.#n - 1;\n // Binary search using BIT — classic Fenwick lower_bound.\n // We're looking for: smallest i with prefix(i+1) > y, equivalently\n // first i with sum(1..i) > y.\n // Adapt for our prefix-with-estimated formula by binary searching\n // directly on prefix(i).\n let lo = 0;\n let hi = this.#n;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (this.prefix(mid + 1) > y) hi = mid;\n else lo = mid + 1;\n }\n return lo;\n }\n\n /** Append `count` new blocks at the end, all unmeasured. */\n grow(count: number): void {\n if (count <= 0) return;\n this.resize(this.#n + count);\n }\n\n /**\n * Resize to exactly `count` blocks. Loses tail measurements when\n * shrinking; preserves them when growing. Always rebuilds the BIT from\n * scratch (cheap — O(n log n) and called rarely).\n */\n resize(count: number): void {\n if (count === this.#n) return;\n const keep = Math.min(count, this.#n);\n const newBit = new Float64Array(count + 1);\n const newMeasured = new Uint8Array(count);\n newMeasured.set(this.#measured.slice(0, keep));\n const newHeights = new Float64Array(count);\n newHeights.set(this.#measuredHeights.slice(0, keep));\n for (let i = 0; i < keep; i++) {\n if (newMeasured[i]) {\n const delta = newHeights[i]! - this.#estimated;\n if (delta !== 0) {\n let idx = i + 1;\n while (idx <= count) {\n newBit[idx] = (newBit[idx] ?? 0) + delta;\n idx += idx & -idx;\n }\n }\n }\n }\n this.#n = count;\n this.#bit = newBit;\n this.#measured = newMeasured;\n this.#measuredHeights = newHeights;\n }\n\n // ---- BIT internals ----\n\n #bitAdd(i: number, delta: number): void {\n while (i <= this.#n) {\n this.#bit[i] = (this.#bit[i] ?? 0) + delta;\n i += i & -i;\n }\n }\n\n #bitQuery(i: number): number {\n let s = 0;\n while (i > 0) {\n s += this.#bit[i] ?? 0;\n i -= i & -i;\n }\n return s;\n }\n}\n",
|
|
37
|
+
"// ---------------------------------------------------------------------------\n// Built-in plugins — every block kind currently shipped by the editor is\n// expressed as a plugin so the core has no per-kind switches.\n//\n// M1 keeps `table` and `columns` here alongside the text-bearing built-ins.\n// M2 will extract them into a separate first-party `cellsPlugin` module\n// (still registered by default) — the structure here is already plugin-shaped\n// so the migration is a file move.\n// ---------------------------------------------------------------------------\n\nimport { p, h1, h2, h3, h4, h5, h6, li, view } from \"creo\";\nimport type { PublicView } from \"creo\";\nimport type {\n Block,\n BlockSpec,\n HeadingBlock,\n ImageBlock,\n InlineRun,\n ListItemBlock,\n Mark,\n ParagraphBlock,\n} from \"../model/types\";\nimport { newBlockId } from \"../model/doc\";\nimport { ParagraphView } from \"../render/blocks/ParagraphView\";\nimport { HeadingView } from \"../render/blocks/HeadingView\";\nimport { ListItemView } from \"../render/blocks/ListItemView\";\nimport { CodeBlockView } from \"../render/blocks/CodeBlockView\";\nimport { ImageView } from \"../render/blocks/ImageView\";\nimport {\n codeBlockCodec,\n defaultTextCodec,\n imageCodec,\n} from \"./anchorCodec\";\nimport type { BlockDef, EditorPlugin } from \"./types\";\nimport { cellsPlugin } from \"../plugins/cells\";\n\n// ---------------------------------------------------------------------------\n// Helpers shared across built-in plugins.\n// ---------------------------------------------------------------------------\n\nconst ALLOWED_MARKS = new Set<Mark>([\"b\", \"i\", \"u\", \"s\", \"code\"]);\n\ntype SerializedRun = { text: string; marks?: string[] };\n\nfunction deserializeRun(r: SerializedRun): InlineRun {\n if (!r.marks || r.marks.length === 0) return { text: r.text };\n const marks = new Set<Mark>();\n for (const m of r.marks) if (ALLOWED_MARKS.has(m as Mark)) marks.add(m as Mark);\n return marks.size === 0 ? { text: r.text } : { text: r.text, marks };\n}\n\nfunction serializeRun(r: InlineRun): SerializedRun {\n if (!r.marks || r.marks.size === 0) return { text: r.text };\n return { text: r.text, marks: [...r.marks] };\n}\n\n// ---------------------------------------------------------------------------\n// HTML inline collection — shared by every text-bearing parser.\n// ---------------------------------------------------------------------------\n\nconst MARK_TAGS: Record<string, Mark> = {\n b: \"b\",\n strong: \"b\",\n i: \"i\",\n em: \"i\",\n u: \"u\",\n s: \"s\",\n strike: \"s\",\n del: \"s\",\n code: \"code\",\n};\n\nfunction runsFor(node: Node, marks: Mark[]): InlineRun[] {\n if (node.nodeType === 3) {\n const t = (node as Text).data;\n if (t.length === 0) return [];\n return [\n {\n text: t,\n ...(marks.length ? { marks: new Set(marks) } : {}),\n },\n ];\n }\n if (node.nodeType !== 1) return [];\n const el = node as HTMLElement;\n const tag = el.tagName.toLowerCase();\n if (tag === \"br\") {\n return [{ text: \"\\n\", ...(marks.length ? { marks: new Set(marks) } : {}) }];\n }\n const additional = MARK_TAGS[tag];\n const nextMarks = additional ? [...marks, additional] : marks;\n const out: InlineRun[] = [];\n for (const c of Array.from(el.childNodes)) out.push(...runsFor(c, nextMarks));\n return out;\n}\n\nfunction collectRuns(el: HTMLElement, marks: Mark[]): InlineRun[] {\n const out: InlineRun[] = [];\n for (const c of Array.from(el.childNodes)) out.push(...runsFor(c, marks));\n return out.filter((r) => r.text.length > 0);\n}\n\n// ---------------------------------------------------------------------------\n// HTML serialization helpers.\n// ---------------------------------------------------------------------------\n\nconst MARK_TAGS_SER: Record<Mark, string> = {\n b: \"strong\",\n i: \"em\",\n u: \"u\",\n s: \"s\",\n code: \"code\",\n};\n\nconst MARK_ORDER: Mark[] = [\"code\", \"b\", \"i\", \"u\", \"s\"];\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\");\n}\n\nfunction runsToHtml(runs: InlineRun[]): string {\n let out = \"\";\n for (const r of runs) {\n let inner = escapeHtml(r.text);\n if (r.marks && r.marks.size) {\n for (const m of MARK_ORDER) {\n if (!r.marks.has(m)) continue;\n const tag = MARK_TAGS_SER[m];\n inner = `<${tag}>${inner}</${tag}>`;\n }\n }\n out += inner;\n }\n return out;\n}\n\nfunction numAttr(el: HTMLElement, name: string): number | undefined {\n const v = el.getAttribute(name);\n if (v == null) return undefined;\n const n = Number(v);\n return Number.isFinite(n) ? n : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Paragraph\n// ---------------------------------------------------------------------------\n\nconst paragraphDef: BlockDef<ParagraphBlock> = {\n type: \"p\",\n view: ParagraphView as PublicView<{ block: ParagraphBlock; key?: string }, void>,\n isTextBearing: true,\n anchorCodec: defaultTextCodec,\n htmlCodec: {\n matchHTML: [\"p\"],\n parseHTML(el, ctx) {\n const runs = collectRuns(el, ctx.marks);\n return { id: newBlockId(), type: \"p\", runs };\n },\n serializeHTML(b) {\n return `<p>${runsToHtml((b as ParagraphBlock).runs)}</p>`;\n },\n },\n serializeCodec: {\n serialize(b) {\n const pb = b as ParagraphBlock;\n return { id: pb.id, type: \"p\", runs: pb.runs.map(serializeRun) };\n },\n deserialize(s, id) {\n const sb = s as { runs: SerializedRun[] };\n return { id, type: \"p\", runs: sb.runs.map(deserializeRun) } as BlockSpec;\n },\n },\n};\n\n// ---------------------------------------------------------------------------\n// Headings — one BlockDef per level (h1..h6) sharing the HeadingView.\n// ---------------------------------------------------------------------------\n\nfunction headingDef(level: 1 | 2 | 3 | 4 | 5 | 6): BlockDef<HeadingBlock> {\n const tag = `h${level}` as HeadingBlock[\"type\"];\n return {\n type: tag,\n view: HeadingView as PublicView<{ block: HeadingBlock; key?: string }, void>,\n isTextBearing: true,\n anchorCodec: defaultTextCodec,\n htmlCodec: {\n matchHTML: [tag],\n parseHTML(el, ctx) {\n const runs = collectRuns(el, ctx.marks);\n return { id: newBlockId(), type: tag, runs };\n },\n serializeHTML(b) {\n const hb = b as HeadingBlock;\n return `<${hb.type}>${runsToHtml(hb.runs)}</${hb.type}>`;\n },\n },\n serializeCodec: {\n serialize(b) {\n const hb = b as HeadingBlock;\n return { id: hb.id, type: hb.type, runs: hb.runs.map(serializeRun) };\n },\n deserialize(s, id) {\n const sb = s as { type: HeadingBlock[\"type\"]; runs: SerializedRun[] };\n return { id, type: sb.type, runs: sb.runs.map(deserializeRun) } as BlockSpec;\n },\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// List item — note: <ul>/<ol> grouping in render and HTML happens above the\n// per-block layer (DocView's planSpans + serializer's listOpen tracker).\n// The block itself only knows about its `ordered`/`depth` fields.\n// ---------------------------------------------------------------------------\n\nconst listItemDef: BlockDef<ListItemBlock> = {\n type: \"li\",\n view: ListItemView as PublicView<{ block: ListItemBlock; key?: string }, void>,\n isTextBearing: true,\n anchorCodec: defaultTextCodec,\n htmlCodec: {\n // <li> parsing is tag-driven through the <ul>/<ol> walker in htmlParser\n // (depth needs ancestor context). We register `li` here so an orphan\n // <li> outside a list still produces a paragraph fallback below.\n matchHTML: [\"li\"],\n parseHTML(el, ctx) {\n const runs = collectRuns(el, ctx.marks);\n return { id: newBlockId(), type: \"p\", runs } as BlockSpec;\n },\n serializeHTML(b) {\n const lb = b as ListItemBlock;\n return `<li data-depth=\"${lb.depth}\">${runsToHtml(lb.runs)}</li>`;\n },\n },\n serializeCodec: {\n serialize(b) {\n const lb = b as ListItemBlock;\n return {\n id: lb.id,\n type: \"li\",\n ordered: lb.ordered,\n depth: lb.depth,\n runs: lb.runs.map(serializeRun),\n };\n },\n deserialize(s, id) {\n const sb = s as {\n ordered: boolean;\n depth?: 0 | 1 | 2 | 3;\n runs: SerializedRun[];\n };\n return {\n id,\n type: \"li\",\n ordered: sb.ordered,\n depth: sb.depth ?? 0,\n runs: sb.runs.map(deserializeRun),\n } as BlockSpec;\n },\n },\n};\n\n// ---------------------------------------------------------------------------\n// Code block\n// ---------------------------------------------------------------------------\n\nimport type { CodeBlock } from \"../model/types\";\n\nconst codeBlockDef: BlockDef<CodeBlock> = {\n type: \"code\",\n view: CodeBlockView as PublicView<{ block: CodeBlock; key?: string }, void>,\n isTextBearing: true,\n anchorCodec: codeBlockCodec,\n htmlCodec: {\n matchHTML: [\"pre\"],\n parseHTML(el) {\n // <pre> typically wraps a <code> with `language-foo`.\n const codeEl = el.querySelector(\"code\");\n const text = (codeEl ?? el).textContent ?? \"\";\n const langMatch = codeEl?.className.match(/language-(\\S+)/);\n return {\n id: newBlockId(),\n type: \"code\",\n runs: text ? [{ text }] : [],\n ...(langMatch ? { lang: langMatch[1] } : {}),\n } as BlockSpec;\n },\n serializeHTML(b) {\n const cb = b as CodeBlock;\n const langCls = cb.lang\n ? ` class=\"language-${escapeHtml(cb.lang)}\"`\n : \"\";\n return `<pre><code${langCls}>${runsToHtml(cb.runs)}</code></pre>`;\n },\n },\n serializeCodec: {\n serialize(b) {\n const cb = b as CodeBlock;\n return {\n id: cb.id,\n type: \"code\",\n runs: cb.runs.map(serializeRun),\n ...(cb.lang ? { lang: cb.lang } : {}),\n };\n },\n deserialize(s, id) {\n const sb = s as { runs: SerializedRun[]; lang?: string };\n return {\n id,\n type: \"code\",\n runs: sb.runs.map(deserializeRun),\n ...(sb.lang ? { lang: sb.lang } : {}),\n } as BlockSpec;\n },\n },\n};\n\n// ---------------------------------------------------------------------------\n// Image\n// ---------------------------------------------------------------------------\n\nconst imageDef: BlockDef<ImageBlock> = {\n type: \"img\",\n view: ImageView as PublicView<{ block: ImageBlock; key?: string }, void>,\n isTextBearing: false,\n isAtomic: true,\n anchorCodec: imageCodec,\n htmlCodec: {\n matchHTML: [\"img\"],\n parseHTML(el) {\n const src = el.getAttribute(\"src\") ?? \"\";\n if (!src) return null;\n const alt = el.getAttribute(\"alt\") ?? undefined;\n const w = numAttr(el, \"width\");\n const h = numAttr(el, \"height\");\n return {\n id: newBlockId(),\n type: \"img\",\n src,\n alt,\n width: w,\n height: h,\n } as BlockSpec;\n },\n serializeHTML(b) {\n const ib = b as ImageBlock;\n const attrs: string[] = [`src=\"${escapeHtml(ib.src)}\"`];\n if (ib.alt) attrs.push(`alt=\"${escapeHtml(ib.alt)}\"`);\n if (ib.width) attrs.push(`width=\"${ib.width}\"`);\n if (ib.height) attrs.push(`height=\"${ib.height}\"`);\n return `<img ${attrs.join(\" \")}/>`;\n },\n },\n serializeCodec: {\n serialize(b) {\n const ib = b as ImageBlock;\n return {\n id: ib.id,\n type: \"img\",\n src: ib.src,\n alt: ib.alt,\n width: ib.width,\n height: ib.height,\n };\n },\n deserialize(s, id) {\n const sb = s as {\n src: string;\n alt?: string;\n width?: number;\n height?: number;\n };\n return {\n id,\n type: \"img\",\n src: sb.src,\n alt: sb.alt,\n width: sb.width,\n height: sb.height,\n } as BlockSpec;\n },\n },\n};\n\n// ---------------------------------------------------------------------------\n// Plugin assembly\n//\n// Built-ins are split into per-kind plugins so users can opt out granularly\n// (e.g. drop `imagePlugin` to disable images). `defaultPlugins` exports them\n// all as a flat array in the order createEditor registers by default. The\n// `cells` plugin (table + columns) is imported from src/plugins/cells.\n// ---------------------------------------------------------------------------\n\nexport const paragraphPlugin: EditorPlugin = {\n name: \"paragraph\",\n blocks: [paragraphDef as BlockDef<Block>],\n};\n\nexport const headingPlugin: EditorPlugin = {\n name: \"heading\",\n blocks: [\n headingDef(1) as BlockDef<Block>,\n headingDef(2) as BlockDef<Block>,\n headingDef(3) as BlockDef<Block>,\n headingDef(4) as BlockDef<Block>,\n headingDef(5) as BlockDef<Block>,\n headingDef(6) as BlockDef<Block>,\n ],\n};\n\nexport const listPlugin: EditorPlugin = {\n name: \"list\",\n blocks: [listItemDef as BlockDef<Block>],\n};\n\nexport const codeBlockPlugin: EditorPlugin = {\n name: \"code-block\",\n blocks: [codeBlockDef as BlockDef<Block>],\n};\n\nexport const imagePlugin: EditorPlugin = {\n name: \"image\",\n blocks: [imageDef as BlockDef<Block>],\n};\n\nexport { cellsPlugin };\n\n/** All built-in plugins, in registration order. */\nexport const defaultPlugins: EditorPlugin[] = [\n paragraphPlugin,\n headingPlugin,\n listPlugin,\n codeBlockPlugin,\n imagePlugin,\n cellsPlugin,\n];\n\n// Suppress unused-import warnings for creo-element helpers that text-bearing\n// blocks would have used had we inlined their views here.\nvoid p;\nvoid h1;\nvoid h2;\nvoid h3;\nvoid h4;\nvoid h5;\nvoid h6;\nvoid li;\nvoid view;\n",
|
|
38
|
+
"import { p, view } from \"creo\";\nimport type { ParagraphBlock } from \"../../model/types\";\nimport { InlineRunsView } from \"../InlineRunsView\";\n\nexport const ParagraphView = view<{ block: ParagraphBlock }>(({ props }) => ({\n shouldUpdate(next) {\n return next.block !== props().block;\n },\n render() {\n const b = props().block;\n p({ \"data-block-id\": b.id, \"data-block-kind\": \"p\", class: \"ce-block ce-p\" }, () => {\n InlineRunsView({ runs: b.runs });\n });\n },\n}));\n",
|
|
39
|
+
"import { _ } from \"creo\";\nimport { code, em, s, span, strong, text, u, view } from \"creo\";\nimport type { InlineRun, Mark } from \"../model/types\";\n\n/**\n * Render a sequence of inline runs as keyed spans.\n *\n * Each run becomes one DOM span with `data-run-index` for caret math, then the\n * spans are wrapped from inside-out by their marks (stable, deterministic\n * order: code → b → i → u → s). Wrapping order is fixed so toggling marks\n * doesn't shuffle the DOM tree.\n *\n * Empty runs are skipped — but if all runs are empty / list is empty, we emit\n * a single zero-width-space span so the block keeps a measurable line box.\n */\n\nconst MARK_ORDER: Mark[] = [\"code\", \"b\", \"i\", \"u\", \"s\"];\n\nconst ZWSP = \"\";\n\nconst RunView = view<{ run: InlineRun; index: number; empty?: boolean }>(({ props }) => ({\n shouldUpdate(next) {\n const cur = props();\n return (\n next.run !== cur.run ||\n next.index !== cur.index ||\n next.empty !== cur.empty\n );\n },\n render() {\n const { run, index, empty } = props();\n const t = run.text.length === 0 ? ZWSP : run.text;\n // `data-empty` lets host CSS show a placeholder (\"+ Write…\") on empty\n // paragraphs without the framework knowing about it. The flag is\n // only on the synthetic placeholder run, never on real (even empty\n // textually) runs the model stores.\n const sentinelAttrs = empty ? { \"data-empty\": \"true\" } : {};\n let inner = () => {\n span({ \"data-run-index\": String(index), ...sentinelAttrs }, t);\n };\n if (run.marks && run.marks.size) {\n for (const m of MARK_ORDER) {\n if (!run.marks.has(m)) continue;\n const child = inner;\n switch (m) {\n case \"code\":\n inner = () => {\n code(_, child);\n };\n break;\n case \"b\":\n inner = () => {\n strong(_, child);\n };\n break;\n case \"i\":\n inner = () => {\n em(_, child);\n };\n break;\n case \"u\":\n inner = () => {\n u(_, child);\n };\n break;\n case \"s\":\n inner = () => {\n s(_, child);\n };\n break;\n }\n }\n }\n inner();\n void text; // keep `text` import — used below for empty-run pathway in tests\n },\n}));\n\n// Stable singleton placeholder run for empty-runs blocks. Reusing the same\n// reference means RunView's identity-based shouldUpdate skips re-renders\n// when the block stays empty. RunView renders the text content via its\n// `text` field, so a single zero-width-space gives the line a measurable\n// box without leaking any visible glyph.\nconst EMPTY_PLACEHOLDER_RUN: InlineRun = { text: ZWSP };\n\nexport const InlineRunsView = view<{ runs: InlineRun[] }>(({ props }) => ({\n shouldUpdate(next) {\n return next.runs !== props().runs;\n },\n render() {\n const runs = props().runs;\n // Always render via RunView so the children-shape stays stable across\n // empty <-> non-empty transitions. An earlier version branched into a\n // raw <span> placeholder for empty runs; that flipped the children\n // type (primitive <-> composite) and the reconciler ended up keeping\n // the placeholder span around forever instead of swapping it for the\n // RunView with the new text.\n if (runs.length === 0) {\n RunView({ run: EMPTY_PLACEHOLDER_RUN, index: 0, empty: true, key: 0 });\n return;\n }\n for (let i = 0; i < runs.length; i++) {\n RunView({ run: runs[i]!, index: i, key: i });\n }\n },\n}));\n",
|
|
40
|
+
"import { h1, h2, h3, h4, h5, h6, view } from \"creo\";\nimport type { HeadingBlock } from \"../../model/types\";\nimport { InlineRunsView } from \"../InlineRunsView\";\n\nconst TAG = { h1, h2, h3, h4, h5, h6 } as const;\n\nexport const HeadingView = view<{ block: HeadingBlock }>(({ props }) => ({\n shouldUpdate(next) {\n return next.block !== props().block;\n },\n render() {\n const b = props().block;\n const tag = TAG[b.type];\n tag(\n { \"data-block-id\": b.id, \"data-block-kind\": b.type, class: `ce-block ce-${b.type}` },\n () => {\n InlineRunsView({ runs: b.runs });\n },\n );\n },\n}));\n",
|
|
41
|
+
"import { li, view } from \"creo\";\nimport type { ListItemBlock } from \"../../model/types\";\nimport { InlineRunsView } from \"../InlineRunsView\";\n\nexport const ListItemView = view<{ block: ListItemBlock }>(({ props }) => ({\n shouldUpdate(next) {\n return next.block !== props().block;\n },\n render() {\n const b = props().block;\n li(\n {\n \"data-block-id\": b.id,\n \"data-block-kind\": \"li\",\n class: `ce-block ce-li ce-li-d${b.depth}`,\n \"data-depth\": String(b.depth),\n },\n () => {\n InlineRunsView({ runs: b.runs });\n },\n );\n },\n}));\n",
|
|
42
|
+
"import { div, pre, view, _ } from \"creo\";\nimport type { CodeBlock, InlineRun } from \"../../model/types\";\nimport { InlineRunsView } from \"../InlineRunsView\";\n\n// Split a code block's flat run list into one InlineRun[] per line. Runs\n// that contain `\\n` are split into per-line pieces preserving their marks;\n// empty lines are rendered as empty arrays (which InlineRunsView turns\n// into a ZWSP placeholder so the line div has measurable height).\n//\n// The caret model treats `\\n` as a real character at the END of every\n// non-last line — this matches what `runs[].text` stores. measure.ts'\n// code-block walker re-derives line lengths from this same shape.\nfunction splitRunsByNewline(runs: InlineRun[]): InlineRun[][] {\n const lines: InlineRun[][] = [[]];\n for (const r of runs) {\n const parts = r.text.split(\"\\n\");\n for (let i = 0; i < parts.length; i++) {\n const text = parts[i]!;\n if (text.length > 0) {\n const last = lines[lines.length - 1]!;\n last.push(r.marks ? { text, marks: r.marks } : { text });\n }\n if (i < parts.length - 1) lines.push([]);\n }\n }\n return lines;\n}\n\n// A code block renders as <pre data-block-id=…> containing one\n// <div class=\"ce-code-line\"> per line of the model's runs. Per-line block\n// elements give the caret overlay measurable geometry on EVERY line\n// (including empty ones — InlineRunsView emits a ZWSP for empty runs, so\n// empty lines still have a non-zero bounding rect with the correct\n// line-height).\n//\n// Styling (monospace font, boxed look, white-space:pre on children to\n// preserve leading indent) is handled by the host stylesheet.\nexport const CodeBlockView = view<{ block: CodeBlock }>(({ props }) => ({\n shouldUpdate(next) {\n return next.block !== props().block;\n },\n render() {\n const b = props().block;\n pre(\n {\n \"data-block-id\": b.id,\n \"data-block-kind\": \"code\",\n class: \"ce-block ce-code-block\",\n ...(b.lang ? { \"data-lang\": b.lang } : {}),\n },\n () => {\n const lines = splitRunsByNewline(b.runs);\n for (let i = 0; i < lines.length; i++) {\n const lineRuns = lines[i]!;\n div({ class: \"ce-code-line\", key: i }, () => {\n InlineRunsView({ runs: lineRuns });\n });\n }\n },\n );\n void _;\n },\n}));\n",
|
|
43
|
+
"import { _ } from \"creo\";\nimport { div, img, view } from \"creo\";\nimport type { ImageBlock } from \"../../model/types\";\n\nexport const ImageView = view<{ block: ImageBlock; selected?: boolean }>(\n ({ props }) => ({\n shouldUpdate(next) {\n const cur = props();\n return next.block !== cur.block || next.selected !== cur.selected;\n },\n render() {\n const b = props().block;\n const sel = props().selected === true;\n div(\n {\n \"data-block-id\": b.id,\n \"data-block-kind\": \"img\",\n // Atomic to native caret — under contentEditable the browser must\n // skip OVER the img rather than placing the caret inside it.\n // contenteditable=\"false\" inside an editable root creates exactly\n // that \"non-editable island\" behaviour. Harmless when the editor\n // is not contenteditable (textarea-driven path ignores the attr).\n contenteditable: \"false\",\n class: sel ? \"ce-block ce-img ce-img-selected\" : \"ce-block ce-img\",\n // Override the editor root's `cursor: text` so hovering an image\n // shows the default arrow, not the I-beam.\n style:\n (sel\n ? \"outline:2px solid rgba(64,128,255,0.7);outline-offset:2px;\"\n : \"\") + \"cursor:default;\",\n },\n () => {\n img({\n src: b.src,\n alt: b.alt ?? \"\",\n width: b.width,\n height: b.height,\n draggable: false,\n });\n void _;\n },\n );\n },\n }),\n);\n",
|
|
44
|
+
"// ---------------------------------------------------------------------------\n// Anchor + runsAt codecs for table and columns blocks.\n//\n// Path encoding:\n// table: [row, col, charOffset]\n// columns: [colIndex, charOffset]\n//\n// The codecs walk into the cell sub-element by reading data-cell / data-col\n// attributes the views emit, then delegate visible-character math to the\n// shared offsetWithinScope / findTextPoint helpers from anchorCodec.\n// ---------------------------------------------------------------------------\n\nimport type {\n Anchor,\n Block,\n ColumnsBlock,\n InlineRun,\n TableBlock,\n} from \"../../model/types\";\nimport {\n findTextPoint,\n offsetWithinScope,\n} from \"../../plugin/anchorCodec\";\nimport type { AnchorCodec, RunsCtx } from \"../../plugin/types\";\n\n// ---------------------------------------------------------------------------\n// Table\n// ---------------------------------------------------------------------------\n\nexport function tableRunsAt(b: TableBlock, a: Anchor): RunsCtx | null {\n const r = a.path[0] ?? 0;\n const c = a.path[1] ?? 0;\n if (r < 0 || r >= b.rows || c < 0 || c >= b.cols) return null;\n const runs = b.cells[r]?.[c] ?? [];\n return {\n runs,\n setRuns: (newRuns: InlineRun[]) => {\n const cells = b.cells.map((row, rr) =>\n rr === r ? row.map((cell, cc) => (cc === c ? newRuns : cell)) : row,\n );\n return { ...b, cells } as Block;\n },\n };\n}\n\nfunction findOwningCellEl(node: Node): HTMLElement | null {\n let cur: Node | null = node;\n while (cur && cur.nodeType !== 1) cur = cur.parentNode;\n while (cur && cur.nodeType === 1) {\n const el = cur as HTMLElement;\n if (el.tagName.toLowerCase() === \"td\" && el.hasAttribute(\"data-cell\")) {\n return el;\n }\n cur = el.parentElement;\n }\n return null;\n}\n\nexport const tableAnchorCodec: AnchorCodec = {\n domToAnchor(blockEl, hit, off) {\n const blockId = blockEl.getAttribute(\"data-block-id\");\n if (!blockId) return null;\n const td = findOwningCellEl(hit);\n if (td) {\n const cellAttr = td.getAttribute(\"data-cell\");\n if (cellAttr) {\n const [rs, cs] = cellAttr.split(\":\");\n const r = Number(rs);\n const c = Number(cs);\n if (Number.isFinite(r) && Number.isFinite(c)) {\n const charOff = offsetWithinScope(td, hit, off);\n return { blockId, path: [r, c, charOff], offset: charOff };\n }\n }\n }\n return { blockId, path: [0, 0, 0], offset: 0 };\n },\n anchorToDom(blockEl, a) {\n const r = a.path[0] ?? 0;\n const c = a.path[1] ?? 0;\n const charOff = a.path[2] ?? 0;\n const tdEl = blockEl.querySelector<HTMLElement>(`td[data-cell=\"${r}:${c}\"]`);\n if (!tdEl) return null;\n return findTextPoint(tdEl, charOff);\n },\n domScope(blockEl, a) {\n const r = a.path[0] ?? 0;\n const c = a.path[1] ?? 0;\n return blockEl.querySelector<HTMLElement>(`td[data-cell=\"${r}:${c}\"]`);\n },\n};\n\n// ---------------------------------------------------------------------------\n// Columns\n// ---------------------------------------------------------------------------\n\nexport function columnsRunsAt(b: ColumnsBlock, a: Anchor): RunsCtx | null {\n const c = a.path[0] ?? 0;\n if (c < 0 || c >= b.cols) return null;\n const runs = b.cells[c] ?? [];\n return {\n runs,\n setRuns: (newRuns: InlineRun[]) => {\n const cells = b.cells.map((cell, cc) => (cc === c ? newRuns : cell));\n return { ...b, cells } as Block;\n },\n };\n}\n\nfunction findOwningColEl(node: Node): HTMLElement | null {\n let cur: Node | null = node;\n while (cur && cur.nodeType !== 1) cur = cur.parentNode;\n while (cur && cur.nodeType === 1) {\n const el = cur as HTMLElement;\n if (el.hasAttribute(\"data-col\")) return el;\n cur = el.parentElement;\n }\n return null;\n}\n\n// Per-line traversal helpers — columns render one `.ce-col-line` div per\n// visual line (mirroring code blocks). The model treats `\\n` as a real\n// char between lines, so we add 1 to the running offset between adjacent\n// line divs.\n\nfunction visibleLength(el: HTMLElement): number {\n const ZWSP = \"\";\n let n = 0;\n const walk = (node: Node): void => {\n if (node.nodeType === 3) {\n const t = (node as Text).data;\n if (t !== ZWSP) n += t.length;\n return;\n }\n for (const c of Array.from(node.childNodes)) walk(c);\n };\n walk(el);\n return n;\n}\n\nexport const columnsAnchorCodec: AnchorCodec = {\n domToAnchor(blockEl, hit, off) {\n const blockId = blockEl.getAttribute(\"data-block-id\");\n if (!blockId) return null;\n const colEl = findOwningColEl(hit);\n if (!colEl) return { blockId, path: [0, 0], offset: 0 };\n const ci = Number(colEl.getAttribute(\"data-col\"));\n if (!Number.isFinite(ci)) return { blockId, path: [0, 0], offset: 0 };\n const lines = colEl.querySelectorAll<HTMLElement>(\".ce-col-line\");\n if (lines.length === 0) {\n const charOff = offsetWithinScope(colEl, hit, off);\n return { blockId, path: [ci, charOff], offset: charOff };\n }\n let total = 0;\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n if (line === hit || line.contains(hit)) {\n const inLine = total + offsetWithinScope(line, hit, off);\n return { blockId, path: [ci, inLine], offset: inLine };\n }\n total += visibleLength(line);\n if (i < lines.length - 1) total += 1;\n }\n return { blockId, path: [ci, total], offset: total };\n },\n anchorToDom(blockEl, a) {\n const ci = a.path[0] ?? 0;\n const charOff = a.path[1] ?? 0;\n const colEl = blockEl.querySelector<HTMLElement>(`[data-col=\"${ci}\"]`);\n if (!colEl) return null;\n const lines = colEl.querySelectorAll<HTMLElement>(\".ce-col-line\");\n if (lines.length === 0) return findTextPoint(colEl, charOff);\n let remaining = charOff;\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const len = visibleLength(line);\n if (remaining <= len) return findTextPoint(line, remaining);\n remaining -= len;\n if (i < lines.length - 1) {\n if (remaining === 0) return findTextPoint(lines[i + 1]!, 0);\n remaining -= 1;\n }\n }\n const last = lines[lines.length - 1]!;\n return findTextPoint(last, visibleLength(last));\n },\n domScope(blockEl, a) {\n const ci = a.path[0] ?? 0;\n return blockEl.querySelector<HTMLElement>(`[data-col=\"${ci}\"]`);\n },\n};\n",
|
|
45
|
+
"// ---------------------------------------------------------------------------\n// HTML codecs for table + columns blocks.\n// ---------------------------------------------------------------------------\n\nimport { newBlockId } from \"../../model/doc\";\nimport type {\n Block,\n BlockSpec,\n ColumnsBlock,\n InlineRun,\n Mark,\n TableBlock,\n} from \"../../model/types\";\n\nconst MARK_TAGS_SER: Record<Mark, string> = {\n b: \"strong\",\n i: \"em\",\n u: \"u\",\n s: \"s\",\n code: \"code\",\n};\nconst MARK_ORDER: Mark[] = [\"code\", \"b\", \"i\", \"u\", \"s\"];\n\nconst MARK_TAGS: Record<string, Mark> = {\n b: \"b\",\n strong: \"b\",\n i: \"i\",\n em: \"i\",\n u: \"u\",\n s: \"s\",\n strike: \"s\",\n del: \"s\",\n code: \"code\",\n};\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\");\n}\n\nfunction runsFor(node: Node, marks: Mark[]): InlineRun[] {\n if (node.nodeType === 3) {\n const t = (node as Text).data;\n if (t.length === 0) return [];\n return [\n { text: t, ...(marks.length ? { marks: new Set(marks) } : {}) },\n ];\n }\n if (node.nodeType !== 1) return [];\n const el = node as HTMLElement;\n const tag = el.tagName.toLowerCase();\n if (tag === \"br\") {\n return [{ text: \"\\n\", ...(marks.length ? { marks: new Set(marks) } : {}) }];\n }\n const additional = MARK_TAGS[tag];\n const nextMarks = additional ? [...marks, additional] : marks;\n const out: InlineRun[] = [];\n for (const c of Array.from(el.childNodes)) out.push(...runsFor(c, nextMarks));\n return out;\n}\n\nfunction collectRuns(el: HTMLElement, marks: Mark[]): InlineRun[] {\n const out: InlineRun[] = [];\n for (const c of Array.from(el.childNodes)) out.push(...runsFor(c, marks));\n return out.filter((r) => r.text.length > 0);\n}\n\nfunction runsToHtml(runs: InlineRun[]): string {\n let out = \"\";\n for (const r of runs) {\n let inner = escapeHtml(r.text);\n if (r.marks && r.marks.size) {\n for (const m of MARK_ORDER) {\n if (!r.marks.has(m)) continue;\n const tag = MARK_TAGS_SER[m];\n inner = `<${tag}>${inner}</${tag}>`;\n }\n }\n out += inner;\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Table HTML\n// ---------------------------------------------------------------------------\n\nexport function parseTableHTML(\n el: HTMLElement,\n ctx: { marks: Mark[] },\n): BlockSpec | null {\n const rowsEls: HTMLElement[] = [];\n for (const tr of Array.from(el.querySelectorAll(\"tr\"))) {\n rowsEls.push(tr as HTMLElement);\n }\n if (rowsEls.length === 0) return null;\n const cells: InlineRun[][][] = [];\n let cols = 0;\n for (const tr of rowsEls) {\n const row: InlineRun[][] = [];\n for (const td of Array.from(tr.children)) {\n const tag = td.tagName.toLowerCase();\n if (tag !== \"td\" && tag !== \"th\") continue;\n row.push(collectRuns(td as HTMLElement, ctx.marks));\n }\n cells.push(row);\n if (row.length > cols) cols = row.length;\n }\n for (const row of cells) while (row.length < cols) row.push([]);\n return {\n id: newBlockId(),\n type: \"table\",\n rows: cells.length,\n cols,\n cells,\n } as BlockSpec;\n}\n\nexport function serializeTableHTML(b: Block): string {\n const t = b as TableBlock;\n let s = \"<table><tbody>\";\n for (let r = 0; r < t.rows; r++) {\n s += \"<tr>\";\n for (let c = 0; c < t.cols; c++) {\n s += `<td>${runsToHtml(t.cells[r]?.[c] ?? [])}</td>`;\n }\n s += \"</tr>\";\n }\n s += \"</tbody></table>\";\n return s;\n}\n\n// ---------------------------------------------------------------------------\n// Columns HTML\n// ---------------------------------------------------------------------------\n\nexport function serializeColumnsHTML(b: Block): string {\n const cb = b as ColumnsBlock;\n let s = `<div data-creo-columns=\"${cb.cols}\" style=\"display:grid;grid-template-columns:repeat(${cb.cols},1fr);gap:16px;\">`;\n for (let c = 0; c < cb.cols; c++) {\n s += `<div data-col=\"${c}\">${runsToHtml(cb.cells[c] ?? [])}</div>`;\n }\n s += \"</div>\";\n return s;\n}\n",
|
|
46
|
+
"// ---------------------------------------------------------------------------\n// Cell-block views — table + columns. Moved from src/render/blocks/ as part\n// of the cellsPlugin extraction. The DOM shape (data-cell=\"r:c\", data-col,\n// data-block-kind) is unchanged so the anchor codec walks find the right\n// scopes.\n// ---------------------------------------------------------------------------\n\nimport { div, table, tbody, td, tr, view } from \"creo\";\nimport type { ColumnsBlock, InlineRun, TableBlock } from \"../../model/types\";\nimport { InlineRunsView } from \"../../render/InlineRunsView\";\n\n/**\n * Split a column's flat run list into one InlineRun[] per visual line. `\\n`\n * characters in run text become line boundaries; runs spanning a `\\n` are\n * split into per-line pieces preserving their marks. Empty lines are\n * rendered as empty arrays — InlineRunsView emits a ZWSP placeholder so the\n * line div retains measurable height (otherwise a trailing `\\n` collapses\n * to zero-height in pre-wrap mode and the caret has nowhere to land).\n *\n * Mirrors `splitRunsByNewline` in CodeBlockView; the codec walks\n * `.ce-col-line` divs the same way `codeBlockCodec` walks `.ce-code-line`.\n */\nfunction splitRunsByNewline(runs: InlineRun[]): InlineRun[][] {\n const lines: InlineRun[][] = [[]];\n for (const r of runs) {\n const parts = r.text.split(\"\\n\");\n for (let i = 0; i < parts.length; i++) {\n const text = parts[i]!;\n if (text.length > 0) {\n const last = lines[lines.length - 1]!;\n last.push(r.marks ? { text, marks: r.marks } : { text });\n }\n if (i < parts.length - 1) lines.push([]);\n }\n }\n return lines;\n}\n\n/**\n * Render a TableBlock as <table><tbody> with keyed rows + cells.\n *\n * NOTE: intermediate primitives (tbody, tr) get FRESH prop objects each\n * render, not the `_` no-props constant. The reconciler skips descent\n * when an intermediate primitive's props are reference-equal to the\n * previous render — using `_` everywhere causes that shortcut to fire\n * and changes inside cells (e.g. typed text) never make it to the DOM.\n */\nexport const TableViewPlugin = view<{ block: TableBlock }>(({ props }) => ({\n shouldUpdate(next) {\n return next.block !== props().block;\n },\n render() {\n const b = props().block;\n table(\n {\n \"data-block-id\": b.id,\n \"data-block-kind\": \"table\",\n class: \"ce-block ce-table\",\n },\n () => {\n tbody({}, () => {\n for (let r = 0; r < b.rows; r++) {\n tr({ key: `r${r}`, \"data-row\": String(r) }, () => {\n for (let c = 0; c < b.cols; c++) {\n const runs = b.cells[r]?.[c] ?? [];\n td(\n {\n key: `${r}-${c}`,\n class: \"ce-cell\",\n \"data-block-id\": b.id,\n \"data-cell\": `${r}:${c}`,\n },\n () => {\n InlineRunsView({ runs });\n },\n );\n }\n });\n }\n });\n },\n );\n },\n}));\n\n/**\n * Render a ColumnsBlock as a flex row of equal-width column divs. Each\n * column carries `data-block-id` (so caret-overlay queries find the owner)\n * AND `data-col=\"<index>\"` so pointToAnchor can reconstruct the column.\n */\nexport const ColumnsViewPlugin = view<{ block: ColumnsBlock }>(({ props }) => ({\n shouldUpdate(next) {\n return next.block !== props().block;\n },\n render() {\n const b = props().block;\n div(\n {\n \"data-block-id\": b.id,\n \"data-block-kind\": \"columns\",\n class: \"ce-block ce-columns\",\n style: `display:grid;grid-template-columns:repeat(${b.cols},1fr);gap:16px;`,\n },\n () => {\n for (let c = 0; c < b.cols; c++) {\n const runs = b.cells[c] ?? [];\n div(\n {\n key: `col-${c}`,\n class: \"ce-col\",\n \"data-block-id\": b.id,\n \"data-col\": String(c),\n style: \"min-width:0;\",\n },\n () => {\n const lines = splitRunsByNewline(runs);\n for (let i = 0; i < lines.length; i++) {\n const lineRuns = lines[i]!;\n div({ class: \"ce-col-line\", key: i }, () => {\n InlineRunsView({ runs: lineRuns });\n });\n }\n },\n );\n }\n },\n );\n },\n}));\n",
|
|
47
|
+
"// ---------------------------------------------------------------------------\n// Table / columns commands. Logic moved from src/commands/tableCommands.ts;\n// commands are exposed as CommandDef entries so they're dispatched through\n// the plugin registry by namespaced t-strings (\"table.insertRow\", etc.).\n//\n// Command return values: `boolean` indicates whether the command applied\n// (false = no-op). The plugin keymap dispatcher in nativeInput uses this to\n// decide whether to preventDefault — arrow keys at cell edges that don't\n// jump should fall through to the browser for within-cell motion.\n// ---------------------------------------------------------------------------\n\nimport { getBlock, updateBlock } from \"../../model/doc\";\nimport { anchorOffset, caret } from \"../../controller/selection\";\nimport type {\n Block,\n ColumnsBlock,\n DocState,\n InlineRun,\n Selection,\n TableBlock,\n} from \"../../model/types\";\nimport type { CommandCtx, CommandDef } from \"../../plugin/types\";\n\nfunction currentTable(\n doc: DocState,\n sel: Selection,\n): { block: TableBlock; row: number; col: number; off: number } | null {\n const start = sel.kind === \"caret\" ? sel.at : sel.anchor;\n const block = getBlock(doc, start.blockId);\n if (!block || block.type !== \"table\") return null;\n return {\n block: block as TableBlock,\n row: start.path[0] ?? 0,\n col: start.path[1] ?? 0,\n off: anchorOffset(start),\n };\n}\n\n/**\n * Resolve the table to operate on. If `blockId` is given, look it up directly\n * and default the row/col to 0 (used by hover toolbars that target a specific\n * table without moving the caret). Otherwise fall back to whichever table\n * contains the current selection.\n */\nfunction resolveTable(\n doc: DocState,\n sel: Selection,\n blockId?: string,\n): { block: TableBlock; row: number; col: number } | null {\n if (blockId) {\n const b = getBlock(doc, blockId);\n if (!b || b.type !== \"table\") return null;\n return { block: b as TableBlock, row: 0, col: 0 };\n }\n const c = currentTable(doc, sel);\n if (!c) return null;\n return { block: c.block, row: c.row, col: c.col };\n}\n\nfunction emptyRow(cols: number): InlineRun[][] {\n const row: InlineRun[][] = [];\n for (let i = 0; i < cols; i++) row.push([]);\n return row;\n}\n\nexport function isInTable(doc: DocState, sel: Selection): boolean {\n return currentTable(doc, sel) !== null;\n}\n\nfunction currentColumns(\n doc: DocState,\n sel: Selection,\n): { block: ColumnsBlock; col: number; off: number } | null {\n const start = sel.kind === \"caret\" ? sel.at : sel.anchor;\n const block = getBlock(doc, start.blockId);\n if (!block || block.type !== \"columns\") return null;\n return {\n block: block as ColumnsBlock,\n col: start.path[0] ?? 0,\n off: anchorOffset(start),\n };\n}\n\nexport function isInColumns(doc: DocState, sel: Selection): boolean {\n return currentColumns(doc, sel) !== null;\n}\n\nfunction colTextLength(b: ColumnsBlock, col: number): number {\n const runs = b.cells[col] ?? [];\n return runs.reduce((n, r) => n + r.text.length, 0);\n}\n\nfunction columnsNext(ctx: CommandCtx): boolean {\n const c = currentColumns(ctx.docStore.get(), ctx.selStore.get());\n if (!c) return false;\n const nc = c.col + 1;\n if (nc >= c.block.cols) return false;\n ctx.selStore.set(caret({ blockId: c.block.id, path: [nc, 0], offset: 0 }));\n return true;\n}\n\nfunction columnsPrev(ctx: CommandCtx): boolean {\n const c = currentColumns(ctx.docStore.get(), ctx.selStore.get());\n if (!c) return false;\n const nc = c.col - 1;\n if (nc < 0) return false;\n const off = colTextLength(c.block, nc);\n ctx.selStore.set(caret({ blockId: c.block.id, path: [nc, off], offset: off }));\n return true;\n}\n\nfunction columnsArrowLeft(ctx: CommandCtx): boolean {\n const c = currentColumns(ctx.docStore.get(), ctx.selStore.get());\n if (!c) return false;\n if (c.off !== 0) return false;\n const nc = c.col - 1;\n if (nc < 0) return false;\n const off = colTextLength(c.block, nc);\n ctx.selStore.set(caret({ blockId: c.block.id, path: [nc, off], offset: off }));\n return true;\n}\n\nfunction columnsArrowRight(ctx: CommandCtx): boolean {\n const c = currentColumns(ctx.docStore.get(), ctx.selStore.get());\n if (!c) return false;\n const len = colTextLength(c.block, c.col);\n if (c.off !== len) return false;\n const nc = c.col + 1;\n if (nc >= c.block.cols) return false;\n ctx.selStore.set(caret({ blockId: c.block.id, path: [nc, 0], offset: 0 }));\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// Columns insert / remove\n// ---------------------------------------------------------------------------\n\nfunction findColumnsBlock(\n doc: DocState,\n sel: Selection,\n blockId?: string,\n): { block: ColumnsBlock; col: number } | null {\n if (blockId) {\n const b = getBlock(doc, blockId);\n if (!b || b.type !== \"columns\") return null;\n return { block: b as ColumnsBlock, col: 0 };\n }\n const inSel = currentColumns(doc, sel);\n if (!inSel) return null;\n return { block: inSel.block, col: inSel.col };\n}\n\ntype ColumnsTarget = { blockId?: string; where?: \"before\" | \"after\" | \"end\" };\n\nfunction columnsInsertCol(ctx: CommandCtx, p: ColumnsTarget): boolean {\n const doc = ctx.docStore.get();\n const sel = ctx.selStore.get();\n const c = findColumnsBlock(doc, sel, p.blockId);\n if (!c) return false;\n const { block } = c;\n const where = p.where ?? \"after\";\n const insertAt =\n where === \"end\"\n ? block.cols\n : where === \"before\"\n ? c.col\n : c.col + 1;\n const cells = [\n ...block.cells.slice(0, insertAt),\n [] as InlineRun[],\n ...block.cells.slice(insertAt),\n ];\n const next: ColumnsBlock = { ...block, cols: block.cols + 1, cells };\n ctx.docStore.set(updateBlock(doc, next as Block));\n ctx.selStore.set(caret({ blockId: block.id, path: [insertAt, 0], offset: 0 }));\n return true;\n}\n\nfunction columnsRemoveCol(\n ctx: CommandCtx,\n p: { blockId?: string; col?: number },\n): boolean {\n const doc = ctx.docStore.get();\n const sel = ctx.selStore.get();\n const c = findColumnsBlock(doc, sel, p.blockId);\n if (!c) return false;\n const { block } = c;\n const target = p.col ?? c.col;\n if (target < 0 || target >= block.cols) return false;\n\n if (block.cols <= 1) return false;\n\n const cells = block.cells.filter((_, i) => i !== target);\n const next: ColumnsBlock = { ...block, cols: block.cols - 1, cells };\n ctx.docStore.set(updateBlock(doc, next as Block));\n const newCol = Math.min(target, next.cols - 1);\n ctx.selStore.set(caret({ blockId: block.id, path: [newCol, 0], offset: 0 }));\n return true;\n}\n\nfunction cellTextLength(b: TableBlock, row: number, col: number): number {\n const runs = b.cells[row]?.[col] ?? [];\n return runs.reduce((n, r) => n + r.text.length, 0);\n}\n\n// ---------------------------------------------------------------------------\n// Insert / remove\n// ---------------------------------------------------------------------------\n\ntype TableTarget = { blockId?: string; row?: number; col?: number };\n\nfunction insertRow(\n ctx: CommandCtx,\n where: \"above\" | \"below\" | \"end\",\n blockId?: string,\n rowHint?: number,\n moveTo = false,\n): boolean {\n const doc = ctx.docStore.get();\n const t = resolveTable(doc, ctx.selStore.get(), blockId);\n if (!t) return false;\n const { block } = t;\n const row = rowHint ?? t.row;\n const insertAt =\n where === \"end\" ? block.rows : where === \"above\" ? row : row + 1;\n const cells = [\n ...block.cells.slice(0, insertAt),\n emptyRow(block.cols),\n ...block.cells.slice(insertAt),\n ];\n const next: TableBlock = { ...block, rows: block.rows + 1, cells };\n ctx.docStore.set(updateBlock(doc, next as Block));\n if (moveTo) {\n ctx.selStore.set(caret({ blockId: block.id, path: [insertAt, 0, 0], offset: 0 }));\n }\n return true;\n}\n\nfunction insertCol(\n ctx: CommandCtx,\n where: \"before\" | \"after\" | \"end\",\n blockId?: string,\n colHint?: number,\n): boolean {\n const doc = ctx.docStore.get();\n const t = resolveTable(doc, ctx.selStore.get(), blockId);\n if (!t) return false;\n const { block } = t;\n const col = colHint ?? t.col;\n const insertAt =\n where === \"end\" ? block.cols : where === \"before\" ? col : col + 1;\n const cells = block.cells.map((row) => [\n ...row.slice(0, insertAt),\n [] as InlineRun[],\n ...row.slice(insertAt),\n ]);\n const next: TableBlock = { ...block, cols: block.cols + 1, cells };\n ctx.docStore.set(updateBlock(doc, next as Block));\n return true;\n}\n\nfunction removeRow(ctx: CommandCtx, blockId?: string, rowHint?: number): boolean {\n const doc = ctx.docStore.get();\n const t = resolveTable(doc, ctx.selStore.get(), blockId);\n if (!t) return false;\n const { block } = t;\n const row = rowHint ?? t.row;\n if (block.rows <= 1) return false;\n if (row < 0 || row >= block.rows) return false;\n const cells = block.cells.filter((_, i) => i !== row);\n const next: TableBlock = { ...block, rows: block.rows - 1, cells };\n ctx.docStore.set(updateBlock(doc, next as Block));\n const newRow = Math.min(row, next.rows - 1);\n ctx.selStore.set(caret({ blockId: block.id, path: [newRow, t.col, 0], offset: 0 }));\n return true;\n}\n\nfunction removeCol(ctx: CommandCtx, blockId?: string, colHint?: number): boolean {\n const doc = ctx.docStore.get();\n const t = resolveTable(doc, ctx.selStore.get(), blockId);\n if (!t) return false;\n const { block } = t;\n const col = colHint ?? t.col;\n if (block.cols <= 1) return false;\n if (col < 0 || col >= block.cols) return false;\n const cells = block.cells.map((row) => row.filter((_, i) => i !== col));\n const next: TableBlock = { ...block, cols: block.cols - 1, cells };\n ctx.docStore.set(updateBlock(doc, next as Block));\n const newCol = Math.min(col, next.cols - 1);\n ctx.selStore.set(caret({ blockId: block.id, path: [t.row, newCol, 0], offset: 0 }));\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// Cell navigation\n// ---------------------------------------------------------------------------\n\nfunction nextCell(ctx: CommandCtx): boolean {\n const c = currentTable(ctx.docStore.get(), ctx.selStore.get());\n if (!c) return false;\n const { block, row, col } = c;\n let nr = row;\n let nc = col + 1;\n if (nc >= block.cols) {\n nc = 0;\n nr += 1;\n }\n if (nr >= block.rows) {\n // Auto-add a new row when tabbing past the last cell.\n return insertRow(ctx, \"below\", undefined, undefined, true);\n }\n ctx.selStore.set(caret({ blockId: block.id, path: [nr, nc, 0], offset: 0 }));\n return true;\n}\n\nfunction prevCell(ctx: CommandCtx): boolean {\n const c = currentTable(ctx.docStore.get(), ctx.selStore.get());\n if (!c) return false;\n const { block, row, col } = c;\n let nr = row;\n let nc = col - 1;\n if (nc < 0) {\n nc = block.cols - 1;\n nr -= 1;\n }\n if (nr < 0) return false;\n ctx.selStore.set(caret({ blockId: block.id, path: [nr, nc, 0], offset: 0 }));\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// Arrow-key cell navigation — each returns false when the key isn't an\n// \"edge\" press (e.g. ArrowRight inside cell text); the keymap dispatcher\n// then doesn't preventDefault and the browser handles within-cell motion.\n// ---------------------------------------------------------------------------\n\nfunction arrowLeft(ctx: CommandCtx): boolean {\n const c = currentTable(ctx.docStore.get(), ctx.selStore.get());\n if (!c) return false;\n if (c.off !== 0) return false;\n const { block, row, col } = c;\n let nr = row, nc = col - 1;\n if (nc < 0) {\n nc = block.cols - 1;\n nr -= 1;\n }\n if (nr < 0) return false;\n const off = cellTextLength(block, nr, nc);\n ctx.selStore.set(caret({ blockId: block.id, path: [nr, nc, off], offset: off }));\n return true;\n}\n\nfunction arrowRight(ctx: CommandCtx): boolean {\n const c = currentTable(ctx.docStore.get(), ctx.selStore.get());\n if (!c) return false;\n const len = cellTextLength(c.block, c.row, c.col);\n if (c.off !== len) return false;\n const { block, row, col } = c;\n let nr = row, nc = col + 1;\n if (nc >= block.cols) {\n nc = 0;\n nr += 1;\n }\n if (nr >= block.rows) return false;\n ctx.selStore.set(caret({ blockId: block.id, path: [nr, nc, 0], offset: 0 }));\n return true;\n}\n\nfunction arrowUp(ctx: CommandCtx): boolean {\n const c = currentTable(ctx.docStore.get(), ctx.selStore.get());\n if (!c) return false;\n if (c.row === 0) return false;\n const nr = c.row - 1;\n const off = cellTextLength(c.block, nr, c.col);\n ctx.selStore.set(caret({ blockId: c.block.id, path: [nr, c.col, off], offset: off }));\n return true;\n}\n\nfunction arrowDown(ctx: CommandCtx): boolean {\n const c = currentTable(ctx.docStore.get(), ctx.selStore.get());\n if (!c) return false;\n if (c.row >= c.block.rows - 1) return false;\n const nr = c.row + 1;\n ctx.selStore.set(caret({ blockId: c.block.id, path: [nr, c.col, 0], offset: 0 }));\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// CommandDef export — registered by cellsPlugin.\n// ---------------------------------------------------------------------------\n\nexport const tableCommandDefs: CommandDef<unknown>[] = [\n {\n t: \"table.insertRow\",\n run: (ctx, p) => {\n // Accept either a bare \"above\" | \"below\" string (legacy callers + the\n // backcompat alias below) or a TableTarget object from controls UI.\n if (typeof p === \"string\") return insertRow(ctx, p as \"above\" | \"below\");\n const t = (p ?? {}) as TableTarget & { where?: \"above\" | \"below\" | \"end\" };\n return insertRow(ctx, t.where ?? \"below\", t.blockId, t.row);\n },\n },\n {\n t: \"table.insertCol\",\n run: (ctx, p) => {\n if (typeof p === \"string\") return insertCol(ctx, p as \"before\" | \"after\");\n const t = (p ?? {}) as TableTarget & { where?: \"before\" | \"after\" | \"end\" };\n return insertCol(ctx, t.where ?? \"after\", t.blockId, t.col);\n },\n },\n {\n t: \"table.removeRow\",\n run: (ctx, p) => {\n const t = (p ?? {}) as TableTarget;\n return removeRow(ctx, t.blockId, t.row);\n },\n },\n {\n t: \"table.removeCol\",\n run: (ctx, p) => {\n const t = (p ?? {}) as TableTarget;\n return removeCol(ctx, t.blockId, t.col);\n },\n },\n { t: \"table.nextCell\", run: (ctx) => nextCell(ctx) },\n { t: \"table.prevCell\", run: (ctx) => prevCell(ctx) },\n { t: \"table.arrowLeft\", run: (ctx) => arrowLeft(ctx) },\n { t: \"table.arrowRight\", run: (ctx) => arrowRight(ctx) },\n { t: \"table.arrowUp\", run: (ctx) => arrowUp(ctx) },\n { t: \"table.arrowDown\", run: (ctx) => arrowDown(ctx) },\n // Columns navigation — Tab moves between columns.\n { t: \"columns.next\", run: (ctx) => columnsNext(ctx) },\n { t: \"columns.prev\", run: (ctx) => columnsPrev(ctx) },\n { t: \"columns.arrowLeft\", run: (ctx) => columnsArrowLeft(ctx) },\n { t: \"columns.arrowRight\", run: (ctx) => columnsArrowRight(ctx) },\n // Columns insert / remove.\n {\n t: \"columns.insertCol\",\n run: (ctx, p) => columnsInsertCol(ctx, (p ?? {}) as ColumnsTarget),\n },\n {\n t: \"columns.removeCol\",\n run: (ctx, p) =>\n columnsRemoveCol(ctx, (p ?? {}) as { blockId?: string; col?: number }),\n },\n];\n",
|
|
48
|
+
"// ---------------------------------------------------------------------------\n// Hover/focus-revealed controls for table + columns blocks. Lets users add\n// and remove rows / columns without memorising slash commands. Both\n// decorations mount a small floating toolbar above their block; visibility\n// is driven by hover state OR by the caret being inside the block, so the\n// toolbar stays open while the user is actively editing a cell.\n// ---------------------------------------------------------------------------\n\nimport type { ColumnsBlock, DocState, Selection, TableBlock } from \"../../model/types\";\nimport type { DecorationDef } from \"../../plugin/types\";\nimport type { DispatchableCommand } from \"../../createEditor\";\n\ntype EditorRef = {\n docStore: { get: () => DocState; set: (d: DocState) => void };\n selStore: { get: () => Selection; set: (s: Selection) => void; subscribe?: (fn: () => void) => () => void };\n dispatch: (cmd: DispatchableCommand) => void;\n};\n\nfunction findEditor(blockEl: HTMLElement): EditorRef | null {\n const root = blockEl.closest(\"[data-creo-edit]\") as HTMLElement | null;\n if (!root) return null;\n return (root as unknown as { __creoEdit?: EditorRef }).__creoEdit ?? null;\n}\n\nfunction makeButton(label: string, title: string): HTMLButtonElement {\n const b = document.createElement(\"button\");\n b.type = \"button\";\n b.className = \"ce-cells-ctl\";\n b.textContent = label;\n b.setAttribute(\"aria-label\", title);\n b.title = title;\n // Block focus changes: clicking a control shouldn't move the caret away\n // from the cell the user was editing.\n b.addEventListener(\"mousedown\", (e) => e.preventDefault());\n return b;\n}\n\nfunction selectionBlockId(sel: Selection): string | null {\n return sel.kind === \"caret\" ? sel.at.blockId : sel.anchor.blockId;\n}\n\n/**\n * Mount a hover/focus-revealed toolbar above the block. The bar is hidden\n * unless: (a) the block is hovered, (b) the toolbar itself is hovered, or\n * (c) the caret is inside the block. Returns a cleanup function.\n */\nfunction mountToolbar(\n blockId: string,\n host: HTMLElement,\n buttons: HTMLButtonElement[],\n editor: EditorRef,\n hoveredBlock: () => string | null,\n // The decoration manager observes class changes on `host` to surface\n // hover state via `is-hovered`. We hand the same host down so we can\n // observe the same class flip.\n observeTarget: HTMLElement,\n): () => void {\n // The decoration container fills the whole block rect with\n // pointer-events: auto, which would block clicks on cell content. Disable\n // pointer events on the container and re-enable them on the toolbar so\n // only the toolbar itself is interactive.\n host.style.pointerEvents = \"none\";\n\n const bar = document.createElement(\"div\");\n bar.className = \"ce-cells-toolbar\";\n bar.style.position = \"absolute\";\n bar.style.top = \"-32px\";\n bar.style.right = \"0\";\n bar.style.pointerEvents = \"auto\";\n bar.style.display = \"none\";\n for (const b of buttons) bar.appendChild(b);\n host.appendChild(bar);\n\n let pointerOnBar = false;\n\n const isCaretInBlock = (): boolean => {\n const sel = editor.selStore.get();\n return selectionBlockId(sel) === blockId;\n };\n\n const updateVisibility = (): void => {\n const visible =\n pointerOnBar ||\n hoveredBlock() === blockId ||\n isCaretInBlock();\n bar.style.display = visible ? \"flex\" : \"none\";\n };\n\n bar.addEventListener(\"pointerenter\", () => {\n pointerOnBar = true;\n updateVisibility();\n });\n bar.addEventListener(\"pointerleave\", () => {\n pointerOnBar = false;\n updateVisibility();\n });\n\n // Observe the deco container's class changes (the manager toggles\n // `is-hovered` when the editor pointer enters this block).\n let observer: MutationObserver | null = null;\n try {\n observer = new MutationObserver(updateVisibility);\n observer.observe(observeTarget, {\n attributes: true,\n attributeFilter: [\"class\"],\n });\n } catch {}\n\n // Listen to selection changes so the toolbar stays open while the user is\n // typing inside the block. selectionchange on document is the cheapest\n // signal that fires for caret moves.\n const onSelChange = (): void => updateVisibility();\n document.addEventListener(\"selectionchange\", onSelChange);\n\n updateVisibility();\n\n return () => {\n observer?.disconnect();\n document.removeEventListener(\"selectionchange\", onSelChange);\n bar.remove();\n };\n}\n\n// ---------------------------------------------------------------------------\n// Table controls\n// ---------------------------------------------------------------------------\n\nexport const tableControlsDecoration: DecorationDef = {\n id: \"table-controls\",\n layer: \"top\",\n match: (b) => b.type === \"table\",\n mount(block, blockEl, host, handle) {\n const editor = findEditor(blockEl);\n if (!editor) return;\n const tb = block as TableBlock;\n void tb;\n\n const addRow = makeButton(\"+ Row\", \"Add row at the end\");\n addRow.addEventListener(\"click\", () => {\n editor.dispatch({\n t: \"table.insertRow\",\n payload: { blockId: block.id, where: \"end\" },\n });\n });\n\n const removeRow = makeButton(\"− Row\", \"Remove the last row\");\n removeRow.addEventListener(\"click\", () => {\n const cur = editor.docStore.get().byId.get(block.id) as TableBlock | undefined;\n if (!cur) return;\n editor.dispatch({\n t: \"table.removeRow\",\n payload: { blockId: block.id, row: cur.rows - 1 },\n });\n });\n\n const addCol = makeButton(\"+ Col\", \"Add column at the end\");\n addCol.addEventListener(\"click\", () => {\n editor.dispatch({\n t: \"table.insertCol\",\n payload: { blockId: block.id, where: \"end\" },\n });\n });\n\n const removeCol = makeButton(\"− Col\", \"Remove the last column\");\n removeCol.addEventListener(\"click\", () => {\n const cur = editor.docStore.get().byId.get(block.id) as TableBlock | undefined;\n if (!cur) return;\n editor.dispatch({\n t: \"table.removeCol\",\n payload: { blockId: block.id, col: cur.cols - 1 },\n });\n });\n\n return mountToolbar(\n block.id,\n host,\n [addRow, removeRow, addCol, removeCol],\n editor,\n () => handle.hoveredBlock(),\n host,\n );\n },\n};\n\n// ---------------------------------------------------------------------------\n// Columns controls\n// ---------------------------------------------------------------------------\n\nexport const columnsControlsDecoration: DecorationDef = {\n id: \"columns-controls\",\n layer: \"top\",\n match: (b) => b.type === \"columns\",\n mount(block, blockEl, host, handle) {\n const editor = findEditor(blockEl);\n if (!editor) return;\n\n const addCol = makeButton(\"+ Col\", \"Add column at the end\");\n addCol.addEventListener(\"click\", () => {\n editor.dispatch({\n t: \"columns.insertCol\",\n payload: { blockId: block.id, where: \"end\" },\n });\n });\n\n const removeCol = makeButton(\"− Col\", \"Remove the last column\");\n removeCol.addEventListener(\"click\", () => {\n const cur = editor.docStore.get().byId.get(block.id) as ColumnsBlock | undefined;\n if (!cur) return;\n editor.dispatch({\n t: \"columns.removeCol\",\n payload: { blockId: block.id, col: cur.cols - 1 },\n });\n });\n\n return mountToolbar(\n block.id,\n host,\n [addCol, removeCol],\n editor,\n () => handle.hoveredBlock(),\n host,\n );\n },\n};\n",
|
|
49
|
+
"// ---------------------------------------------------------------------------\n// cellsPlugin — table + columns blocks. First-party plugin shipped by\n// default. Users can opt out by passing `plugins: defaultPlugins.filter(p =>\n// p.name !== \"cells\")` to createEditor.\n//\n// Bundled here:\n// - block defs (view, runsAt, anchor codec, HTML codec, serialize codec)\n// - namespaced commands (table.insertRow, table.nextCell, ...)\n// - keymap entries: Tab / Shift-Tab + Arrow keys (gated by isInTable)\n// ---------------------------------------------------------------------------\n\nimport type { PublicView } from \"creo\";\nimport { newBlockId } from \"../../model/doc\";\nimport type {\n Block,\n BlockSpec,\n ColumnsBlock,\n InlineRun,\n Mark,\n TableBlock,\n} from \"../../model/types\";\nimport type {\n BlockDef,\n EditorPlugin,\n KeymapDef,\n} from \"../../plugin/types\";\nimport {\n columnsAnchorCodec,\n columnsRunsAt,\n tableAnchorCodec,\n tableRunsAt,\n} from \"./codecs\";\nimport {\n parseTableHTML,\n serializeColumnsHTML,\n serializeTableHTML,\n} from \"./htmlCodec\";\nimport { ColumnsViewPlugin, TableViewPlugin } from \"./views\";\nimport { isInColumns, isInTable, tableCommandDefs } from \"./commands\";\nimport { columnsControlsDecoration, tableControlsDecoration } from \"./controls\";\n\nconst ALLOWED_MARKS = new Set<Mark>([\"b\", \"i\", \"u\", \"s\", \"code\"]);\n\ntype SerializedRun = { text: string; marks?: string[] };\n\nfunction deserializeRun(r: SerializedRun): InlineRun {\n if (!r.marks || r.marks.length === 0) return { text: r.text };\n const marks = new Set<Mark>();\n for (const m of r.marks) if (ALLOWED_MARKS.has(m as Mark)) marks.add(m as Mark);\n return marks.size === 0 ? { text: r.text } : { text: r.text, marks };\n}\n\nfunction serializeRun(r: InlineRun): SerializedRun {\n if (!r.marks || r.marks.size === 0) return { text: r.text };\n return { text: r.text, marks: [...r.marks] };\n}\n\nconst tableDef: BlockDef<TableBlock> = {\n type: \"table\",\n view: TableViewPlugin as PublicView<{ block: TableBlock; key?: string }, void>,\n isTextBearing: false,\n runsAt: tableRunsAt as never,\n anchorCodec: tableAnchorCodec,\n htmlCodec: {\n matchHTML: [\"table\"],\n parseHTML: parseTableHTML,\n serializeHTML: serializeTableHTML,\n },\n serializeCodec: {\n serialize(b) {\n const t = b as TableBlock;\n return {\n id: t.id,\n type: \"table\",\n rows: t.rows,\n cols: t.cols,\n cells: t.cells.map((row) => row.map((cell) => cell.map(serializeRun))),\n };\n },\n deserialize(s, id) {\n const sb = s as { rows: number; cols: number; cells: SerializedRun[][][] };\n return {\n id,\n type: \"table\",\n rows: sb.rows,\n cols: sb.cols,\n cells: sb.cells.map((row) => row.map((cell) => cell.map(deserializeRun))),\n } as BlockSpec;\n },\n },\n};\n\nconst columnsDef: BlockDef<ColumnsBlock> = {\n type: \"columns\",\n view: ColumnsViewPlugin as PublicView<{ block: ColumnsBlock; key?: string }, void>,\n isTextBearing: false,\n runsAt: columnsRunsAt as never,\n anchorCodec: columnsAnchorCodec,\n htmlCodec: {\n serializeHTML: serializeColumnsHTML,\n },\n serializeCodec: {\n serialize(b) {\n const cb = b as ColumnsBlock;\n return {\n id: cb.id,\n type: \"columns\",\n cols: cb.cols,\n cells: cb.cells.map((cell) => cell.map(serializeRun)),\n };\n },\n deserialize(s, id) {\n const sb = s as { cols: number; cells: SerializedRun[][] };\n return {\n id,\n type: \"columns\",\n cols: sb.cols,\n cells: sb.cells.map((cell) => cell.map(deserializeRun)),\n } as BlockSpec;\n },\n },\n};\n\n// Keymap: gate by isInTable so plain Tab / arrow keys outside a table fall\n// through to the existing list-indent / browser-default handlers. The arrow\n// commands return false at non-edge positions so the keymap dispatcher\n// doesn't preventDefault — letting the browser handle within-cell motion.\nconst cellsKeymap: KeymapDef[] = [\n {\n chord: \"Tab\",\n when: (ctx) => isInTable(ctx.docStore.get(), ctx.selStore.get()),\n command: { t: \"table.nextCell\" },\n },\n {\n chord: \"Shift+Tab\",\n when: (ctx) => isInTable(ctx.docStore.get(), ctx.selStore.get()),\n command: { t: \"table.prevCell\" },\n },\n {\n chord: \"ArrowLeft\",\n when: (ctx) => isInTable(ctx.docStore.get(), ctx.selStore.get()),\n command: { t: \"table.arrowLeft\" },\n },\n {\n chord: \"ArrowRight\",\n when: (ctx) => isInTable(ctx.docStore.get(), ctx.selStore.get()),\n command: { t: \"table.arrowRight\" },\n },\n {\n chord: \"ArrowUp\",\n when: (ctx) => isInTable(ctx.docStore.get(), ctx.selStore.get()),\n command: { t: \"table.arrowUp\" },\n },\n {\n chord: \"ArrowDown\",\n when: (ctx) => isInTable(ctx.docStore.get(), ctx.selStore.get()),\n command: { t: \"table.arrowDown\" },\n },\n // Columns navigation — Tab walks columns left-to-right; arrow keys jump\n // between columns at the cell text edges (just like in tables).\n {\n chord: \"Tab\",\n when: (ctx) => isInColumns(ctx.docStore.get(), ctx.selStore.get()),\n command: { t: \"columns.next\" },\n },\n {\n chord: \"Shift+Tab\",\n when: (ctx) => isInColumns(ctx.docStore.get(), ctx.selStore.get()),\n command: { t: \"columns.prev\" },\n },\n {\n chord: \"ArrowLeft\",\n when: (ctx) => isInColumns(ctx.docStore.get(), ctx.selStore.get()),\n command: { t: \"columns.arrowLeft\" },\n },\n {\n chord: \"ArrowRight\",\n when: (ctx) => isInColumns(ctx.docStore.get(), ctx.selStore.get()),\n command: { t: \"columns.arrowRight\" },\n },\n];\n\n// Back-compat command aliases — the existing typed Command union has shapes\n// like { t: \"tableInsertRow\", where }. Routing them to the namespaced\n// implementations keeps existing callers (and tests) working without\n// renaming everywhere at once.\nconst backcompatAliases = [\n { t: \"tableInsertRow\", run: (ctx, p) => tableCommandDefs.find((c) => c.t === \"table.insertRow\")!.run(ctx, (p as { where: \"above\" | \"below\" }).where) },\n { t: \"tableInsertCol\", run: (ctx, p) => tableCommandDefs.find((c) => c.t === \"table.insertCol\")!.run(ctx, (p as { where: \"before\" | \"after\" }).where) },\n { t: \"tableRemoveRow\", run: (ctx, _p) => tableCommandDefs.find((c) => c.t === \"table.removeRow\")!.run(ctx, undefined) },\n { t: \"tableRemoveCol\", run: (ctx, _p) => tableCommandDefs.find((c) => c.t === \"table.removeCol\")!.run(ctx, undefined) },\n] as { t: string; run: (ctx: import(\"../../plugin/types\").CommandCtx, p: unknown) => boolean | void }[];\n\nexport const cellsPlugin: EditorPlugin = {\n name: \"cells\",\n blocks: [tableDef as BlockDef<Block>, columnsDef as BlockDef<Block>],\n commands: [...tableCommandDefs, ...backcompatAliases],\n keymap: cellsKeymap,\n decorations: [tableControlsDecoration, columnsControlsDecoration],\n};\n\nexport { isInTable } from \"./commands\";\n",
|
|
50
|
+
"// ---------------------------------------------------------------------------\n// TriggerManager — watches text insertion + key events for plugin triggers\n// (slash commands, mentions, etc.).\n//\n// At most ONE trigger can be active at a time. While active:\n// - subsequent text input extends the query and notifies the controller\n// - keydown events are routed to the controller's onKey first\n// - caret movement off the trigger range auto-closes\n//\n// The controller, returned by `TriggerDef.open`, is the trigger's contract\n// for rendering UI (popover, dropdown, autocomplete) and committing a\n// result. The manager itself never touches the DOM beyond computing a caret\n// rect for positioning.\n// ---------------------------------------------------------------------------\n\nimport type { Store } from \"creo\";\nimport type { Anchor, DocState, Selection } from \"../model/types\";\nimport type {\n DispatchableCommand,\n} from \"../createEditor\";\nimport { runsAt } from \"./runsAt\";\nimport type {\n TriggerController,\n TriggerCtx,\n TriggerDef,\n} from \"./types\";\nimport type { Registry } from \"./registry\";\n\nexport type TriggerManagerOptions = {\n registry: Registry;\n docStore: Store<DocState>;\n selStore: Store<Selection>;\n dispatch: (cmd: DispatchableCommand) => void;\n};\n\ntype ActiveState = {\n def: TriggerDef;\n ctrl: TriggerController;\n start: Anchor;\n query: string;\n};\n\nexport class TriggerManager {\n private active: ActiveState | null = null;\n private unsubSel: (() => void) | null = null;\n private unsubDoc: (() => void) | null = null;\n\n constructor(private opts: TriggerManagerOptions) {\n // Auto-close when caret moves out of the trigger block, OR moves\n // before the trigger char (e.g. arrow-left past the \"/\").\n this.unsubSel = opts.selStore.subscribe(() => this.reconcile());\n // Auto-close when the trigger char itself is deleted (backspace), or\n // when the doc otherwise mutates such that the typed query no longer\n // makes sense. Also recompute the live query string from the doc so\n // backspace inside the query updates the menu's filter.\n this.unsubDoc = opts.docStore.subscribe(() => this.reconcile());\n }\n\n destroy(): void {\n this.close();\n this.unsubSel?.();\n this.unsubDoc?.();\n this.unsubSel = null;\n this.unsubDoc = null;\n }\n\n /**\n * Re-derive the active trigger's state from the current doc + selection.\n * Closes the menu if any of:\n * - caret left the trigger's block\n * - caret moved before the trigger char position\n * - the trigger char at the start position is no longer there\n * Otherwise, recomputes the live query string and notifies the controller.\n */\n private reconcile(): void {\n if (!this.active) return;\n const sel = this.opts.selStore.get();\n const a = sel.kind === \"caret\" ? sel.at : sel.anchor;\n if (a.blockId !== this.active.start.blockId) {\n this.close();\n return;\n }\n const startOff = lastPathEntry(this.active.start);\n const curOff = lastPathEntry(a);\n // Caret moved before/onto the trigger position → trigger char is gone\n // or about to be (close on equality so the user can't backspace into\n // the trigger char itself).\n if (curOff < startOff) {\n this.close();\n return;\n }\n // Read the runs slot at the trigger anchor and check the trigger char\n // is still present at offset (startOff - 1).\n const block = this.opts.docStore.get().byId.get(a.blockId);\n if (!block) {\n this.close();\n return;\n }\n const ctx = runsAt(block, this.active.start);\n if (!ctx) {\n this.close();\n return;\n }\n const text = runsToText(ctx.runs);\n const triggerCharPos = startOff - 1;\n if (triggerCharPos < 0 || triggerCharPos >= text.length) {\n this.close();\n return;\n }\n const triggerChar = text[triggerCharPos];\n const def = this.active.def;\n const expected = typeof def.match === \"string\" ? def.match : null;\n if (expected !== null && triggerChar !== expected) {\n this.close();\n return;\n }\n // Recompute the query: text from the trigger anchor (after the trigger\n // char) up to the current caret position.\n const newQuery = text.slice(startOff, curOff);\n if (newQuery !== this.active.query) {\n this.active.query = newQuery;\n this.active.ctrl.onTextChange?.(newQuery);\n }\n }\n\n /** Called by nativeInput AFTER a successful insertText dispatch. */\n onTextInserted(text: string): void {\n // While a trigger is active, the docStore subscriber's reconcile has\n // already updated the query — no extra work needed here.\n if (this.active) return;\n const sel = this.opts.selStore.get();\n if (sel.kind !== \"caret\") return;\n for (const def of this.opts.registry.triggers) {\n if (!matchesTrigger(def, text)) continue;\n const ctx: TriggerCtx = {\n at: sel.at,\n docStore: this.opts.docStore,\n selStore: this.opts.selStore,\n dispatch: (...args: unknown[]) => {\n // Two call shapes:\n // dispatch({ t: \"toggleList\", ordered: true }) ← typed\n // dispatch(\"table.insertRow\", { where: \"below\" }) ← plugin\n if (typeof args[0] === \"string\") {\n const t = args[0];\n const payload = args[1];\n this.opts.dispatch({ t, payload } as DispatchableCommand);\n } else {\n this.opts.dispatch(args[0] as DispatchableCommand);\n }\n },\n caretRect: () => caretRect(),\n close: () => this.close(),\n };\n const ctrl = def.open(ctx);\n if (ctrl) {\n this.active = { def, ctrl, start: sel.at, query: \"\" };\n return;\n }\n }\n }\n\n /** Called by nativeInput at the top of onKeyDown. Returns true if consumed. */\n handleKeyDown(e: KeyboardEvent): boolean {\n if (!this.active) return false;\n if (e.key === \"Escape\") {\n e.preventDefault();\n this.close();\n return true;\n }\n return this.active.ctrl.onKey?.(e) ?? false;\n }\n\n isActive(): boolean {\n return this.active !== null;\n }\n\n close(): void {\n if (this.active) {\n try {\n this.active.ctrl.close();\n } catch {\n // Don't let a faulty controller leave us in a half-closed state.\n }\n this.active = null;\n }\n }\n}\n\nfunction matchesTrigger(def: TriggerDef, text: string): boolean {\n if (typeof def.match === \"string\") return text === def.match;\n return def.match.test(text);\n}\n\nfunction lastPathEntry(a: Anchor): number {\n return a.path[a.path.length - 1] ?? 0;\n}\n\nfunction runsToText(runs: import(\"../model/types\").InlineRun[]): string {\n let s = \"\";\n for (const r of runs) s += r.text;\n return s;\n}\n\nfunction caretRect(): DOMRect | null {\n if (typeof window === \"undefined\") return null;\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0) return null;\n try {\n return sel.getRangeAt(0).getBoundingClientRect();\n } catch {\n return null;\n }\n}\n",
|
|
51
|
+
"// ---------------------------------------------------------------------------\n// Decoration manager — overlay UI per block, mounted in a sibling layer so\n// hover/focus/drag state can change without dirtying block subscribers.\n//\n// The manager owns ONE absolute-positioned <div.ce-decorations> sibling of\n// the editor root. For each block currently in the doc that matches a\n// registered DecorationDef, it instantiates the decoration's `view` once\n// and re-positions it via getBoundingClientRect on:\n// - doc changes (block reordered / inserted / removed)\n// - scroll / resize on the editor's nearest scroll ancestor\n// - hover changes (decorations that opt into a `hovered` highlight)\n//\n// Decorations are NOT subscribed to per-block doc state. If a decoration\n// needs the block's content (badges, counts), it reads it lazily inside\n// onPointer events, NOT on every doc change.\n// ---------------------------------------------------------------------------\n\nimport type { Store } from \"creo\";\nimport type { Block, BlockId, DocState } from \"../model/types\";\nimport type { DecorationDef } from \"./types\";\nimport { findBlockElementById } from \"../dom/anchorMap\";\nimport type { Registry } from \"./registry\";\n\nexport type DecorationManagerOptions = {\n registry: Registry;\n docStore: Store<DocState>;\n /** Editor root (the contentEditable div). The decoration layer mounts as\n * a sibling, positioned to overlay the same screen rect. */\n editorRoot: HTMLElement;\n};\n\ntype Mounted = {\n def: DecorationDef;\n blockId: BlockId;\n el: HTMLElement;\n cleanup: (() => void) | void;\n};\n\nexport class DecorationManager {\n private layer: HTMLElement;\n private mounted = new Map<string, Mounted>();\n private rafQueued = false;\n private rafSyncRequested = false;\n private unsub: (() => void) | null = null;\n private resizeObserver: ResizeObserver | null = null;\n /** Hovered block id — surfaced to decorations via dataset on the layer\n * so they can style themselves with sibling CSS or read it directly. */\n private hoveredBlockId: BlockId | null = null;\n\n constructor(private opts: DecorationManagerOptions) {\n const layer = document.createElement(\"div\");\n layer.className = \"ce-decorations\";\n Object.assign(layer.style, {\n position: \"absolute\",\n inset: \"0\",\n pointerEvents: \"none\",\n zIndex: \"5\",\n } as Partial<CSSStyleDeclaration>);\n // Insert into the same positioned ancestor as the editor root.\n const parent = opts.editorRoot.parentElement ?? opts.editorRoot;\n parent.appendChild(layer);\n this.layer = layer;\n\n // Pointer tracking for hover.\n opts.editorRoot.addEventListener(\"pointermove\", this.onPointerMove);\n opts.editorRoot.addEventListener(\"pointerleave\", this.onPointerLeave);\n\n // Doc subscription — re-render when blocks come/go/reorder.\n this.unsub = opts.docStore.subscribe(() => this.scheduleSync());\n if (typeof ResizeObserver !== \"undefined\") {\n this.resizeObserver = new ResizeObserver(() => this.schedulePosition());\n this.resizeObserver.observe(opts.editorRoot);\n }\n window.addEventListener(\"scroll\", this.schedulePosition, { passive: true });\n window.addEventListener(\"resize\", this.schedulePosition);\n\n // Initial sync.\n this.sync();\n }\n\n destroy(): void {\n this.unsub?.();\n this.opts.editorRoot.removeEventListener(\"pointermove\", this.onPointerMove);\n this.opts.editorRoot.removeEventListener(\"pointerleave\", this.onPointerLeave);\n window.removeEventListener(\"scroll\", this.schedulePosition);\n window.removeEventListener(\"resize\", this.schedulePosition);\n this.resizeObserver?.disconnect();\n for (const m of this.mounted.values()) {\n try { m.cleanup?.(); } catch {}\n m.el.remove();\n }\n this.mounted.clear();\n this.layer.remove();\n }\n\n /** Currently hovered block id (or null). Decorations read this via\n * `manager.hoveredBlock()` to decide their own visibility. */\n hoveredBlock(): BlockId | null {\n return this.hoveredBlockId;\n }\n\n // -------------------------------------------------------------------------\n // Sync — reconcile mounted vs. desired set.\n // -------------------------------------------------------------------------\n\n // Scheduling: a single queued frame coalesces both `position` and `sync`\n // requests. `rafSyncRequested` upgrades the queued frame from a plain\n // reposition to a full sync (mount/unmount + reposition). Without this\n // upgrade a `schedulePosition` from a scroll/resize landing right before a\n // doc change would consume the frame, dropping the doc change's sync.\n private scheduleSync = (): void => {\n this.rafSyncRequested = true;\n if (this.rafQueued) return;\n this.rafQueued = true;\n this.queueFlush();\n };\n\n private schedulePosition = (): void => {\n if (this.rafQueued) return;\n this.rafQueued = true;\n this.queueFlush();\n };\n\n private queueFlush(): void {\n const cb = () => {\n this.rafQueued = false;\n const wantSync = this.rafSyncRequested;\n this.rafSyncRequested = false;\n if (wantSync) this.sync();\n else this.position();\n };\n if (typeof requestAnimationFrame !== \"undefined\") {\n requestAnimationFrame(cb);\n } else {\n queueMicrotask(cb);\n }\n }\n\n private sync(): void {\n const doc = this.opts.docStore.get();\n const wantKeys = new Set<string>();\n for (const id of doc.order) {\n const block = doc.byId.get(id)!;\n for (const def of this.opts.registry.decorations) {\n if (!def.match(block)) continue;\n const key = `${def.id}:${id}`;\n wantKeys.add(key);\n if (!this.mounted.has(key)) {\n this.mountDecoration(def, block);\n }\n }\n }\n // Unmount decorations whose blocks are gone.\n for (const [key, m] of this.mounted) {\n if (!wantKeys.has(key)) {\n try { m.cleanup?.(); } catch {}\n m.el.remove();\n this.mounted.delete(key);\n }\n }\n this.position();\n }\n\n private mountDecoration(def: DecorationDef, block: Block): void {\n const blockEl = findBlockElementById(this.opts.editorRoot, block.id);\n if (!blockEl) return;\n const el = document.createElement(\"div\");\n el.className = `ce-deco ce-deco-${def.id} ce-deco-layer-${def.layer}`;\n el.dataset.blockId = block.id;\n Object.assign(el.style, {\n position: \"absolute\",\n pointerEvents: \"auto\",\n } as Partial<CSSStyleDeclaration>);\n let cleanup: (() => void) | void = undefined;\n try {\n cleanup = def.mount(block, blockEl, el, this) ?? undefined;\n } catch {\n // Plugin error — drop without taking down the layer.\n }\n this.layer.appendChild(el);\n this.mounted.set(`${def.id}:${block.id}`, { def, blockId: block.id, el, cleanup });\n }\n\n // -------------------------------------------------------------------------\n // Position — set absolute coords from each block's bounding rect.\n // -------------------------------------------------------------------------\n\n private position(): void {\n const layerRect = this.layer.getBoundingClientRect();\n // Group mounted decorations by (blockId, layer) so we can stack\n // multiple decorations in the same layer side-by-side instead of\n // overlapping. Order within a (blockId, layer) group follows the\n // plugin registration order via this.opts.registry.decorations.\n const orderById = new Map<string, number>();\n this.opts.registry.decorations.forEach((d, i) => orderById.set(d.id, i));\n type Group = { blockId: string; layer: string; items: Mounted[] };\n const groups = new Map<string, Group>();\n for (const m of this.mounted.values()) {\n const key = `${m.blockId}::${m.def.layer}`;\n let g = groups.get(key);\n if (!g) {\n g = { blockId: m.blockId, layer: m.def.layer, items: [] };\n groups.set(key, g);\n }\n g.items.push(m);\n }\n for (const g of groups.values()) {\n g.items.sort(\n (a, b) =>\n (orderById.get(a.def.id) ?? 0) - (orderById.get(b.def.id) ?? 0),\n );\n }\n for (const g of groups.values()) {\n const blockEl = findBlockElementById(this.opts.editorRoot, g.blockId);\n if (!blockEl) {\n for (const m of g.items) m.el.style.display = \"none\";\n continue;\n }\n const r = blockEl.getBoundingClientRect();\n for (let i = 0; i < g.items.length; i++) {\n const m = g.items[i]!;\n m.el.style.display = \"\";\n const slot = layerSlotForLayer(m.def.layer, r, i, g.items.length);\n m.el.style.top = `${r.top - layerRect.top}px`;\n m.el.style.left = `${r.left - layerRect.left + slot.left}px`;\n m.el.style.width = `${slot.width ?? r.width}px`;\n m.el.style.height = `${r.height}px`;\n }\n }\n }\n\n // -------------------------------------------------------------------------\n // Hover tracking\n // -------------------------------------------------------------------------\n\n private onPointerMove = (e: PointerEvent): void => {\n const blockEl = (e.target as HTMLElement | null)?.closest?.(\n \"[data-block-kind]\",\n ) as HTMLElement | null;\n const id = blockEl?.getAttribute(\"data-block-id\") ?? null;\n if (id !== this.hoveredBlockId) {\n this.hoveredBlockId = id;\n // Surface as a dataset on each mounted decoration so CSS can style.\n for (const m of this.mounted.values()) {\n if (m.blockId === id) m.el.classList.add(\"is-hovered\");\n else m.el.classList.remove(\"is-hovered\");\n }\n }\n };\n\n private onPointerLeave = (): void => {\n if (this.hoveredBlockId !== null) {\n this.hoveredBlockId = null;\n for (const m of this.mounted.values()) m.el.classList.remove(\"is-hovered\");\n }\n };\n}\n\nfunction layerSlotForLayer(\n layer: DecorationDef[\"layer\"],\n blockRect: DOMRect,\n index: number,\n _total: number,\n): { left: number; width?: number } {\n // Slot width matches the gutter \"cell\" reserved per-decoration so multiple\n // decorations in the same layer don't overlap. Layout: slots stack\n // outward from the block — slot 0 nearest, slot 1 further out, ...\n const SLOT = 24;\n switch (layer) {\n case \"left\":\n // Closest slot at left = -SLOT (right against the block), then -2*SLOT,\n // -3*SLOT, … going further into the gutter.\n return { left: -SLOT * (index + 1), width: SLOT };\n case \"right\":\n return { left: blockRect.width + SLOT * index, width: SLOT };\n default:\n return { left: 0 };\n }\n}\n\n",
|
|
52
|
+
"// ---------------------------------------------------------------------------\n// Default slash menu items — building blocks every editor ships with.\n// Plugin authors extend by passing their own items to `slashCommandsPlugin`.\n// ---------------------------------------------------------------------------\n\nimport type { CommandCtx } from \"../../plugin/types\";\nimport type { DispatchableCommand } from \"../../createEditor\";\n\nexport type SlashItem = {\n id: string;\n title: string;\n description?: string;\n /** Lowercase keywords used by the default fuzzy filter. */\n keywords?: string[];\n /**\n * Run the action. The slash menu has already removed the trigger char(s)\n * from the document by the time this fires, and the caret is back where\n * the trigger was — this fn just dispatches whatever should happen.\n */\n run(ctx: CommandCtx & { dispatch: (cmd: DispatchableCommand) => void }): void;\n};\n\nexport const defaultSlashItems: SlashItem[] = [\n {\n id: \"p\",\n title: \"Paragraph\",\n description: \"Plain body text\",\n keywords: [\"paragraph\", \"text\", \"body\", \"p\"],\n run: (ctx) => ctx.dispatch({ t: \"setBlockType\", payload: { type: \"p\" } }),\n },\n {\n id: \"h1\",\n title: \"Heading 1\",\n keywords: [\"heading\", \"h1\", \"title\"],\n run: (ctx) => ctx.dispatch({ t: \"setBlockType\", payload: { type: \"h1\" } }),\n },\n {\n id: \"h2\",\n title: \"Heading 2\",\n keywords: [\"heading\", \"h2\", \"subtitle\"],\n run: (ctx) => ctx.dispatch({ t: \"setBlockType\", payload: { type: \"h2\" } }),\n },\n {\n id: \"h3\",\n title: \"Heading 3\",\n keywords: [\"heading\", \"h3\"],\n run: (ctx) => ctx.dispatch({ t: \"setBlockType\", payload: { type: \"h3\" } }),\n },\n {\n id: \"ul\",\n title: \"Bulleted list\",\n keywords: [\"bullet\", \"list\", \"ul\", \"unordered\"],\n run: (ctx) => ctx.dispatch({ t: \"toggleList\", ordered: false }),\n },\n {\n id: \"ol\",\n title: \"Numbered list\",\n keywords: [\"numbered\", \"ordered\", \"ol\", \"list\"],\n run: (ctx) => ctx.dispatch({ t: \"toggleList\", ordered: true }),\n },\n {\n id: \"code\",\n title: \"Code block\",\n keywords: [\"code\", \"pre\", \"snippet\"],\n run: (ctx) => ctx.dispatch({ t: \"setBlockType\", payload: { type: \"code\" } }),\n },\n {\n id: \"table\",\n title: \"Table\",\n description: \"2 × 2 grid you can grow with Tab\",\n keywords: [\"table\", \"grid\"],\n run: (ctx) => ctx.dispatch({ t: \"insertTable\", rows: 2, cols: 2 }),\n },\n {\n id: \"columns\",\n title: \"Columns\",\n description: \"Side-by-side layout\",\n keywords: [\"columns\", \"layout\", \"split\"],\n run: (ctx) => ctx.dispatch({ t: \"insertColumns\", cols: 2 }),\n },\n];\n\n/** Default fuzzy filter — case-insensitive substring match against title +\n * keywords. Plugins can pass a custom matcher via slashCommandsPlugin opts. */\nexport function defaultFilter(items: SlashItem[], query: string): SlashItem[] {\n const q = query.trim().toLowerCase();\n if (!q) return items;\n return items.filter((it) => {\n if (it.title.toLowerCase().includes(q)) return true;\n if (it.keywords) {\n for (const k of it.keywords) if (k.includes(q)) return true;\n }\n return false;\n });\n}\n",
|
|
53
|
+
"// ---------------------------------------------------------------------------\n// Slash menu UI — vanilla DOM popover anchored at the caret rect.\n//\n// The framework only sets the bare minimum required for the menu to work:\n// - the popover is `position: fixed` (positional)\n// - active item gets `is-active` class\n// - items get the `creo-slash-item` class\n// All cosmetic styling (colors, borders, padding, fonts) lives in the\n// consumer's stylesheet. A reference stylesheet is shipped at\n// `creo-edit/src/plugins/styles.css` for hosts that want defaults.\n// ---------------------------------------------------------------------------\n\nimport type { SlashItem } from \"./items\";\nimport { defaultFilter } from \"./items\";\n\nexport type MenuOptions = {\n items: SlashItem[];\n filter?: (items: SlashItem[], query: string) => SlashItem[];\n caretRect: DOMRect | null;\n /** Called when the user picks an item (Enter or click). */\n onPick(item: SlashItem): void;\n /** Called when the user hits Escape, clicks away, or otherwise dismisses. */\n onCancel(): void;\n};\n\nexport type MenuHandle = {\n setQuery(q: string): void;\n /** Returns true if the key was consumed (arrow nav / Enter / Esc). */\n handleKey(e: KeyboardEvent): boolean;\n destroy(): void;\n};\n\nconst ITEM_CLASS = \"creo-slash-item\";\n\nexport function mountSlashMenu(opts: MenuOptions): MenuHandle {\n const root = document.createElement(\"div\");\n root.className = \"creo-slash\";\n root.setAttribute(\"role\", \"listbox\");\n // Positional only — host stylesheet owns appearance.\n root.style.position = \"fixed\";\n root.style.zIndex = \"10000\";\n positionAt(root, opts.caretRect);\n\n document.body.appendChild(root);\n\n let filtered: SlashItem[] = (opts.filter ?? defaultFilter)(opts.items, \"\");\n let activeIdx = 0;\n\n const render = (): void => {\n root.innerHTML = \"\";\n if (filtered.length === 0) {\n const empty = document.createElement(\"div\");\n empty.className = \"creo-slash-empty\";\n empty.textContent = \"No matches\";\n root.appendChild(empty);\n return;\n }\n for (let i = 0; i < filtered.length; i++) {\n const it = filtered[i]!;\n const el = document.createElement(\"div\");\n el.className = ITEM_CLASS + (i === activeIdx ? \" is-active\" : \"\");\n el.setAttribute(\"role\", \"option\");\n el.setAttribute(\"data-id\", it.id);\n const title = document.createElement(\"div\");\n title.className = \"creo-slash-item-title\";\n title.textContent = it.title;\n el.appendChild(title);\n if (it.description) {\n const desc = document.createElement(\"div\");\n desc.className = \"creo-slash-item-desc\";\n desc.textContent = it.description;\n el.appendChild(desc);\n }\n el.addEventListener(\"mousedown\", (e) => {\n // mousedown (not click) so we fire before the editor loses focus.\n e.preventDefault();\n opts.onPick(it);\n });\n el.addEventListener(\"mouseenter\", () => {\n activeIdx = i;\n render();\n });\n root.appendChild(el);\n }\n };\n\n render();\n\n const handle: MenuHandle = {\n setQuery(q) {\n filtered = (opts.filter ?? defaultFilter)(opts.items, q);\n activeIdx = 0;\n render();\n },\n handleKey(e) {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n if (filtered.length > 0) {\n activeIdx = (activeIdx + 1) % filtered.length;\n render();\n }\n return true;\n }\n if (e.key === \"ArrowUp\") {\n e.preventDefault();\n if (filtered.length > 0) {\n activeIdx = (activeIdx - 1 + filtered.length) % filtered.length;\n render();\n }\n return true;\n }\n if (e.key === \"Enter\") {\n e.preventDefault();\n const it = filtered[activeIdx];\n if (it) opts.onPick(it);\n else opts.onCancel();\n return true;\n }\n return false;\n },\n destroy() {\n root.remove();\n },\n };\n return handle;\n}\n\nfunction positionAt(el: HTMLElement, rect: DOMRect | null): void {\n if (!rect) {\n el.style.left = \"20px\";\n el.style.top = \"20px\";\n return;\n }\n const vh = window.innerHeight ?? 800;\n const vw = window.innerWidth ?? 800;\n const PAD = 4;\n let top = rect.bottom + PAD;\n let left = rect.left;\n const estH = 280;\n if (top + estH > vh) top = Math.max(PAD, rect.top - estH - PAD);\n if (left + 240 > vw) left = vw - 240 - PAD;\n el.style.left = `${left}px`;\n el.style.top = `${top}px`;\n}\n",
|
|
54
|
+
"// ---------------------------------------------------------------------------\n// slashCommandsPlugin — registers a \"/\" trigger that opens a popover menu\n// of block-creation actions. Reuses the trigger system shipped in M3.\n//\n// Behavior:\n// - Typing \"/\" at the caret opens the menu, anchored to the caret rect\n// - Subsequent typed chars filter the item list (default: substring match\n// against title + keywords)\n// - ArrowUp / ArrowDown navigate; Enter picks; Escape / click-away closes\n// - Picking an item:\n// 1. Deletes the typed \"/<query>\" string from the document\n// 2. Calls the item's `run(ctx)` which dispatches the actual command\n//\n// Plugin authors extend by passing custom items via `slashCommandsPlugin({\n// items: [...] })`. A trigger plugin for \"@\" mentions can ignore this whole\n// module and register its own TriggerDef with a different match.\n// ---------------------------------------------------------------------------\n\nimport type { CommandCtx, EditorPlugin, TriggerDef } from \"../../plugin/types\";\nimport type { DispatchableCommand } from \"../../createEditor\";\nimport {\n defaultFilter,\n defaultSlashItems,\n type SlashItem,\n} from \"./items\";\nimport { mountSlashMenu } from \"./menu\";\n\nexport type SlashOptions = {\n /** Replace or extend the default item list. */\n items?: SlashItem[];\n /** Custom filter — defaults to case-insensitive substring on title+keywords. */\n filter?: (items: SlashItem[], query: string) => SlashItem[];\n};\n\nexport function slashCommandsPlugin(opts: SlashOptions = {}): EditorPlugin {\n const items = opts.items ?? defaultSlashItems;\n const filter = opts.filter ?? defaultFilter;\n\n const trigger: TriggerDef = {\n match: \"/\",\n open(ctx) {\n const startAt = ctx.at;\n let query = \"\";\n\n const removeTriggerText = (): void => {\n // Walk back from the current caret to startAt and delete the\n // characters in between via repeated deleteBackward dispatches.\n // The trigger char itself (\"/\") was at startAt.offset, so we want\n // to delete from current offset back to startAt.offset.\n const sel = ctx.selStore.get();\n const at = sel.kind === \"caret\" ? sel.at : sel.anchor;\n if (at.blockId !== startAt.blockId) return;\n const pathSame = at.path.length === startAt.path.length &&\n at.path.every((v, i) => i === at.path.length - 1 ? true : v === startAt.path[i]);\n if (!pathSame) return;\n const startOff = startAt.path[startAt.path.length - 1] ?? 0;\n const curOff = at.path[at.path.length - 1] ?? 0;\n const delta = curOff - startOff + 1; // +1 for the \"/\" itself\n for (let i = 0; i < delta; i++) {\n ctx.dispatch(\"deleteBackward\");\n }\n };\n\n const cmdCtx: CommandCtx & { dispatch: (cmd: DispatchableCommand) => void } = {\n docStore: ctx.docStore,\n selStore: ctx.selStore,\n // Pass the full command object through (don't extract `payload`) so\n // typed built-ins like `{ t: \"insertTable\", rows, cols }` keep their\n // flat fields instead of arriving as `{ t, payload: undefined }`.\n dispatch: (cmd) => ctx.dispatch(cmd as never),\n };\n\n const menu = mountSlashMenu({\n items,\n filter,\n caretRect: ctx.caretRect(),\n onPick: (it) => {\n removeTriggerText();\n it.run(cmdCtx);\n // Tell the trigger manager we're done so subsequent keys (e.g.\n // Enter to split the just-promoted h1) flow through normally.\n // ctx.close() invokes our own `close()` below, which destroys\n // the menu — no need to call menu.destroy() here as well.\n ctx.close();\n },\n onCancel: () => ctx.close(),\n });\n\n return {\n onTextChange(q) {\n query = q;\n menu.setQuery(query);\n },\n onKey(e) {\n return menu.handleKey(e);\n },\n close() {\n menu.destroy();\n },\n };\n },\n };\n\n return {\n name: \"slash-commands\",\n triggers: [trigger],\n };\n}\n\nexport type { SlashItem } from \"./items\";\nexport { defaultSlashItems, defaultFilter } from \"./items\";\n// Re-export the menu mount fn so consumers can attach a slash UI to\n// non-editor surfaces (e.g. a markdown source textarea in the demo).\nexport { mountSlashMenu, type MenuHandle, type MenuOptions } from \"./menu\";\n",
|
|
55
|
+
"// ---------------------------------------------------------------------------\n// dragHandlePlugin — Notion-style \"⋮⋮\" handle in the left gutter of every\n// block. Drag a block to reorder via fractional-index mutation.\n//\n// UX: pointer-down clones the block as a semi-transparent \"ghost\" that\n// follows the cursor; the real block is dimmed in place; a blue drop-\n// indicator line shows the insertion point under any hovered block;\n// release commits the reorder via the doc store.\n// ---------------------------------------------------------------------------\n\nimport { generateBetween } from \"../../model/fractional\";\nimport { newBlockId } from \"../../model/doc\";\nimport type {\n Block,\n BlockId,\n ColumnsBlock,\n DocState,\n InlineRun,\n Selection,\n} from \"../../model/types\";\nimport type { EditorPlugin } from \"../../plugin/types\";\n\ntype DropPos = \"before\" | \"after\" | \"left\" | \"right\";\n\nexport type DragHandleOptions = {\n /** Show on hover only (default). When `false`, handles are always visible. */\n hoverOnly?: boolean;\n};\n\nexport function dragHandlePlugin(\n opts: DragHandleOptions = {},\n): EditorPlugin {\n const hoverOnly = opts.hoverOnly !== false;\n\n return {\n name: \"drag-handle\",\n decorations: [\n {\n id: \"drag-handle\",\n layer: \"left\",\n match: () => true,\n mount(block, blockEl, host, handle) {\n const btn = document.createElement(\"button\");\n btn.type = \"button\";\n btn.setAttribute(\"aria-label\", \"Drag to reorder\");\n btn.textContent = \"⋮⋮\";\n btn.className = \"ce-drag-btn\";\n // touchAction is functional (prevents browser scroll on touch\n // drag); cursor is functional (grab vs grabbing). Everything\n // else (color, size, opacity defaults) is in consumer CSS.\n btn.style.touchAction = \"none\";\n btn.style.cursor = \"grab\";\n\n const updateVisibility = () => {\n if (!hoverOnly) {\n btn.classList.add(\"is-visible\");\n return;\n }\n const hovered = handle.hoveredBlock() === block.id;\n btn.classList.toggle(\"is-visible\", hovered);\n };\n let observer: MutationObserver | null = null;\n try {\n observer = new MutationObserver(updateVisibility);\n observer.observe(host, { attributes: true, attributeFilter: [\"class\"] });\n } catch {}\n updateVisibility();\n\n // ---------------------------------------------------------------\n // Drag state\n // ---------------------------------------------------------------\n let dragging = false;\n let dragOver: BlockId | null = null;\n let dragOverPos: DropPos = \"after\";\n let indicator: HTMLElement | null = null;\n let ghost: HTMLElement | null = null;\n let ghostOffsetX = 0;\n let ghostOffsetY = 0;\n // Side zone: the leftmost / rightmost N pixels of a target trigger\n // a left-drop / right-drop (creates a columns block). Anywhere\n // else falls through to top/bottom reorder.\n const SIDE_ZONE_PX = 60;\n\n const ensureGhost = (sourceRect: DOMRect, clientX: number, clientY: number): void => {\n if (ghost) return;\n // Clone the block element so the ghost shows the actual block\n // content. data-block-* stripped so anchor lookups don't pick\n // up the ghost.\n const clone = blockEl.cloneNode(true) as HTMLElement;\n for (const el of Array.from(clone.querySelectorAll(\"[data-block-id]\"))) {\n el.removeAttribute(\"data-block-id\");\n }\n clone.removeAttribute(\"data-block-id\");\n clone.removeAttribute(\"data-block-kind\");\n clone.removeAttribute(\"contenteditable\");\n clone.classList.add(\"ce-drag-ghost\");\n // Functional positional styles only — appearance via CSS class.\n clone.style.position = \"fixed\";\n clone.style.top = `${sourceRect.top}px`;\n clone.style.left = `${sourceRect.left}px`;\n clone.style.width = `${sourceRect.width}px`;\n clone.style.pointerEvents = \"none\";\n clone.style.zIndex = \"10001\";\n document.body.appendChild(clone);\n ghost = clone;\n ghostOffsetX = clientX - sourceRect.left;\n ghostOffsetY = clientY - sourceRect.top;\n };\n\n const moveGhost = (clientX: number, clientY: number): void => {\n if (!ghost) return;\n ghost.style.left = `${clientX - ghostOffsetX}px`;\n ghost.style.top = `${clientY - ghostOffsetY}px`;\n };\n\n const showIndicator = (target: HTMLElement, pos: DropPos): void => {\n if (!indicator) {\n indicator = document.createElement(\"div\");\n indicator.className = \"ce-drag-indicator\";\n indicator.style.position = \"fixed\";\n indicator.style.pointerEvents = \"none\";\n indicator.style.zIndex = \"10000\";\n document.body.appendChild(indicator);\n }\n const r = target.getBoundingClientRect();\n indicator.style.display = \"\";\n // Toggle horizontal vs. vertical orientation by class so the\n // host stylesheet can swap dimensions/colors per direction.\n indicator.classList.toggle(\"is-vertical\", pos === \"left\" || pos === \"right\");\n if (pos === \"before\" || pos === \"after\") {\n indicator.style.top = `${(pos === \"before\" ? r.top : r.bottom) - 1}px`;\n indicator.style.left = `${r.left}px`;\n indicator.style.width = `${r.width}px`;\n indicator.style.height = \"\";\n } else {\n // Vertical bar at left or right edge.\n indicator.style.top = `${r.top}px`;\n indicator.style.left = `${(pos === \"left\" ? r.left : r.right) - 1}px`;\n indicator.style.width = \"\";\n indicator.style.height = `${r.height}px`;\n }\n };\n\n const hideIndicator = (): void => {\n if (indicator) indicator.style.display = \"none\";\n };\n\n const onMove = (e: PointerEvent): void => {\n if (!dragging) return;\n e.preventDefault();\n moveGhost(e.clientX, e.clientY);\n // Find target block under the pointer.\n const editorRoot = blockEl.closest(\"[data-creo-edit]\") as HTMLElement | null;\n if (!editorRoot) return;\n // Hide the ghost briefly so elementFromPoint sees the underlying\n // editor content, then restore.\n const prevDisplay = ghost?.style.display ?? \"\";\n if (ghost) ghost.style.display = \"none\";\n const elUnder = document.elementFromPoint(e.clientX, e.clientY);\n if (ghost) ghost.style.display = prevDisplay;\n const targetBlock = elUnder?.closest(\"[data-block-kind]\") as HTMLElement | null;\n if (!targetBlock || targetBlock === blockEl) {\n dragOver = null;\n hideIndicator();\n return;\n }\n const tid = targetBlock.getAttribute(\"data-block-id\");\n if (!tid) return;\n const r = targetBlock.getBoundingClientRect();\n dragOver = tid;\n // Side-zone detection: leftmost / rightmost N pixels create a\n // columns block; everything else is a top/bottom reorder.\n const leftEdge = e.clientX - r.left;\n const rightEdge = r.right - e.clientX;\n if (leftEdge >= 0 && leftEdge < SIDE_ZONE_PX) {\n dragOverPos = \"left\";\n } else if (rightEdge >= 0 && rightEdge < SIDE_ZONE_PX) {\n dragOverPos = \"right\";\n } else {\n dragOverPos = e.clientY < r.top + r.height / 2 ? \"before\" : \"after\";\n }\n showIndicator(targetBlock, dragOverPos);\n };\n\n const cleanupDrag = (): void => {\n document.removeEventListener(\"pointermove\", onMove);\n document.removeEventListener(\"pointerup\", onUp);\n document.removeEventListener(\"pointercancel\", onUp);\n ghost?.remove();\n ghost = null;\n indicator?.remove();\n indicator = null;\n dragOver = null;\n };\n\n const onUp = (e: PointerEvent): void => {\n if (!dragging) {\n cleanupDrag();\n return;\n }\n e.preventDefault();\n dragging = false;\n btn.style.cursor = \"grab\";\n blockEl.style.opacity = \"\";\n // Capture the target before cleanup nulls dragOver.\n const target = dragOver;\n const pos = dragOverPos;\n cleanupDrag();\n if (target && target !== block.id) {\n reorderTo(blockEl, block.id, target, pos);\n }\n };\n\n btn.addEventListener(\"pointerdown\", (e) => {\n // Only respond to primary button.\n if (e.button !== undefined && e.button !== 0) return;\n e.preventDefault();\n dragging = true;\n btn.style.cursor = \"grabbing\";\n blockEl.style.opacity = \"0.4\";\n const r = blockEl.getBoundingClientRect();\n ensureGhost(r, e.clientX, e.clientY);\n document.addEventListener(\"pointermove\", onMove);\n document.addEventListener(\"pointerup\", onUp);\n document.addEventListener(\"pointercancel\", onUp);\n });\n\n host.appendChild(btn);\n return () => {\n observer?.disconnect();\n cleanupDrag();\n blockEl.style.opacity = \"\";\n };\n },\n },\n ],\n };\n}\n\n/**\n * Move the dragged block to before/after the target (reorder) OR to the\n * left/right of the target (Notion-style: wraps target + dragged into a\n * `columns` block, or appends to an existing one).\n */\nfunction reorderTo(\n blockEl: HTMLElement,\n draggedId: BlockId,\n targetId: BlockId,\n pos: DropPos,\n): void {\n const editorRoot = blockEl.closest(\"[data-creo-edit]\") as HTMLElement | null;\n if (!editorRoot) return;\n const editor = (editorRoot as unknown as { __creoEdit?: {\n docStore: { get: () => DocState; set: (d: DocState) => void };\n selStore?: { set: (s: Selection) => void };\n } }).__creoEdit;\n if (!editor) return;\n const doc = editor.docStore.get();\n const draggedBlock = doc.byId.get(draggedId);\n const targetBlock = doc.byId.get(targetId);\n if (!draggedBlock || !targetBlock) return;\n if (pos === \"left\" || pos === \"right\") {\n sideDrop(editor, doc, draggedBlock, targetBlock, pos);\n return;\n }\n const order = doc.order;\n const tIdx = order.indexOf(targetId);\n if (tIdx < 0) return;\n const newOrder = order.filter((id) => id !== draggedId);\n const newTIdx = newOrder.indexOf(targetId);\n if (newTIdx < 0) return;\n const insertAt = pos === \"before\" ? newTIdx : newTIdx + 1;\n const prevId = insertAt === 0 ? null : newOrder[insertAt - 1] ?? null;\n const nextId = insertAt === newOrder.length ? null : newOrder[insertAt] ?? null;\n const prevIdx = prevId ? doc.byId.get(prevId)!.index : null;\n const nextIdx = nextId ? doc.byId.get(nextId)!.index : null;\n let newIdx: string;\n try {\n newIdx = generateBetween(prevIdx, nextIdx);\n } catch {\n return;\n }\n const nextById = new Map(doc.byId);\n nextById.set(draggedId, { ...(draggedBlock as Block), index: newIdx } as Block);\n newOrder.splice(insertAt, 0, draggedId);\n editor.docStore.set({ byId: nextById, order: newOrder });\n}\n\n/** Extract inline runs from a block. Text-bearing blocks return `runs`;\n * other kinds (img / table / columns) flatten to an empty run set since\n * the columns block model only stores `InlineRun[]` per cell. Callers\n * that hand non-text blocks lose their structure here. */\nfunction blockToRuns(block: Block): InlineRun[] {\n if (\"runs\" in block && Array.isArray((block as { runs?: InlineRun[] }).runs)) {\n return (block as Block & { runs: InlineRun[] }).runs;\n }\n return [];\n}\n\n/** Drop the dragged block onto the left/right of the target. If the target\n * is already a columns block, append/prepend a new column from dragged.\n * Otherwise wrap target+dragged into a fresh 2-column columns block. */\nfunction sideDrop(\n editor: {\n docStore: { get: () => DocState; set: (d: DocState) => void };\n selStore?: { set: (s: Selection) => void };\n },\n doc: DocState,\n draggedBlock: Block,\n targetBlock: Block,\n side: \"left\" | \"right\",\n): void {\n const draggedRuns = blockToRuns(draggedBlock);\n // Build the new columns block content.\n let nextColumns: ColumnsBlock;\n if (targetBlock.type === \"columns\") {\n const tb = targetBlock as ColumnsBlock;\n const cells = side === \"left\"\n ? [draggedRuns, ...tb.cells]\n : [...tb.cells, draggedRuns];\n nextColumns = {\n ...tb,\n cols: cells.length,\n cells,\n };\n } else {\n const targetRuns = blockToRuns(targetBlock);\n const cells = side === \"left\" ? [draggedRuns, targetRuns] : [targetRuns, draggedRuns];\n nextColumns = {\n id: newBlockId(),\n // Reuse the target's index slot — the new columns block takes the\n // target's position in the order.\n index: targetBlock.index,\n type: \"columns\",\n cols: 2,\n cells,\n };\n }\n // Apply the doc mutation: remove dragged, replace target with the columns\n // block (or merge into existing columns block).\n const nextById = new Map(doc.byId);\n nextById.delete(draggedBlock.id);\n if (targetBlock.type === \"columns\") {\n nextById.set(targetBlock.id, nextColumns as unknown as Block);\n } else {\n nextById.delete(targetBlock.id);\n nextById.set(nextColumns.id, nextColumns as unknown as Block);\n }\n const nextOrder = doc.order\n .filter((id) => id !== draggedBlock.id)\n .map((id) => (id === targetBlock.id && targetBlock.type !== \"columns\" ? nextColumns.id : id));\n editor.docStore.set({ byId: nextById, order: nextOrder });\n // Place the caret at the start of the dragged column.\n if (editor.selStore) {\n const colIndex =\n targetBlock.type === \"columns\"\n ? side === \"left\"\n ? 0\n : (targetBlock as ColumnsBlock).cols\n : side === \"left\"\n ? 0\n : 1;\n editor.selStore.set({\n kind: \"caret\",\n at: { blockId: nextColumns.id, path: [colIndex, 0], offset: 0 },\n });\n }\n}\n",
|
|
56
|
+
"// ---------------------------------------------------------------------------\n// addBlockPlugin — \"+\" button in the left gutter. Default behavior:\n//\n// 1. Click → open a \"what to add?\" menu anchored to the button\n// 2. Pick → insert an empty block ABOVE the hovered block, place the\n// caret in it, and dispatch the chosen action (which usually changes\n// the block kind, applies a list, inserts a table, etc.)\n//\n// The menu uses the slash menu's mountSlashMenu UI so it's visually\n// consistent across \"/\" trigger and \"+\" gutter button — but it does NOT\n// require the slash plugin to be installed.\n//\n// Override with `onClick(block, blockEl)` to do something custom (e.g.\n// open your own picker or directly insert a fixed block kind).\n// ---------------------------------------------------------------------------\n\nimport { generateBetween } from \"../../model/fractional\";\nimport { newBlockId } from \"../../model/doc\";\nimport type {\n Block,\n BlockSpec,\n DocState,\n Selection,\n} from \"../../model/types\";\nimport type { DispatchableCommand } from \"../../createEditor\";\nimport type { EditorPlugin } from \"../../plugin/types\";\nimport {\n defaultSlashItems,\n type SlashItem,\n} from \"../slash/items\";\nimport { mountSlashMenu } from \"../slash/menu\";\n\nexport type AddBlockOptions = {\n /** Show on hover only (default). */\n hoverOnly?: boolean;\n /**\n * Custom click handler. When provided, replaces the default behavior of\n * opening the picker menu — useful for hosts that want a different UI\n * or that want to insert a fixed block kind without prompting.\n */\n onClick?: (block: Block, blockEl: HTMLElement) => void;\n /** Replace or extend the items shown in the picker. Defaults to the\n * same set as the slash menu. */\n items?: SlashItem[];\n};\n\nexport function addBlockPlugin(opts: AddBlockOptions = {}): EditorPlugin {\n const hoverOnly = opts.hoverOnly !== false;\n const items = opts.items ?? defaultSlashItems;\n\n return {\n name: \"add-block\",\n decorations: [\n {\n id: \"add-block\",\n layer: \"left\",\n match: () => true,\n mount(block, blockEl, host, handle) {\n const btn = document.createElement(\"button\");\n btn.type = \"button\";\n btn.setAttribute(\"aria-label\", \"Insert block above\");\n btn.textContent = \"+\";\n btn.className = \"ce-add-block-btn\";\n\n const updateVisibility = () => {\n if (!hoverOnly) {\n btn.classList.add(\"is-visible\");\n return;\n }\n const hovered = handle.hoveredBlock() === block.id;\n btn.classList.toggle(\"is-visible\", hovered);\n };\n let observer: MutationObserver | null = null;\n try {\n observer = new MutationObserver(updateVisibility);\n observer.observe(host, { attributes: true, attributeFilter: [\"class\"] });\n } catch {}\n updateVisibility();\n\n btn.addEventListener(\"click\", (e) => {\n e.preventDefault();\n if (opts.onClick) {\n opts.onClick(block, blockEl);\n return;\n }\n openAddMenu(btn, blockEl, block.id, items);\n });\n\n host.appendChild(btn);\n return () => observer?.disconnect();\n },\n },\n ],\n };\n}\n\nfunction openAddMenu(\n btn: HTMLElement,\n blockEl: HTMLElement,\n beforeBlockId: string,\n items: SlashItem[],\n): void {\n // The block element captured at mount may have been replaced by a\n // creo re-render; fall back to a fresh document-level lookup so the\n // editor reference stays reachable.\n let editorRoot = blockEl.closest(\"[data-creo-edit]\") as HTMLElement | null;\n if (!editorRoot) {\n editorRoot = document.querySelector(\"[data-creo-edit]\") as HTMLElement | null;\n }\n if (!editorRoot) return;\n const editor = (editorRoot as unknown as { __creoEdit?: {\n docStore: { get: () => DocState; set: (d: DocState) => void };\n selStore: { set: (s: Selection) => void };\n dispatch: (cmd: DispatchableCommand) => void;\n } }).__creoEdit;\n if (!editor) return;\n\n const r = btn.getBoundingClientRect();\n // Anchor the menu just to the right of the + button. Use a plain\n // DOMRect-shaped object instead of `new DOMRect(...)` because some\n // headless test envs (happy-dom) don't expose the constructor globally.\n const caretRect = {\n x: r.right + 4,\n y: r.top,\n width: 0,\n height: r.height,\n top: r.top,\n right: r.right + 4,\n bottom: r.top + r.height,\n left: r.right + 4,\n toJSON() { return this; },\n } as DOMRect;\n\n const menu = mountSlashMenu({\n items,\n caretRect,\n onPick: (it) => {\n // 1. Insert an empty paragraph ABOVE the hovered block.\n const newId = insertParagraphAbove(editor, beforeBlockId);\n if (!newId) {\n menu.destroy();\n return;\n }\n // 2. Place caret in the new paragraph.\n editor.selStore.set({\n kind: \"caret\",\n at: { blockId: newId, path: [0], offset: 0 },\n });\n // 3. Run the item's action — most items dispatch setBlockType /\n // toggleList / insertTable etc. against the current selection,\n // which is now the newly-inserted paragraph.\n const cmdCtx = {\n docStore: editor.docStore,\n selStore: editor.selStore,\n dispatch: editor.dispatch,\n };\n try {\n it.run(cmdCtx as never);\n } catch {\n // Item handler error — leave the empty paragraph in place.\n }\n menu.destroy();\n },\n onCancel: () => menu.destroy(),\n });\n\n // Close on Escape / click outside.\n const onKey = (e: KeyboardEvent): void => {\n if (e.key === \"Escape\") {\n menu.destroy();\n cleanup();\n } else {\n menu.handleKey(e);\n }\n };\n const onDocClick = (e: MouseEvent): void => {\n const target = e.target as Node;\n if (!document.querySelector(\".creo-slash\")?.contains(target)) {\n menu.destroy();\n cleanup();\n }\n };\n const cleanup = (): void => {\n document.removeEventListener(\"keydown\", onKey, true);\n document.removeEventListener(\"mousedown\", onDocClick, true);\n };\n // Defer to next tick so the click that opened the menu doesn't immediately close it.\n setTimeout(() => {\n document.addEventListener(\"keydown\", onKey, true);\n document.addEventListener(\"mousedown\", onDocClick, true);\n }, 0);\n}\n\n/** Insert an empty paragraph immediately before `beforeBlockId`. Returns\n * the new block's id, or null on failure. */\nfunction insertParagraphAbove(\n editor: {\n docStore: { get: () => DocState; set: (d: DocState) => void };\n },\n beforeBlockId: string,\n): string | null {\n const doc = editor.docStore.get();\n const idx = doc.order.indexOf(beforeBlockId);\n if (idx < 0) return null;\n const prevId = idx === 0 ? null : doc.order[idx - 1] ?? null;\n const prevIdx = prevId ? doc.byId.get(prevId)!.index : null;\n const nextIdx = doc.byId.get(beforeBlockId)!.index;\n let newIdx: string;\n try {\n newIdx = generateBetween(prevIdx, nextIdx);\n } catch {\n return null;\n }\n const newId = newBlockId();\n const newBlock: BlockSpec & { index: string } = {\n id: newId,\n type: \"p\",\n runs: [],\n index: newIdx,\n };\n const nextById = new Map(doc.byId);\n nextById.set(newId, newBlock as unknown as Block);\n const nextOrder = [...doc.order];\n nextOrder.splice(idx, 0, newId);\n editor.docStore.set({ byId: nextById, order: nextOrder });\n return newId;\n}\n",
|
|
57
|
+
"// ---------------------------------------------------------------------------\n// mdShortcutsPlugin — markdown typing shortcuts in WYSIWYG mode.\n//\n// Triggers fire on space (block-prefix patterns) or on the closing token of\n// inline mark patterns. Each rule:\n// 1. Matches a regex against the current block's text + caret position\n// 2. Removes the matched markup characters (`# `, `**`, etc.)\n// 3. Dispatches the corresponding command (setBlockType, toggleMark)\n//\n// Reuses the trigger system: each rule is a TriggerDef whose `match` is the\n// trigger character (space, asterisk, backtick, ...) and whose `open()`\n// inspects the block prefix and applies the rule synchronously, then\n// closes — no UI rendered.\n// ---------------------------------------------------------------------------\n\nimport { caret } from \"../../controller/selection\";\nimport { runsLengthAt, runsAt } from \"../../plugin/runsAt\";\nimport type {\n EditorPlugin,\n TriggerCtx,\n TriggerDef,\n} from \"../../plugin/types\";\nimport type { Mark } from \"../../model/types\";\n\ntype RuleResult = \"applied\" | \"skipped\";\n\ntype BlockRule = {\n /** Pattern matched against the prefix of the block's runs text — must\n * capture the leading markup so we know how many chars to delete. */\n pattern: RegExp;\n apply(ctx: TriggerCtx): RuleResult;\n};\n\nconst blockRules: BlockRule[] = [\n // Headings: `# ` … `###### `\n ...[1, 2, 3, 4, 5, 6].map((lvl) => ({\n pattern: new RegExp(`^${\"#\".repeat(lvl)} $`),\n apply(ctx: TriggerCtx): RuleResult {\n // Delete the `#`s and the trailing space, then setBlockType.\n const drop = lvl + 1;\n for (let i = 0; i < drop; i++) ctx.dispatch({ t: \"deleteBackward\" });\n ctx.dispatch({ t: \"setBlockType\", payload: { type: `h${lvl}` } });\n return \"applied\";\n },\n })),\n // Unordered list: `- ` or `* `\n {\n pattern: /^[-*] $/,\n apply(ctx) {\n ctx.dispatch({ t: \"deleteBackward\" });\n ctx.dispatch({ t: \"deleteBackward\" });\n ctx.dispatch({ t: \"toggleList\", ordered: false });\n return \"applied\";\n },\n },\n // Ordered list: `1. `\n {\n pattern: /^1\\. $/,\n apply(ctx) {\n ctx.dispatch({ t: \"deleteBackward\" });\n ctx.dispatch({ t: \"deleteBackward\" });\n ctx.dispatch({ t: \"deleteBackward\" });\n ctx.dispatch({ t: \"toggleList\", ordered: true });\n return \"applied\";\n },\n },\n // Code block: ``` (followed by space)\n {\n pattern: /^``` $/,\n apply(ctx) {\n for (let i = 0; i < 4; i++) ctx.dispatch({ t: \"deleteBackward\" });\n ctx.dispatch({ t: \"setBlockType\", payload: { type: \"code\" } });\n return \"applied\";\n },\n },\n];\n\n/** Dispatch the given mark as toggle, by selecting the matched range and\n * applying then collapsing back. Used for inline rules like `**foo**`. */\nfunction applyInlineMark(\n ctx: TriggerCtx,\n mark: Mark,\n matchLen: number,\n innerLen: number,\n delimLen: number,\n): void {\n // Caret currently sits AFTER the closing delimiter. We want to:\n // 1. Delete the closing delimiter (delimLen chars)\n // 2. Select back from caret (after step 1) to (matchLen - delimLen) chars\n // before — which is the start of the inner text\n // 3. Toggle mark on selection\n // 4. Collapse caret to end of inner\n const sel = ctx.selStore.get();\n if (sel.kind !== \"caret\") return;\n const at = sel.at;\n const lastIdx = at.path.length - 1;\n const off = at.path[lastIdx] ?? 0;\n // Delete the closing delimiter chars after the inner content.\n for (let i = 0; i < delimLen; i++) ctx.dispatch({ t: \"deleteBackward\" });\n // Now caret is at offset `off - delimLen`. We want to select the inner\n // run [off - matchLen, off - delimLen).\n const innerEnd = off - delimLen;\n const innerStart = innerEnd - innerLen;\n if (innerStart < 0) return;\n const path = [...at.path];\n path[lastIdx] = innerStart;\n const startA = { blockId: at.blockId, path, offset: innerStart };\n path[lastIdx] = innerEnd;\n const endA = { blockId: at.blockId, path: [...path], offset: innerEnd };\n ctx.selStore.set({ kind: \"range\", anchor: startA, focus: endA });\n ctx.dispatch({ t: \"toggleMark\", mark });\n // Collapse caret to end. Also delete the OPENING delimiter that's still\n // sitting before the (now-marked) inner text.\n ctx.selStore.set(caret(endA));\n // Delete leading delimiter chars (they're at innerStart - delimLen).\n const newPath = [...at.path];\n newPath[lastIdx] = innerStart;\n ctx.selStore.set(caret({ blockId: at.blockId, path: newPath, offset: innerStart }));\n for (let i = 0; i < delimLen; i++) ctx.dispatch({ t: \"deleteBackward\" });\n // Caret now at innerStart - delimLen + innerLen (after marked text).\n const finalOff = innerStart - delimLen + innerLen;\n const finalPath = [...at.path];\n finalPath[lastIdx] = finalOff;\n ctx.selStore.set(\n caret({ blockId: at.blockId, path: finalPath, offset: finalOff }),\n );\n}\n\ntype InlineRule = {\n /** Closing trigger char that should fire the rule. */\n closer: string;\n /** Pattern matched against the run text up to and INCLUDING the just-\n * inserted `closer`. The first capture group is the inner text. */\n pattern: RegExp;\n delimLen: number;\n mark: Mark;\n};\n\nconst inlineRules: InlineRule[] = [\n // **bold**\n { closer: \"*\", pattern: /\\*\\*([^*\\n]+)\\*\\*$/, delimLen: 2, mark: \"b\" },\n // __bold__\n { closer: \"_\", pattern: /__([^_\\n]+)__$/, delimLen: 2, mark: \"b\" },\n // *italic* — match only after we've seen the closing single asterisk and\n // there isn't already a ** wrap around it.\n { closer: \"*\", pattern: /(?<!\\*)\\*([^*\\n]+)\\*$/, delimLen: 1, mark: \"i\" },\n // _italic_\n { closer: \"_\", pattern: /(?<!_)_([^_\\n]+)_$/, delimLen: 1, mark: \"i\" },\n // ~~strike~~\n { closer: \"~\", pattern: /~~([^~\\n]+)~~$/, delimLen: 2, mark: \"s\" },\n // `code`\n { closer: \"`\", pattern: /`([^`\\n]+)`$/, delimLen: 1, mark: \"code\" },\n];\n\nfunction getBlockPrefixUpToCaret(ctx: TriggerCtx): string | null {\n const sel = ctx.selStore.get();\n if (sel.kind !== \"caret\") return null;\n const at = sel.at;\n const block = ctx.docStore.get().byId.get(at.blockId);\n if (!block) return null;\n const rc = runsAt(block, at);\n if (!rc) return null;\n const off = at.path[at.path.length - 1] ?? 0;\n let s = \"\";\n let acc = 0;\n for (const r of rc.runs) {\n if (acc + r.text.length >= off) {\n s += r.text.slice(0, off - acc);\n break;\n }\n s += r.text;\n acc += r.text.length;\n }\n void runsLengthAt;\n return s;\n}\n\nfunction makeSpaceTrigger(): TriggerDef {\n return {\n match: \" \",\n open(ctx) {\n const prefix = getBlockPrefixUpToCaret(ctx);\n if (prefix === null) return null;\n for (const rule of blockRules) {\n if (rule.pattern.test(prefix)) {\n rule.apply(ctx);\n break;\n }\n }\n // Return null — no UI to open, manager stays inactive so subsequent\n // typing can fire other rules.\n return null;\n },\n };\n}\n\nfunction makeInlineTrigger(closer: string): TriggerDef {\n return {\n match: closer,\n open(ctx) {\n const prefix = getBlockPrefixUpToCaret(ctx);\n if (prefix === null) return null;\n for (const rule of inlineRules) {\n if (rule.closer !== closer) continue;\n const m = rule.pattern.exec(prefix);\n if (!m) continue;\n const inner = m[1] ?? \"\";\n if (inner.length === 0) continue;\n applyInlineMark(ctx, rule.mark, m[0]!.length, inner.length, rule.delimLen);\n break;\n }\n return null;\n },\n };\n}\n\n\nexport function mdShortcutsPlugin(): EditorPlugin {\n return {\n name: \"md-shortcuts\",\n triggers: [\n makeSpaceTrigger(),\n makeInlineTrigger(\"*\"),\n makeInlineTrigger(\"_\"),\n makeInlineTrigger(\"~\"),\n makeInlineTrigger(\"`\"),\n ],\n };\n}\n",
|
|
58
|
+
"// ---------------------------------------------------------------------------\n// CalendarView — non-editable atomic block. Renders one row per day,\n// labelled \"Wed, Apr 30\" style. The current calendar date (in the local\n// timezone) gets a `is-today` class so consumers can highlight it.\n//\n// `contenteditable=\"false\"` on the outer element makes the browser skip\n// the caret over the block; combined with isAtomic the editor treats\n// caret hits inside the calendar as side 0 / side 1 edges.\n// ---------------------------------------------------------------------------\n\nimport { _, div, span, view } from \"creo\";\nimport type { CalendarBlock, DateMarkerBlock } from \"../../model/types\";\n\nconst DAY_NAMES_LONG = [\n \"Sunday\",\n \"Monday\",\n \"Tuesday\",\n \"Wednesday\",\n \"Thursday\",\n \"Friday\",\n \"Saturday\",\n];\nconst DAY_NAMES_SHORT = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"];\nconst MONTH_NAMES_SHORT = [\n \"Jan\",\n \"Feb\",\n \"Mar\",\n \"Apr\",\n \"May\",\n \"Jun\",\n \"Jul\",\n \"Aug\",\n \"Sep\",\n \"Oct\",\n \"Nov\",\n \"Dec\",\n];\n\nfunction todayIso(): string {\n const d = new Date();\n return formatIso(d);\n}\n\nfunction formatIso(d: Date): string {\n const yyyy = d.getFullYear();\n const mm = String(d.getMonth() + 1).padStart(2, \"0\");\n const dd = String(d.getDate()).padStart(2, \"0\");\n return `${yyyy}-${mm}-${dd}`;\n}\n\nfunction parseIso(s: string): Date {\n // Treat the ISO date as a *local* date — using `new Date(s)` would\n // interpret it as UTC midnight which can shift the day by one in some\n // timezones.\n const [y, m, d] = s.split(\"-\").map(Number);\n return new Date(y ?? 1970, (m ?? 1) - 1, d ?? 1);\n}\n\nfunction addDays(d: Date, n: number): Date {\n const out = new Date(d);\n out.setDate(out.getDate() + n);\n return out;\n}\n\nexport const CalendarView = view<{ block: CalendarBlock }>(({ props }) => ({\n shouldUpdate(next) {\n return next.block !== props().block;\n },\n render() {\n const b = props().block;\n const start = parseIso(b.date);\n const today = todayIso();\n div(\n {\n \"data-block-id\": b.id,\n \"data-block-kind\": \"calendar\",\n // Atomic island — the browser places the caret around the block,\n // not inside it.\n contenteditable: \"false\",\n class: \"ce-block ce-calendar\",\n },\n () => {\n // Header line: month + year of the anchor day. Helps when the\n // calendar shows a span (e.g. last week of April + first of May).\n div({ class: \"ce-calendar-header\" }, () => {\n const m = MONTH_NAMES_SHORT[start.getMonth()];\n span({}, `${m ?? \"\"} ${start.getFullYear()}`);\n });\n // One row per day. Plain div per row; no `data-side` markers\n // needed because the generic atomicCodec falls back to \"halves\n // of the block\" hit-testing.\n for (let i = 0; i < b.days; i++) {\n const d = addDays(start, i);\n const iso = formatIso(d);\n const isToday = iso === today;\n const cls = isToday\n ? \"ce-calendar-row is-today\"\n : \"ce-calendar-row\";\n div({ class: cls, key: iso, \"data-iso\": iso }, () => {\n span({ class: \"ce-calendar-dow\" }, () => {\n const long = DAY_NAMES_LONG[d.getDay()];\n const short = DAY_NAMES_SHORT[d.getDay()];\n span({ \"aria-hidden\": \"true\" }, short ?? \"\");\n span({ class: \"ce-sr-only\" }, long ?? \"\");\n });\n span({ class: \"ce-calendar-date\" }, () => {\n const m = MONTH_NAMES_SHORT[d.getMonth()];\n span({}, `${m ?? \"\"} ${d.getDate()}`);\n });\n });\n }\n void _;\n },\n );\n },\n}));\n\n/**\n * DateMarkerView — slim non-editable atomic block that renders a single\n * \"Wednesday, 2 Sep.\" line. Used as a separator block in journal /\n * planner UX where the user writes editable paragraphs between days.\n */\nexport const DateMarkerView = view<{ block: DateMarkerBlock }>(({ props }) => ({\n shouldUpdate(next) {\n return next.block !== props().block;\n },\n render() {\n const b = props().block;\n const d = parseIso(b.date);\n const today = todayIso();\n const dow = DAY_NAMES_LONG[d.getDay()] ?? \"\";\n const month = MONTH_NAMES_SHORT[d.getMonth()] ?? \"\";\n const label = `${dow}, ${d.getDate()} ${month}.`;\n const cls =\n b.date === today ? \"ce-block ce-date-marker is-today\" : \"ce-block ce-date-marker\";\n div(\n {\n \"data-block-id\": b.id,\n \"data-block-kind\": \"date-marker\",\n \"data-iso\": b.date,\n contenteditable: \"false\",\n class: cls,\n },\n () => {\n span({}, label);\n void _;\n },\n );\n },\n}));\n\n// Re-exports useful for plugin consumers building related UI.\nexport const calendarHelpers = {\n todayIso,\n formatIso,\n parseIso,\n addDays,\n};\n",
|
|
59
|
+
"// ---------------------------------------------------------------------------\n// calendarPlugin — example \"non-editable\" plugin block. Demonstrates the\n// `isAtomic` BlockDef contract: a block whose only valid caret positions\n// are before / after the block, never inside.\n//\n// Consumers opt in:\n// import { calendarPlugin } from \"creo-edit\";\n// createEditor({ plugins: [calendarPlugin()] });\n//\n// Insert a calendar via the typed command shape:\n// editor.dispatch({\n// t: \"calendar.insert\",\n// payload: { date: \"2026-05-08\", days: 7 },\n// });\n//\n// The plugin also ships a slash-menu item (`calendarSlashItem`) that hosts\n// can append to their slash items list.\n// ---------------------------------------------------------------------------\n\nimport { newBlockId } from \"../../model/doc\";\nimport { insertBlocks } from \"../../commands/insertCommands\";\nimport type {\n Block,\n BlockSpec,\n CalendarBlock,\n DateMarkerBlock,\n} from \"../../model/types\";\nimport type {\n BlockDef,\n CommandCtx,\n CommandDef,\n EditorPlugin,\n} from \"../../plugin/types\";\nimport { CalendarView, DateMarkerView, calendarHelpers } from \"./view\";\nimport type { SlashItem } from \"../slash/items\";\nimport type { PublicView } from \"creo\";\n\ntype CalendarInsertPayload = { date?: string; days?: number };\n\nfunction clampDays(n: unknown): number {\n if (typeof n !== \"number\" || !Number.isFinite(n)) return 7;\n return Math.max(1, Math.min(31, Math.floor(n)));\n}\n\nfunction normalizedDate(s: unknown): string {\n if (typeof s === \"string\" && /^\\d{4}-\\d{2}-\\d{2}$/.test(s)) return s;\n return calendarHelpers.todayIso();\n}\n\nfunction runInsert(ctx: CommandCtx, p: CalendarInsertPayload | undefined): boolean {\n const date = normalizedDate(p?.date);\n const days = clampDays(p?.days);\n const block: BlockSpec = {\n id: newBlockId(),\n type: \"calendar\",\n date,\n days,\n };\n return insertBlocks(\n { docStore: ctx.docStore, selStore: ctx.selStore },\n [block],\n );\n}\n\nconst calendarDef: BlockDef<CalendarBlock> = {\n type: \"calendar\",\n view: CalendarView as PublicView<{ block: CalendarBlock; key?: string }, void>,\n isTextBearing: false,\n isAtomic: true,\n // anchorCodec omitted — Registry.install falls back to atomicCodec for\n // isAtomic blocks without an explicit codec.\n htmlCodec: {\n matchHTML: [\"div\"],\n parseHTML(el) {\n // Only claim <div> elements that explicitly identify themselves as a\n // calendar block — avoids collision with arbitrary divs.\n if (el.getAttribute(\"data-block-kind\") !== \"calendar\") return null;\n const date = normalizedDate(el.getAttribute(\"data-date\"));\n const days = clampDays(Number(el.getAttribute(\"data-days\")));\n return { id: newBlockId(), type: \"calendar\", date, days };\n },\n serializeHTML(b) {\n const cb = b as CalendarBlock;\n return `<div data-block-kind=\"calendar\" data-date=\"${cb.date}\" data-days=\"${cb.days}\"></div>`;\n },\n },\n serializeCodec: {\n serialize(b) {\n const cb = b as CalendarBlock;\n return { id: cb.id, type: \"calendar\", date: cb.date, days: cb.days };\n },\n deserialize(s, id) {\n const sb = s as { date?: string; days?: number };\n return {\n id,\n type: \"calendar\",\n date: normalizedDate(sb.date),\n days: clampDays(sb.days),\n } as BlockSpec;\n },\n },\n};\n\nfunction runDateMarkerInsert(ctx: CommandCtx, p: { date?: string } | undefined): boolean {\n const date = normalizedDate(p?.date);\n const block: BlockSpec = {\n id: newBlockId(),\n type: \"date-marker\",\n date,\n };\n return insertBlocks(\n { docStore: ctx.docStore, selStore: ctx.selStore },\n [block],\n );\n}\n\nconst dateMarkerDef: BlockDef<DateMarkerBlock> = {\n type: \"date-marker\",\n view: DateMarkerView as PublicView<{ block: DateMarkerBlock; key?: string }, void>,\n isTextBearing: false,\n isAtomic: true,\n htmlCodec: {\n matchHTML: [\"div\"],\n parseHTML(el) {\n if (el.getAttribute(\"data-block-kind\") !== \"date-marker\") return null;\n const date = normalizedDate(el.getAttribute(\"data-date\"));\n return { id: newBlockId(), type: \"date-marker\", date };\n },\n serializeHTML(b) {\n const dm = b as DateMarkerBlock;\n return `<div data-block-kind=\"date-marker\" data-date=\"${dm.date}\"></div>`;\n },\n },\n serializeCodec: {\n serialize(b) {\n const dm = b as DateMarkerBlock;\n return { id: dm.id, type: \"date-marker\", date: dm.date };\n },\n deserialize(s, id) {\n const sb = s as { date?: string };\n return {\n id,\n type: \"date-marker\",\n date: normalizedDate(sb.date),\n } as BlockSpec;\n },\n },\n};\n\nconst calendarCommands: CommandDef<unknown>[] = [\n {\n t: \"calendar.insert\",\n run: (ctx, p) => runInsert(ctx, (p ?? {}) as CalendarInsertPayload),\n },\n {\n t: \"dateMarker.insert\",\n run: (ctx, p) => runDateMarkerInsert(ctx, (p ?? {}) as { date?: string }),\n },\n];\n\n/** Slash-menu item — append to your slash items array to expose calendar\n * insertion at the `/` trigger. */\nexport const calendarSlashItem: SlashItem = {\n id: \"calendar\",\n title: \"Calendar\",\n description: \"Insert a non-editable calendar block\",\n keywords: [\"calendar\", \"date\", \"schedule\", \"week\"],\n run: (ctx) => ctx.dispatch({ t: \"calendar.insert\", payload: {} }),\n};\n\nexport function calendarPlugin(): EditorPlugin {\n return {\n name: \"calendar\",\n blocks: [\n calendarDef as BlockDef<Block>,\n dateMarkerDef as BlockDef<Block>,\n ],\n commands: calendarCommands,\n };\n}\n\nexport { CalendarView, DateMarkerView, calendarHelpers } from \"./view\";\n",
|
|
60
|
+
"// ---------------------------------------------------------------------------\n// infiniteScrollPlugin — load more blocks as the user scrolls toward an\n// edge of the editor's scroll container.\n//\n// The plugin is generic: it doesn't know what kind of blocks the host\n// wants to load. The host supplies `loadBefore` and/or `loadAfter`\n// callbacks; the plugin watches scroll position, throttles, and calls\n// the callback when the viewport gets close to an edge. On prepend the\n// plugin captures `scrollHeight + scrollTop` before the load and\n// re-applies the delta after the next frame so the user's view stays\n// anchored to whatever they were reading.\n//\n// Usage:\n//\n// createEditor({\n// plugins: [\n// infiniteScrollPlugin({\n// scrollContainer: () => document.querySelector(\".my-wrap\"),\n// loadAfter: (editor) => editor.appendBlocks(nextDay()),\n// loadBefore: (editor) => editor.prependBlocks(prevDay()),\n// }),\n// ],\n// });\n//\n// The callbacks should mutate the editor synchronously via\n// `editor.appendBlocks` / `editor.prependBlocks`. Async work is fine but\n// the scroll-anchoring window is one animation frame — keep mutations\n// synchronous when possible.\n// ---------------------------------------------------------------------------\n\nimport type { BlockId, DistOmit, BlockSpec, DocState, Selection } from \"../../model/types\";\nimport type { EditorPlugin } from \"../../plugin/types\";\n\n// Input shape mirrors the editor's BlockInsertInput — `id` optional so\n// the plugin can pass through specs without manufacturing ids itself.\ntype Input = DistOmit<BlockSpec, \"id\"> & { id?: BlockId };\n\n// The plugin reaches into the editor only via the public docStore /\n// selStore / appendBlocks / prependBlocks surface. We accept a minimal\n// shape so the plugin stays decoupled from `Editor` (avoiding a circular\n// import with createEditor.ts).\nexport type InfiniteScrollEditor = {\n docStore: { get: () => DocState; subscribe: (fn: () => void) => () => void };\n selStore: { get: () => Selection };\n appendBlocks: (specs: Input[]) => BlockId[];\n prependBlocks: (specs: Input[]) => BlockId[];\n};\n\nexport type InfiniteScrollOptions = {\n /**\n * The scrolling element to watch. Either an element, or a getter (the\n * element may not exist at editor-mount time). When omitted, the\n * plugin walks up from the editor root looking for the nearest\n * `overflow-y: auto|scroll` ancestor; falls back to `window`.\n */\n scrollContainer?: HTMLElement | (() => HTMLElement | null);\n /** Called when the user scrolls within `threshold` of the bottom. */\n loadAfter?: (editor: InfiniteScrollEditor) => void;\n /**\n * Called when the user scrolls within `threshold` of the top. The\n * plugin re-anchors `scrollTop` after the load so the viewport doesn't\n * jump.\n */\n loadBefore?: (editor: InfiniteScrollEditor) => void;\n /** Pixel distance from an edge that triggers a load. Default: 240. */\n threshold?: number;\n /**\n * Minimum gap between successive triggers in the SAME direction (ms).\n * Prevents back-to-back appends while the user is mid-flick. Default\n * 60ms — short enough to feel responsive while letting the renderer\n * commit a frame in between.\n */\n cooldownMs?: number;\n};\n\nconst DEFAULT_THRESHOLD = 240;\nconst DEFAULT_COOLDOWN = 60;\n\nfunction isWindowScroll(target: HTMLElement | Window): target is Window {\n return target === window;\n}\n\nfunction findScrollAncestor(start: HTMLElement): HTMLElement | Window {\n let cur: HTMLElement | null = start.parentElement;\n while (cur) {\n const cs = window.getComputedStyle(cur);\n const ov = cs.overflowY + cs.overflow;\n if (/(auto|scroll|overlay)/.test(ov)) return cur;\n cur = cur.parentElement;\n }\n return window;\n}\n\nfunction geometryOf(target: HTMLElement | Window): {\n scrollTop: number;\n scrollHeight: number;\n clientHeight: number;\n} {\n if (isWindowScroll(target)) {\n return {\n scrollTop: window.scrollY,\n scrollHeight: document.documentElement.scrollHeight,\n clientHeight: window.innerHeight,\n };\n }\n return {\n scrollTop: target.scrollTop,\n scrollHeight: target.scrollHeight,\n clientHeight: target.clientHeight,\n };\n}\n\nfunction setScrollTop(target: HTMLElement | Window, top: number): void {\n if (isWindowScroll(target)) window.scrollTo({ top });\n else target.scrollTop = top;\n}\n\n// Schedule `cb` to run after the editor's renderer has committed the\n// next batch of DOM mutations and the browser has performed a layout\n// pass. We use a microtask + a 0ms timeout instead of `rAF` because some\n// environments throttle rAF (background tabs, headless previews) — the\n// throttling gates rAF callbacks behind a focus event we never receive,\n// so the anchor adjustment never lands. The microtask drains creo's\n// scheduler; the setTimeout yields back to the event loop so layout\n// runs before we read scrollHeight.\nfunction afterCommit(cb: () => void): void {\n Promise.resolve().then(() => setTimeout(cb, 0));\n}\n\nexport function infiniteScrollPlugin(opts: InfiniteScrollOptions): EditorPlugin {\n const threshold = opts.threshold ?? DEFAULT_THRESHOLD;\n const cooldownMs = opts.cooldownMs ?? DEFAULT_COOLDOWN;\n\n return {\n name: \"infinite-scroll\",\n decorations: [\n // The plugin doesn't actually need a per-block decoration; we\n // hijack the decoration `mount` lifecycle to attach a single\n // window-level listener. `match` returns true only for the FIRST\n // block in the doc so we don't double-mount. A dedicated\n // \"editor lifecycle\" hook would be cleaner — flag for later.\n {\n id: \"infinite-scroll\",\n layer: \"absolute\",\n match: (b) => b !== null,\n mount(_block, blockEl, host, _handle) {\n // The decoration manager creates one host per (def, block).\n // We don't render any per-block UI — the plugin only needs a\n // SINGLE editor-level scroll listener. Hide every host so the\n // absolute-positioned deco containers don't overlay the\n // editor blocks and steal clicks.\n host.style.display = \"none\";\n host.style.pointerEvents = \"none\";\n\n // Only run the listener / setup ONCE per editor. Subsequent\n // matching blocks land here, hide their host (above), then\n // bail out before re-attaching listeners.\n const editorRoot = blockEl.closest(\n \"[data-creo-edit]\",\n ) as HTMLElement | null;\n if (!editorRoot) return;\n const FLAG = \"__creoInfiniteScrollMounted\";\n if ((editorRoot as unknown as Record<string, unknown>)[FLAG]) return;\n (editorRoot as unknown as Record<string, unknown>)[FLAG] = true;\n\n const editor = (\n editorRoot as unknown as { __creoEdit?: InfiniteScrollEditor }\n ).__creoEdit;\n if (!editor) return;\n\n const resolveContainer = (): HTMLElement | Window => {\n if (typeof opts.scrollContainer === \"function\") {\n const el = opts.scrollContainer();\n if (el) return el;\n } else if (opts.scrollContainer) {\n return opts.scrollContainer;\n }\n return findScrollAncestor(editorRoot);\n };\n\n let lastFiredAt = 0;\n let lastDir: \"up\" | \"down\" | null = null;\n let pendingPrependAnchor:\n | { container: HTMLElement | Window; height: number; top: number }\n | null = null;\n // True from the moment a prepend dispatches until its\n // scrollTop re-anchor has landed. While set, further\n // loadBefore fires are suppressed — without this gate,\n // scrollTop stays near 0 during the afterCommit window and\n // every scroll event triggers another prepend, ballooning the\n // doc and starving the renderer. (loadAfter is naturally\n // self-throttling: appending grows scrollHeight immediately,\n // so distFromBottom jumps past threshold without needing any\n // post-load adjustment.)\n let prependAdjustPending = false;\n\n // Scroll-event entry-point. Cooldown gates back-to-back\n // firings in the same direction during a single scroll\n // gesture. Each firing produces ONE doc mutation; the next\n // firing has to wait for either the scroll-direction to flip\n // or the cooldown to elapse — that's what keeps user input\n // (clicks, selection changes) from being starved by the\n // editor's renderPending flag during a load.\n const tryFire = (): void => {\n const sc = resolveContainer();\n const g = geometryOf(sc);\n const distFromBottom = g.scrollHeight - g.scrollTop - g.clientHeight;\n const now = Date.now();\n const cooldownOk = (dir: \"up\" | \"down\") =>\n lastDir !== dir || now - lastFiredAt > cooldownMs;\n if (opts.loadAfter && distFromBottom < threshold && cooldownOk(\"down\")) {\n lastDir = \"down\";\n lastFiredAt = now;\n opts.loadAfter(editor);\n return;\n }\n if (\n opts.loadBefore &&\n g.scrollTop < threshold &&\n cooldownOk(\"up\") &&\n !prependAdjustPending\n ) {\n lastDir = \"up\";\n lastFiredAt = now;\n prependAdjustPending = true;\n // Capture geometry BEFORE the load so we can re-anchor.\n pendingPrependAnchor = {\n container: sc,\n height: g.scrollHeight,\n top: g.scrollTop,\n };\n opts.loadBefore(editor);\n return;\n }\n };\n\n // After every doc change, if a prepend anchor was queued,\n // re-apply scrollTop on the next frame so the user's viewport\n // stays put. We subscribe to docStore (not the scroll event)\n // because the load may be async — we want to wait until the\n // doc actually grew before reading the new scrollHeight.\n const unsubDoc = editor.docStore.subscribe(() => {\n if (!pendingPrependAnchor) return;\n const anchor = pendingPrependAnchor;\n pendingPrependAnchor = null;\n // Two-frame defer: the first frame is when creo's renderer\n // commits the DOM mutation; we read scrollHeight on the\n // SECOND frame after layout has settled. A single rAF\n // measured the OLD height because our docStore subscriber\n // fires synchronously inside set() and our rAF callback\n // queued before creo's renderer ran.\n afterCommit(() => {\n const next = geometryOf(anchor.container);\n const delta = next.scrollHeight - anchor.height;\n if (delta !== 0) {\n setScrollTop(anchor.container, anchor.top + delta);\n }\n prependAdjustPending = false;\n });\n });\n\n const initialContainer = resolveContainer();\n // Listen on whichever container we resolved; if the host swaps\n // the container at runtime they should re-create the editor.\n const listenerTarget = initialContainer as\n | HTMLElement\n | (Window & typeof globalThis);\n const onScroll = (): void => tryFire();\n listenerTarget.addEventListener(\"scroll\", onScroll, { passive: true });\n\n // No mount-time auto-fill — that historically chained many\n // docStore.set events through the editor's renderPending\n // window and starved user `selectionchange` events. Hosts\n // should seed enough content up-front so the viewport\n // overflows at mount; further loads happen as the user\n // scrolls.\n\n return () => {\n listenerTarget.removeEventListener(\"scroll\", onScroll);\n unsubDoc();\n (editorRoot as unknown as Record<string, unknown>)[FLAG] = false;\n };\n },\n },\n ],\n };\n}\n",
|
|
61
|
+
"// ---------------------------------------------------------------------------\n// Search engine — iterate every text-bearing slot in the doc and emit\n// `SearchMatch` records. Anchor encoding mirrors model/types.ts:\n// - text-bearing (p/h*/li/code): path = [charOffset]\n// - table: path = [row, col, charOffset]\n// - columns: path = [colIndex, charOffset]\n// ---------------------------------------------------------------------------\n\nimport type { Anchor, Block, BlockId, DocState, InlineRun } from \"../../model/types\";\nimport { isTextBearing } from \"../../model/blockText\";\n\nexport type SearchMatch = {\n blockId: BlockId;\n start: Anchor;\n end: Anchor;\n /** Slice of the matched text — used for backend results that don't\n * resolve to a live block; engine results include it for parity. */\n snippet?: string;\n};\n\nexport type SearchOpts = {\n caseSensitive: boolean;\n wholeWord: boolean;\n regex: boolean;\n};\n\ntype Slot = {\n text: string;\n /** Anchor path prefix this slot belongs to. Concatenated with charOffset\n * to form the final anchor path. */\n prefix: number[];\n};\n\nfunction runsText(runs: InlineRun[]): string {\n let s = \"\";\n for (const r of runs) s += r.text;\n return s;\n}\n\n/** Yield every searchable text slot for a block, with the anchor prefix\n * needed to address positions inside it. Skips non-text blocks (img,\n * calendar, date-marker). */\nexport function* slotsOf(block: Block): Generator<Slot> {\n if (isTextBearing(block)) {\n yield { text: runsText(block.runs), prefix: [] };\n return;\n }\n if (block.type === \"table\") {\n for (let r = 0; r < block.rows; r++) {\n const row = block.cells[r];\n if (!row) continue;\n for (let c = 0; c < block.cols; c++) {\n const cell = row[c];\n if (!cell) continue;\n yield { text: runsText(cell), prefix: [r, c] };\n }\n }\n return;\n }\n if (block.type === \"columns\") {\n for (let c = 0; c < block.cols; c++) {\n const cell = block.cells[c];\n if (!cell) continue;\n yield { text: runsText(cell), prefix: [c] };\n }\n return;\n }\n // img / calendar / date-marker — no searchable text in v1.\n}\n\nfunction escapeRegex(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/** Build a sticky-global regex for the query + options. Throws if the user\n * supplied an invalid `regex: true` pattern — caller should catch and show\n * a UI error. */\nexport function buildMatcher(query: string, opts: SearchOpts): RegExp {\n let pattern: string;\n if (opts.regex) {\n pattern = query;\n } else {\n pattern = escapeRegex(query);\n }\n if (opts.wholeWord) {\n pattern = `(?:^|[^\\\\w])(${pattern})(?=[^\\\\w]|$)`;\n }\n const flags = opts.caseSensitive ? \"g\" : \"gi\";\n return new RegExp(pattern, flags);\n}\n\n/** Run the matcher over a single slot and emit matches. The wholeWord\n * wrapping captures the previous boundary char in group 0; we use the\n * first capture group's index to land on the actual match. */\nfunction* matchSlot(\n slot: Slot,\n blockId: BlockId,\n matcher: RegExp,\n wholeWord: boolean,\n): Generator<SearchMatch> {\n matcher.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = matcher.exec(slot.text)) !== null) {\n let startCh: number;\n let endCh: number;\n let matchedText: string;\n if (wholeWord && m[1] !== undefined) {\n // group 1 is the actual match; group 0 includes the leading boundary\n const groupOffset = m[0].indexOf(m[1]);\n startCh = m.index + groupOffset;\n matchedText = m[1];\n endCh = startCh + matchedText.length;\n // If the match is zero-width somehow, advance to avoid infinite loop.\n if (matchedText.length === 0) {\n matcher.lastIndex = m.index + 1;\n continue;\n }\n } else {\n startCh = m.index;\n matchedText = m[0];\n endCh = startCh + matchedText.length;\n if (matchedText.length === 0) {\n matcher.lastIndex = m.index + 1;\n continue;\n }\n }\n yield {\n blockId,\n start: {\n blockId,\n path: [...slot.prefix, startCh],\n offset: startCh,\n },\n end: {\n blockId,\n path: [...slot.prefix, endCh],\n offset: endCh,\n },\n snippet: matchedText,\n };\n }\n}\n\n/** Scan every block in the doc and return all matches, in document order. */\nexport function searchDoc(\n doc: DocState,\n query: string,\n opts: SearchOpts,\n): SearchMatch[] {\n if (query.length === 0) return [];\n let matcher: RegExp;\n try {\n matcher = buildMatcher(query, opts);\n } catch {\n return [];\n }\n const out: SearchMatch[] = [];\n for (const id of doc.order) {\n const block = doc.byId.get(id);\n if (!block) continue;\n for (const slot of slotsOf(block)) {\n if (slot.text.length === 0) continue;\n for (const m of matchSlot(slot, id, matcher, opts.wholeWord)) {\n out.push(m);\n }\n }\n }\n return out;\n}\n\n/** Stable key for dedupe across re-scans. */\nexport function matchKey(m: SearchMatch): string {\n return `${m.blockId}|${m.start.path.join(\",\")}|${m.end.path.join(\",\")}`;\n}\n",
|
|
62
|
+
"// ---------------------------------------------------------------------------\n// highlight.ts — paint search matches via the CSS Custom Highlight API.\n//\n// Two named highlights:\n// creo-search — every visible match (yellow-ish)\n// creo-search-current — only the active match (orange-ish)\n//\n// Matches in unmounted blocks (virtualized off-screen) are skipped — they\n// have no DOM. The MutationObserver in index.ts re-renders highlights when\n// VirtualDoc mounts/unmounts blocks, so a previously-skipped match lights\n// up as soon as its block scrolls into view.\n// ---------------------------------------------------------------------------\n\nimport { anchorToDom } from \"../../dom/anchorMap\";\nimport type { SearchMatch } from \"./engine\";\n\nexport const HL_ALL = \"creo-search\";\nexport const HL_CURRENT = \"creo-search-current\";\n\ntype HighlightCtor = new (...ranges: AbstractRange[]) => Highlight;\ntype HighlightRegistry = {\n set(name: string, value: Highlight): void;\n delete(name: string): void;\n get?(name: string): Highlight | undefined;\n};\ntype CSSWithHighlights = typeof CSS & {\n highlights?: HighlightRegistry;\n};\n\nexport function isHighlightApiSupported(): boolean {\n if (typeof CSS === \"undefined\") return false;\n return Boolean((CSS as CSSWithHighlights).highlights) && typeof (globalThis as { Highlight?: unknown }).Highlight === \"function\";\n}\n\nfunction buildRange(\n root: HTMLElement,\n match: SearchMatch,\n): Range | null {\n const a = anchorToDom(match.start, root);\n const b = anchorToDom(match.end, root);\n if (!a || !b) return null;\n try {\n const r = new Range();\n r.setStart(a.node, a.offset);\n r.setEnd(b.node, b.offset);\n return r;\n } catch {\n return null;\n }\n}\n\n/**\n * Sync the named highlights with the current match list and active index.\n *\n * Returns the number of matches that landed in DOM (i.e. mounted). The\n * caller can use it for diagnostics — e.g. if `0 < total`, some matches\n * are off-screen and waiting on virtualization to mount their blocks.\n */\nexport function paintHighlights(\n root: HTMLElement,\n matches: readonly SearchMatch[],\n activeIndex: number,\n): number {\n if (!isHighlightApiSupported()) return 0;\n const css = CSS as CSSWithHighlights;\n const highlights = css.highlights!;\n const Hi = (globalThis as unknown as { Highlight: HighlightCtor }).Highlight;\n\n const allRanges: Range[] = [];\n let currentRange: Range | null = null;\n let mounted = 0;\n for (let i = 0; i < matches.length; i++) {\n const m = matches[i]!;\n const r = buildRange(root, m);\n if (!r) continue;\n mounted++;\n if (i === activeIndex) currentRange = r;\n else allRanges.push(r);\n }\n // Always set the \"all\" highlight even if empty so prior matches clear.\n highlights.set(HL_ALL, new Hi(...allRanges));\n if (currentRange) {\n highlights.set(HL_CURRENT, new Hi(currentRange));\n } else {\n highlights.delete(HL_CURRENT);\n }\n return mounted;\n}\n\nexport function clearHighlights(): void {\n if (!isHighlightApiSupported()) return;\n const css = CSS as CSSWithHighlights;\n css.highlights!.delete(HL_ALL);\n css.highlights!.delete(HL_CURRENT);\n}\n",
|
|
63
|
+
"// ---------------------------------------------------------------------------\n// navigate.ts — next/prev navigation + scroll-into-view that handles\n// virtualized off-screen blocks AND hosts that lazily load chunks via\n// `source.ensureLoaded`.\n// ---------------------------------------------------------------------------\n\nimport type { BlockId, DocState } from \"../../model/types\";\nimport type { SearchMatch } from \"./engine\";\nimport type { SearchSource } from \"./types\";\n\nexport type EditorScrollHandle = {\n docStore: { get(): DocState };\n scrollToBlock(\n blockId: BlockId,\n opts?: { block?: \"start\" | \"center\" | \"end\" | \"nearest\"; behavior?: ScrollBehavior },\n ): void;\n};\n\nexport async function jumpToMatch(\n editor: EditorScrollHandle,\n match: SearchMatch,\n source?: SearchSource,\n): Promise<void> {\n const doc = editor.docStore.get();\n if (!doc.byId.has(match.blockId) && source?.ensureLoaded) {\n try {\n await source.ensureLoaded(match.blockId);\n } catch {\n // Host signaled it can't load — bail; UI stays put.\n return;\n }\n }\n // Instant jump — smooth scrolling between matches feels broken when the\n // user is rapidly cycling through results (Enter / Shift+Enter).\n editor.scrollToBlock(match.blockId, { block: \"center\", behavior: \"auto\" });\n}\n\nexport function nextIndex(current: number, total: number): number {\n if (total === 0) return -1;\n return (current + 1) % total;\n}\n\nexport function prevIndex(current: number, total: number): number {\n if (total === 0) return -1;\n return (current - 1 + total) % total;\n}\n",
|
|
64
|
+
"// ---------------------------------------------------------------------------\n// styles.ts — inject base CSS for the search panel + the named highlights.\n// Idempotent: re-injecting only updates the <style> contents, never adds\n// duplicates.\n// ---------------------------------------------------------------------------\n\nconst STYLE_ID = \"creo-search-styles\";\n\nconst CSS_TEXT = `\n::highlight(creo-search) {\n background-color: rgba(255, 220, 0, 0.45);\n color: inherit;\n}\n::highlight(creo-search-current) {\n background-color: rgba(255, 140, 0, 0.85);\n color: inherit;\n}\n\n.creo-search-panel {\n position: absolute;\n top: 8px;\n right: 8px;\n width: max-content;\n max-width: calc(100% - 16px);\n z-index: 100;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 8px;\n background: var(--creo-search-bg, #ffffff);\n color: var(--creo-search-fg, #1a1a1a);\n border: 1px solid var(--creo-search-border, rgba(0, 0, 0, 0.15));\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n font: 13px/1.2 -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n pointer-events: auto;\n}\n.creo-search-panel input.creo-search-input {\n appearance: none;\n border: 1px solid transparent;\n outline: none;\n background: var(--creo-search-input-bg, rgba(0, 0, 0, 0.04));\n border-radius: 4px;\n padding: 4px 8px;\n width: 200px;\n font: inherit;\n color: inherit;\n}\n.creo-search-panel input.creo-search-input.creo-search-error {\n border-color: rgba(220, 50, 50, 0.7);\n}\n.creo-search-panel .creo-search-count {\n font-variant-numeric: tabular-nums;\n opacity: 0.7;\n min-width: 56px;\n text-align: center;\n}\n.creo-search-panel button {\n appearance: none;\n border: none;\n background: transparent;\n color: inherit;\n width: 24px;\n height: 24px;\n border-radius: 4px;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font: inherit;\n padding: 0;\n}\n.creo-search-panel button:hover {\n background: rgba(0, 0, 0, 0.06);\n}\n.creo-search-panel button[aria-pressed=\"true\"] {\n background: rgba(0, 0, 0, 0.12);\n}\n.creo-search-panel button[disabled] {\n opacity: 0.4;\n cursor: default;\n}\n\n@media (prefers-color-scheme: dark) {\n .creo-search-panel {\n background: var(--creo-search-bg, #1f1f1f);\n color: var(--creo-search-fg, #f0f0f0);\n border-color: var(--creo-search-border, rgba(255, 255, 255, 0.15));\n }\n .creo-search-panel input.creo-search-input {\n background: var(--creo-search-input-bg, rgba(255, 255, 255, 0.08));\n }\n .creo-search-panel button:hover {\n background: rgba(255, 255, 255, 0.08);\n }\n .creo-search-panel button[aria-pressed=\"true\"] {\n background: rgba(255, 255, 255, 0.16);\n }\n}\n`;\n\nexport function ensureStylesInjected(): void {\n if (typeof document === \"undefined\") return;\n let el = document.getElementById(STYLE_ID) as HTMLStyleElement | null;\n if (!el) {\n el = document.createElement(\"style\");\n el.id = STYLE_ID;\n document.head.appendChild(el);\n }\n if (el.textContent !== CSS_TEXT) el.textContent = CSS_TEXT;\n}\n",
|
|
65
|
+
"// ---------------------------------------------------------------------------\n// Default search panel — plain DOM (no creo) so it doesn't fight the\n// editor's own selection plumbing or render scheduler.\n//\n// Floating top-right via `position: sticky` inside the decoration host.\n// Skipped entirely when the host supplies `opts.renderUI`.\n// ---------------------------------------------------------------------------\n\nimport type { SearchController, SearchOptions, SearchToggle } from \"./types\";\n\ntype ToggleSpec = {\n key: SearchToggle;\n label: string;\n title: string;\n};\n\nconst TOGGLES: ToggleSpec[] = [\n { key: \"caseSensitive\", label: \"Aa\", title: \"Match case\" },\n { key: \"wholeWord\", label: \"W\", title: \"Whole word\" },\n { key: \"regex\", label: \".*\", title: \"Regex\" },\n];\n\nexport function mountDefaultPanel(\n host: HTMLElement,\n controller: SearchController,\n options: SearchOptions,\n): () => void {\n const panel = document.createElement(\"div\");\n panel.className = \"creo-search-panel\";\n panel.setAttribute(\"role\", \"search\");\n // Stop edits/clicks inside the panel from reaching the editor.\n for (const evt of [\n \"keydown\",\n \"keyup\",\n \"keypress\",\n \"input\",\n \"beforeinput\",\n \"mousedown\",\n \"click\",\n \"pointerdown\",\n ] as const) {\n panel.addEventListener(evt, (e) => e.stopPropagation());\n }\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.className = \"creo-search-input\";\n input.placeholder = \"Find\";\n input.spellcheck = false;\n input.setAttribute(\"aria-label\", \"Find in document\");\n panel.appendChild(input);\n\n const count = document.createElement(\"span\");\n count.className = \"creo-search-count\";\n count.textContent = \"\";\n panel.appendChild(count);\n\n const prevBtn = document.createElement(\"button\");\n prevBtn.type = \"button\";\n prevBtn.title = \"Previous match (Shift+Enter)\";\n prevBtn.setAttribute(\"aria-label\", \"Previous match\");\n prevBtn.textContent = \"↑\";\n panel.appendChild(prevBtn);\n\n const nextBtn = document.createElement(\"button\");\n nextBtn.type = \"button\";\n nextBtn.title = \"Next match (Enter)\";\n nextBtn.setAttribute(\"aria-label\", \"Next match\");\n nextBtn.textContent = \"↓\";\n panel.appendChild(nextBtn);\n\n // Build toggle buttons only for those declared `show: true`.\n const toggleEls = new Map<SearchToggle, HTMLButtonElement>();\n for (const t of TOGGLES) {\n const cfg = options.toggles?.[t.key];\n if (!cfg?.show) continue;\n const b = document.createElement(\"button\");\n b.type = \"button\";\n b.title = t.title;\n b.setAttribute(\"aria-label\", t.title);\n b.setAttribute(\"aria-pressed\", \"false\");\n b.textContent = t.label;\n b.addEventListener(\"click\", () => {\n controller.setToggle(t.key, !controller.toggle(t.key));\n });\n panel.appendChild(b);\n toggleEls.set(t.key, b);\n }\n\n const close = document.createElement(\"button\");\n close.type = \"button\";\n close.title = \"Close (Esc)\";\n close.setAttribute(\"aria-label\", \"Close search\");\n close.textContent = \"×\";\n close.addEventListener(\"click\", () => controller.close());\n panel.appendChild(close);\n\n // Wiring -----------------------------------------------------------------\n\n input.addEventListener(\"input\", () => {\n controller.setQuery(input.value);\n });\n input.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Enter\") {\n e.preventDefault();\n if (e.shiftKey) controller.prev();\n else controller.next();\n } else if (e.key === \"Escape\") {\n e.preventDefault();\n controller.close();\n }\n });\n prevBtn.addEventListener(\"click\", () => controller.prev());\n nextBtn.addEventListener(\"click\", () => controller.next());\n\n host.appendChild(panel);\n\n const sync = () => {\n const s = controller.state();\n panel.style.display = s.isOpen ? \"\" : \"none\";\n if (input.value !== s.query) input.value = s.query;\n input.classList.toggle(\"creo-search-error\", Boolean(s.error));\n if (s.error) {\n input.title = s.error;\n } else {\n input.removeAttribute(\"title\");\n }\n if (s.matches.length === 0) {\n count.textContent = s.query ? \"0 / 0\" : \"\";\n } else {\n count.textContent = `${s.activeIndex + 1} / ${s.matches.length}`;\n }\n const noMatches = s.matches.length === 0;\n prevBtn.toggleAttribute(\"disabled\", noMatches);\n nextBtn.toggleAttribute(\"disabled\", noMatches);\n for (const [k, btn] of toggleEls) {\n const on = controller.toggle(k);\n btn.setAttribute(\"aria-pressed\", on ? \"true\" : \"false\");\n }\n if (s.isOpen && document.activeElement !== input) {\n // Only refocus on initial open (when value is empty or matches the\n // controller); otherwise let the user interact with the panel.\n // We refocus when isOpen flipped to true — track via a flag.\n }\n };\n\n let lastOpen = false;\n const onChange = () => {\n const open = controller.isOpen();\n if (open && !lastOpen) {\n // Just opened — focus + select existing query so re-opens are fast.\n // Defer to next frame so the panel is visible first.\n requestAnimationFrame(() => {\n input.focus();\n input.select();\n });\n }\n lastOpen = open;\n sync();\n };\n const unsub = controller.subscribe(onChange);\n sync();\n\n return () => {\n unsub();\n panel.remove();\n };\n}\n",
|
|
66
|
+
"// ---------------------------------------------------------------------------\n// searchPlugin — in-page find for the editor.\n//\n// Works as an optional plugin. When `interceptBrowserFind: true`, claims\n// `Mod+F` and prevents the browser's find UI from opening. Searches every\n// loaded block in `docStore` (including those virtualized off-screen),\n// highlights matches via the CSS Custom Highlight API, and scrolls the\n// active match into view — handing virtualized off-screen blocks to\n// `editor.scrollToBlock` so the height-index resolves the right Y.\n//\n// Hosts using `infiniteScrollPlugin` can supply `opts.source` so search\n// queries hit a backend; `source.ensureLoaded(blockId)` is called before\n// jump-to-match for blocks not currently in docStore.\n//\n// The default UI is a small floating panel, top-right of the editor. Hosts\n// can replace it by passing `opts.renderUI`.\n// ---------------------------------------------------------------------------\n\nimport type { Store } from \"creo\";\nimport type { BlockId, DocState, Selection } from \"../../model/types\";\nimport type { CommandCtx, EditorPlugin } from \"../../plugin/types\";\nimport { searchDoc, type SearchMatch, type SearchOpts } from \"./engine\";\nimport {\n clearHighlights,\n paintHighlights,\n} from \"./highlight\";\nimport { jumpToMatch, nextIndex, prevIndex } from \"./navigate\";\nimport { ensureStylesInjected } from \"./styles\";\nimport { mountDefaultPanel } from \"./ui\";\nimport type {\n SearchController,\n SearchOptions,\n SearchSource,\n SearchState,\n SearchToggle,\n} from \"./types\";\n\nexport type {\n SearchController,\n SearchOptions,\n SearchSource,\n SearchState,\n SearchToggle,\n} from \"./types\";\nexport type { SearchMatch, SearchOpts } from \"./engine\";\n\n// Internal — minimum surface from `__creoEdit` we depend on.\ntype EditorHandle = {\n docStore: Store<DocState>;\n selStore: Store<Selection>;\n scrollToBlock: (\n blockId: BlockId,\n opts?: { block?: \"start\" | \"center\" | \"end\" | \"nearest\"; behavior?: ScrollBehavior },\n ) => void;\n};\n\nconst ROOT_FLAG = \"__creoSearchMounted\";\nconst COMMAND_OPEN = \"search.open\";\nconst COMMAND_CLOSE = \"search.close\";\n\nexport function searchPlugin(opts: SearchOptions = {}): EditorPlugin {\n const debounceMs = opts.debounceMs ?? 80;\n\n // Per-editor state lives in a closure created at first mount. The\n // controller plus all DOM is stashed on `__creoEdit` via a side channel\n // so the keymap command can find it.\n type Wired = {\n controller: SearchController;\n open(): void;\n close(): void;\n };\n const wiredByRoot = new WeakMap<HTMLElement, Wired>();\n\n const findWiredFromCtx = (ctx: CommandCtx): Wired | null => {\n // The command has no direct DOM handle. Walk all editor roots and\n // find the one whose docStore identity matches. Cheap — there's\n // usually one editor on the page.\n const roots = document.querySelectorAll<HTMLElement>(\"[data-creo-edit]\");\n for (let i = 0; i < roots.length; i++) {\n const r = roots[i]!;\n const e = (r as unknown as { __creoEdit?: EditorHandle }).__creoEdit;\n if (e?.docStore === ctx.docStore) return wiredByRoot.get(r) ?? null;\n }\n return null;\n };\n\n return {\n name: \"search\",\n commands: [\n {\n t: COMMAND_OPEN,\n run(ctx) {\n const w = findWiredFromCtx(ctx);\n if (!w) return false;\n w.open();\n return true;\n },\n },\n {\n t: COMMAND_CLOSE,\n run(ctx) {\n const w = findWiredFromCtx(ctx);\n if (!w) return false;\n w.close();\n return true;\n },\n },\n ],\n keymap: opts.interceptBrowserFind\n ? [{ chord: \"Mod+F\", command: { t: COMMAND_OPEN } }]\n : [],\n decorations: [\n {\n id: \"search\",\n layer: \"absolute\",\n // Match the FIRST block only (so we don't double-mount). Same\n // pattern as infinite-scroll: `match` returns true for every\n // block but we guard the body with a per-root flag.\n match: (b) => b !== null,\n mount(_block, blockEl, host) {\n // The decoration manager creates one host per (def, block).\n // We don't render per-block UI; one editor-level panel is\n // enough. Hide every spare host.\n host.style.display = \"none\";\n host.style.pointerEvents = \"none\";\n\n const root = blockEl.closest(\n \"[data-creo-edit]\",\n ) as HTMLElement | null;\n if (!root) return;\n if ((root as unknown as Record<string, unknown>)[ROOT_FLAG]) return;\n (root as unknown as Record<string, unknown>)[ROOT_FLAG] = true;\n\n const editor = (root as unknown as { __creoEdit?: EditorHandle })\n .__creoEdit;\n if (!editor) {\n (root as unknown as Record<string, unknown>)[ROOT_FLAG] = false;\n return;\n }\n\n ensureStylesInjected();\n\n // ----- panel host (floating, sticky top-right) -----------------\n // The host is itself `position: sticky` and zero-height, so it\n // pins to the top of the viewport as long as the editor root is\n // in view (and slides back down when the editor scrolls past).\n // The panel inside is absolutely positioned relative to the\n // sticky host — that keeps the panel pinned without displacing\n // editor content.\n //\n // Earlier we made the host `position: absolute; height: 0`,\n // which broke sticky positioning entirely: a sticky child can\n // only stick within its containing block, and a zero-height\n // absolute box gives it nothing to stick to. The panel ended up\n // scrolling away with the editor content.\n const panelHost = document.createElement(\"div\");\n panelHost.className = \"creo-search-host\";\n panelHost.style.position = \"sticky\";\n panelHost.style.top = \"0\";\n panelHost.style.height = \"0\";\n panelHost.style.zIndex = \"100\";\n panelHost.style.pointerEvents = \"none\";\n // Children (the panel) re-enable pointer-events on themselves.\n // Prepend so the sticky edge is the top of the editor's content.\n if (root.firstChild) root.insertBefore(panelHost, root.firstChild);\n else root.appendChild(panelHost);\n\n // ----- state ---------------------------------------------------\n const initial = (k: SearchToggle): boolean =>\n Boolean(opts.toggles?.[k]?.initial);\n const state: SearchState = {\n isOpen: false,\n query: \"\",\n caseSensitive: initial(\"caseSensitive\"),\n wholeWord: initial(\"wholeWord\"),\n regex: initial(\"regex\"),\n matches: [],\n activeIndex: -1,\n error: null,\n };\n const subscribers = new Set<() => void>();\n const emit = () => {\n for (const fn of subscribers) fn();\n };\n\n // Stash the pre-open selection so Escape can restore it.\n let stashedSelection: Selection | null = null;\n\n // IME composition gate — pause re-scans while composing.\n let composing = false;\n const onCompStart = () => { composing = true; };\n const onCompEnd = () => {\n composing = false;\n scheduleRescan();\n };\n root.addEventListener(\"compositionstart\", onCompStart);\n root.addEventListener(\"compositionend\", onCompEnd);\n\n // ----- search execution ----------------------------------------\n let scanTimer: ReturnType<typeof setTimeout> | null = null;\n let scanSeq = 0;\n const runScan = async () => {\n if (composing) return;\n const seq = ++scanSeq;\n const q = state.query;\n const sopts: SearchOpts = {\n caseSensitive: state.caseSensitive,\n wholeWord: state.wholeWord,\n regex: state.regex,\n };\n if (q.length === 0) {\n state.matches = [];\n state.activeIndex = -1;\n state.error = null;\n repaint();\n emit();\n return;\n }\n // Validate regex up-front so the UI can show an error.\n if (sopts.regex) {\n try {\n new RegExp(q, sopts.caseSensitive ? \"g\" : \"gi\");\n state.error = null;\n } catch (e) {\n state.error = (e as Error).message;\n state.matches = [];\n state.activeIndex = -1;\n repaint();\n emit();\n return;\n }\n } else {\n state.error = null;\n }\n let matches: SearchMatch[];\n if (opts.source) {\n try {\n const r = await opts.source.search(q, sopts);\n if (seq !== scanSeq) return; // newer scan in flight\n matches = r;\n } catch (e) {\n state.error = (e as Error).message;\n state.matches = [];\n state.activeIndex = -1;\n repaint();\n emit();\n return;\n }\n } else {\n matches = searchDoc(editor.docStore.get(), q, sopts);\n }\n state.matches = matches;\n // Keep activeIndex on a sensible value across re-scans:\n // - empty: -1\n // - first scan: 0\n // - subsequent: clamp to range\n if (matches.length === 0) state.activeIndex = -1;\n else if (state.activeIndex < 0) state.activeIndex = 0;\n else if (state.activeIndex >= matches.length)\n state.activeIndex = matches.length - 1;\n repaint();\n emit();\n };\n const scheduleRescan = () => {\n if (scanTimer) clearTimeout(scanTimer);\n scanTimer = setTimeout(runScan, debounceMs);\n };\n\n // ----- highlighting --------------------------------------------\n const repaint = () => {\n if (!state.isOpen) {\n clearHighlights();\n return;\n }\n paintHighlights(root, state.matches, state.activeIndex);\n };\n\n // Re-paint when blocks mount/unmount via VirtualDoc — Range\n // construction needs the live DOM. childList on the root\n // catches block insertions; subtree-scoped to catch them\n // wherever they land (DocView swaps the inner container as a\n // unit on some renders).\n let mutTimer: ReturnType<typeof setTimeout> | null = null;\n const mo = new MutationObserver((records) => {\n // Cheap filter: only repaint if at least one mutated element\n // is (or contains) a block element.\n let touched = false;\n for (const r of records) {\n for (const n of Array.from(r.addedNodes).concat(\n Array.from(r.removedNodes),\n )) {\n if (\n n instanceof HTMLElement &&\n (n.hasAttribute(\"data-block-id\") ||\n n.querySelector?.(\"[data-block-id]\"))\n ) {\n touched = true;\n break;\n }\n }\n if (touched) break;\n }\n if (!touched) return;\n if (mutTimer) clearTimeout(mutTimer);\n mutTimer = setTimeout(repaint, 16);\n });\n mo.observe(root, { childList: true, subtree: true });\n\n // Re-scan on doc mutations (edits, infinite-scroll loads, undo).\n const unsubDoc = editor.docStore.subscribe(() => {\n if (!state.isOpen) return;\n scheduleRescan();\n });\n\n // ----- controller ----------------------------------------------\n const controller: SearchController = {\n state: () => ({ ...state, matches: state.matches }),\n isOpen: () => state.isOpen,\n open: () => {\n if (state.isOpen) {\n // Re-open while open: focus input via UI's subscriber.\n emit();\n return;\n }\n stashedSelection = editor.selStore.get();\n state.isOpen = true;\n // First open: kick off a scan if we have a query.\n if (state.query) scheduleRescan();\n else repaint();\n emit();\n },\n close: () => {\n if (!state.isOpen) return;\n state.isOpen = false;\n clearHighlights();\n if (stashedSelection) editor.selStore.set(stashedSelection);\n stashedSelection = null;\n emit();\n },\n toggleOpen: () => {\n if (state.isOpen) controller.close();\n else controller.open();\n },\n setQuery: (q) => {\n if (state.query === q) return;\n state.query = q;\n // Reset active index when the query changes meaningfully —\n // otherwise the user types one char and we keep \"match #5\"\n // even though the result list is entirely different.\n state.activeIndex = q.length === 0 ? -1 : 0;\n scheduleRescan();\n emit();\n },\n query: () => state.query,\n setToggle: (t, v) => {\n if (state[t] === v) return;\n state[t] = v;\n scheduleRescan();\n emit();\n },\n toggle: (t) => state[t],\n matches: () => state.matches,\n activeIndex: () => state.activeIndex,\n setActiveIndex: (i) => {\n if (state.activeIndex === i) return;\n state.activeIndex = i;\n repaint();\n emit();\n },\n next: () => {\n if (state.matches.length === 0) return;\n state.activeIndex = nextIndex(state.activeIndex, state.matches.length);\n const m = state.matches[state.activeIndex]!;\n void jumpToMatch(editor, m, opts.source);\n repaint();\n emit();\n },\n prev: () => {\n if (state.matches.length === 0) return;\n state.activeIndex = prevIndex(state.activeIndex, state.matches.length);\n const m = state.matches[state.activeIndex]!;\n void jumpToMatch(editor, m, opts.source);\n repaint();\n emit();\n },\n subscribe: (fn) => {\n subscribers.add(fn);\n return () => subscribers.delete(fn);\n },\n };\n\n // ----- UI ------------------------------------------------------\n let cleanupUI: () => void;\n if (opts.renderUI) {\n cleanupUI = opts.renderUI(controller, panelHost);\n } else {\n cleanupUI = mountDefaultPanel(panelHost, controller, opts);\n }\n\n wiredByRoot.set(root, {\n controller,\n open: controller.open,\n close: controller.close,\n });\n\n // ----- cleanup -------------------------------------------------\n return () => {\n cleanupUI();\n mo.disconnect();\n unsubDoc();\n if (scanTimer) clearTimeout(scanTimer);\n if (mutTimer) clearTimeout(mutTimer);\n clearHighlights();\n root.removeEventListener(\"compositionstart\", onCompStart);\n root.removeEventListener(\"compositionend\", onCompEnd);\n panelHost.remove();\n wiredByRoot.delete(root);\n (root as unknown as Record<string, unknown>)[ROOT_FLAG] = false;\n };\n },\n },\n ],\n };\n}\n",
|
|
67
|
+
"// ---------------------------------------------------------------------------\n// docToMarkdown — serialize a SerializedDoc to a markdown string.\n//\n// Coverage: paragraphs, headings (h1..h6), lists (bulleted + numbered, with\n// depth indentation), code blocks (fenced with lang), images, inline marks\n// (bold, italic, strike, code). Tables emit GFM table syntax. Columns\n// degrade to a `data-creo-columns` HTML block embedded in markdown.\n//\n// Round-trip fidelity is \"good enough\" — parsing the output via the docs\n// site's markdown converter restores the same block structure for the\n// covered shapes. Edge cases like nested marks adjacent to whitespace may\n// degrade to plainer text.\n// ---------------------------------------------------------------------------\n\nimport type { SerializedBlock, SerializedDoc, SerializedRun } from \"../createEditor\";\n\nconst MARK_OPEN: Record<string, string> = {\n b: \"**\",\n i: \"*\",\n s: \"~~\",\n code: \"`\",\n};\nconst MARK_CLOSE = MARK_OPEN;\nconst MARK_ORDER = [\"code\", \"b\", \"i\", \"s\"] as const;\n\nfunction runsToMarkdown(runs: SerializedRun[]): string {\n let out = \"\";\n for (const r of runs) {\n if (!r.marks || r.marks.length === 0) {\n out += escapeInline(r.text);\n continue;\n }\n const ordered = MARK_ORDER.filter((m) => r.marks!.includes(m));\n let s = escapeInline(r.text);\n // Inside-out wrap so the last marker closes first.\n for (const m of ordered.slice().reverse()) {\n s = `${MARK_OPEN[m]}${s}${MARK_CLOSE[m]}`;\n }\n out += s;\n }\n return out;\n}\n\nfunction escapeInline(s: string): string {\n // Lightweight: escape only the chars that would be parsed as syntax in\n // plain runs (`*`, `_`, `` ` ``, `~`, `\\`). Newlines stay raw.\n return s.replace(/([\\\\`*_~])/g, \"\\\\$1\");\n}\n\nfunction blockToMarkdown(\n block: SerializedBlock,\n state: { listKind: \"ul\" | \"ol\" | null; olCounter: number },\n): string {\n // Reset list counter when leaving a list.\n if (block.type !== \"li\" && state.listKind !== null) {\n state.listKind = null;\n state.olCounter = 0;\n }\n switch (block.type) {\n case \"p\":\n return runsToMarkdown(block.runs);\n case \"h1\":\n case \"h2\":\n case \"h3\":\n case \"h4\":\n case \"h5\":\n case \"h6\": {\n const level = Number(block.type.slice(1));\n return `${\"#\".repeat(level)} ${runsToMarkdown(block.runs)}`;\n }\n case \"li\": {\n const wantKind = block.ordered ? \"ol\" : \"ul\";\n if (state.listKind !== wantKind) {\n state.listKind = wantKind;\n state.olCounter = 0;\n }\n const depth = block.depth ?? 0;\n const indent = \" \".repeat(depth);\n const marker = block.ordered ? `${++state.olCounter}.` : \"-\";\n return `${indent}${marker} ${runsToMarkdown(block.runs)}`;\n }\n case \"code\": {\n const lang = block.lang ? block.lang : \"\";\n const text = block.runs.map((r) => r.text).join(\"\");\n return \"```\" + lang + \"\\n\" + text + \"\\n```\";\n }\n case \"img\": {\n const alt = block.alt ?? \"\";\n return ``;\n }\n case \"table\": {\n const rows = block.cells;\n if (rows.length === 0) return \"\";\n const headerCells = (rows[0] ?? []).map((cell) => runsToMarkdown(cell));\n const sep = headerCells.map(() => \"---\");\n const lines: string[] = [];\n lines.push(`| ${headerCells.join(\" | \")} |`);\n lines.push(`| ${sep.join(\" | \")} |`);\n for (let r = 1; r < rows.length; r++) {\n const row = rows[r] ?? [];\n lines.push(`| ${row.map((c) => runsToMarkdown(c)).join(\" | \")} |`);\n }\n return lines.join(\"\\n\");\n }\n case \"columns\": {\n // No standard markdown for columns — fall back to an HTML-in-markdown\n // marker that the parser recognises on the way back.\n const inner = block.cells\n .map((cell, c) => `<div data-col=\"${c}\">${runsToMarkdown(cell)}</div>`)\n .join(\"\");\n return `<div data-creo-columns=\"${block.cols}\">${inner}</div>`;\n }\n case \"calendar\": {\n // Atomic block — no native markdown form; serialize as an HTML stub\n // so the parser can round-trip via its `data-block-kind` matcher.\n return `<div data-block-kind=\"calendar\" data-date=\"${block.date}\" data-days=\"${block.days}\"></div>`;\n }\n case \"date-marker\": {\n return `<div data-block-kind=\"date-marker\" data-date=\"${block.date}\"></div>`;\n }\n }\n}\n\nexport function docToMarkdown(doc: SerializedDoc): string {\n const lines: string[] = [];\n const state = { listKind: null as \"ul\" | \"ol\" | null, olCounter: 0 };\n for (const b of doc.blocks) {\n const md = blockToMarkdown(b, state);\n if (md.length > 0) lines.push(md);\n }\n return lines.join(\"\\n\\n\") + \"\\n\";\n}\n"
|
|
68
|
+
],
|
|
69
|
+
"mappings": "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",
|
|
70
|
+
"debugId": "1EDD33F5E0A7F33F64756E2164756E21",
|
|
71
|
+
"names": []
|
|
72
|
+
}
|