{"version":3,"file":"use-insert-markdown-BWJniE62.mjs","names":["useCallback","useLexicalComposerContext","getNodeExtensions","$insertMarkdownSnippet","useInsertMarkdown","$","_c","editor","t0","text","update","onUpdate","focus","_c","TextEditorSlots","defineRenderSlot","registry","createSourcedRegistry","tokenExtension","spec","source","editor","extensions","lines","root","$getRoot","para","$isElementNode","buf","child","$isLineBreakNode","$isTextNode","handled","ext","result","$tokenizedLineNodes","line","focused","carried","markdown","$createParagraphNode","node","len","SKIP_DOM_SELECTION_TAG","selection","$getSelection","$isRangeSelection","start","end","paragraphs","lineStart","total","point","base","children","within","i","snippet","s","acc","rem","offset","lastPara","lineLen","anchor","focus","$createRangeSelection","$setSelection","$","c","useLexicalComposerContext","text"],"sources":["../../../../../__A__/dev/singularity/.claude/worktrees/att-1794541508-7vtgpd/plugins/primitives/plugins/text-editor/web/slots.ts","../../../../../__A__/dev/singularity/.claude/worktrees/att-1794541508-7vtgpd/plugins/primitives/plugins/text-editor/web/internal/node-extensions.ts","../../../../../__A__/dev/singularity/.claude/worktrees/att-1794541508-7vtgpd/plugins/primitives/plugins/text-editor/web/internal/markdown.ts","../../../../../__A__/dev/singularity/.claude/worktrees/att-1794541508-7vtgpd/plugins/primitives/plugins/text-editor/web/internal/use-insert-markdown.ts"],"sourcesContent":["import { type ComponentType } from \"react\";\nimport { defineRenderSlot } from \"@plugins/primitives/plugins/slot-render/web\";\n\nexport interface TextEditorPluginProps {\n onError?: (msg: string) => void;\n}\n\nexport const TextEditorSlots = {\n Plugin: defineRenderSlot<{\n component: ComponentType;\n }>(),\n};\n","import {\n createSourcedRegistry,\n tokenExtension,\n type InlineTokenExtension,\n type InlineTokenNodeRef,\n} from \"@plugins/primitives/plugins/text-editor/plugins/token-extension/core\";\n\n/**\n * An inline token family this editor knows about.\n *\n * This editor's name for the shared {@link InlineTokenExtension}: one type,\n * one line scan and one (de)serialization derivation across every Lexical host\n * in the app. The trio that used to be written by hand here — `serializeNode`,\n * `deserializePattern`, `createNodeFromMatch` — is derived from the node\n * declaration, so a serializer that disagrees with its parser is unspellable.\n */\nexport type NodeExtension = InlineTokenExtension;\n\nconst registry = createSourcedRegistry();\n\n/**\n * Register an inline token family. Returns its unregister.\n *\n * Takes the field-erased {@link InlineTokenNodeRef}, which every family's typed\n * `InlineTokenNode` already is — so a contributor passes its own descriptor\n * straight in and the registry stores one type, with no cast between them.\n */\nexport function registerNodeExtension(spec: {\n id: string;\n node: InlineTokenNodeRef;\n pattern: RegExp;\n}): () => void {\n return registry.register(tokenExtension(spec));\n}\n\n/**\n * Register a LOOKUP for a set of families that is not yet knowable — the escape\n * hatch for a plugin whose token set is itself a registry (active-data's inline\n * chips, which register progressively as the plugin tiers load).\n *\n * This replaced a `NodeExtensions` SLOT, whose contributions could only be read\n * through a React hook. That confined the editor's extension set to render, and\n * mirroring the same idea into the page editor was impossible — its registry\n * readers are headless. A source is readable from both.\n */\nexport function registerNodeExtensionSource(\n source: () => readonly NodeExtension[],\n): () => void {\n return registry.registerSource(source);\n}\n\n/**\n * Every registered family, sources expanded.\n *\n * Read at CALL time, never memoized: extensions and sources register during\n * plugin load, and a snapshot taken too early silently under-reports — the\n * token then renders as plain characters with nothing failing.\n */\nexport function getNodeExtensions(): readonly NodeExtension[] {\n return registry.all();\n}\n","import {\n $getRoot,\n $getSelection,\n $isElementNode,\n $isLineBreakNode,\n $isRangeSelection,\n $isTextNode,\n $createParagraphNode,\n $createRangeSelection,\n $setSelection,\n SKIP_DOM_SELECTION_TAG,\n type ElementNode,\n type LexicalEditor,\n type LexicalNode,\n type PointType,\n} from \"lexical\";\nimport { hasToken } from \"@plugins/primitives/plugins/text-editor/plugins/token-extension/core\";\nimport {\n $insertTokenizedText,\n $tokenizedLineNodes,\n} from \"@plugins/primitives/plugins/text-editor/plugins/token-extension/plugins/node/core\";\nimport { getNodeExtensions, type NodeExtension } from \"./node-extensions\";\n\nexport function serializeEditorToMarkdown(\n editor: LexicalEditor,\n extensions: readonly NodeExtension[] = getNodeExtensions(),\n): string {\n return editor\n .getEditorState()\n .read(() => $serializeRootToMarkdown(extensions));\n}\n\n// The serializer body, for a caller already inside an `editor.update()` /\n// `read()` — it sees that update's pending state, not the last committed one.\nexport function $serializeRootToMarkdown(\n extensions: readonly NodeExtension[] = getNodeExtensions(),\n): string {\n const lines: string[] = [];\n const root = $getRoot();\n for (const para of root.getChildren()) {\n if (!$isElementNode(para)) continue;\n let buf = \"\";\n for (const child of para.getChildren()) {\n if ($isLineBreakNode(child)) {\n buf += \"\\n\";\n } else if ($isTextNode(child)) {\n buf += child.getTextContent();\n } else {\n let handled = false;\n for (const ext of extensions) {\n const result = ext.serializeNode(child);\n if (result !== null) {\n buf += result;\n handled = true;\n break;\n }\n }\n if (!handled) buf += child.getTextContent();\n }\n }\n lines.push(buf);\n }\n return lines.join(\"\\n\");\n}\n\n// Deserialize one raw source line into Lexical nodes: every extension pattern\n// (``, image markdown, …) becomes its node, the rest stays text.\n// The single deserialization path — shared by the whole-value apply below and\n// the caret insert — so a snippet dropped at the cursor yields the same nodes\n// as the same snippet arriving through the value round-trip.\n//\n// The scan itself is the shared one (`token-extension`), so this editor and the\n// page editor agree byte-for-byte about where a token starts and which of two\n// overlapping candidates wins.\nfunction $lineToNodes(\n line: string,\n extensions: readonly NodeExtension[],\n): LexicalNode[] {\n return $tokenizedLineNodes(line, extensions);\n}\n\n// Does this raw snippet carry at least one node-extension token? The gate the\n// paste path uses to decide between \"deserialize into nodes\" and \"let the\n// editor insert it as plain text\" — same registry, same patterns as\n// `$lineToNodes`, so the two can never disagree about what is a token.\nexport function hasNodeExtensionToken(\n text: string,\n extensions: readonly NodeExtension[] = getNodeExtensions(),\n): boolean {\n return hasToken(text, extensions);\n}\n\nexport function applyMarkdownToEditor(\n editor: LexicalEditor,\n markdown: string,\n extensions: readonly NodeExtension[] = getNodeExtensions(),\n): void {\n // The rebuild below replaces every node in the document, which destroys the\n // selection — Lexical then parks the caret at the START of the new document.\n // That caret is a lie: it is not where the user was, and everything that acts\n // \"at the caret\" afterwards (typing, a template chip, a picked ui-context)\n // acts at the top of the draft and drags the viewport there with it. So the\n // caret is carried across the rebuild as raw-source offsets — the same\n // coordinate system `value` itself is in, and therefore the only one that\n // survives a re-serialization.\n const focused =\n editor.getRootElement() !== null &&\n editor.getRootElement() === document.activeElement;\n editor.update(\n () => {\n const carried = $captureCaret(extensions);\n const root = $getRoot();\n root.clear();\n const lines = markdown.split(\"\\n\");\n for (const line of lines) {\n const para = $createParagraphNode();\n for (const node of $lineToNodes(line, extensions)) para.append(node);\n root.append(para);\n }\n if (root.getChildrenSize() === 0) {\n root.append($createParagraphNode());\n }\n if (carried) {\n const len = markdown.length;\n $selectMarkdownRange(\n Math.min(carried.start, len),\n Math.min(carried.end, len),\n extensions,\n );\n } else {\n // Nothing to carry — this is a restore into an editor the user has not\n // put a caret in. The end of the restored text is where a draft is\n // continued, and it is what makes an insert land where the user is\n // reading rather than at the top.\n $getRoot().selectEnd();\n }\n },\n // An unfocused editor must not pull the browser's selection out of whatever\n // the user IS focused on: the editor-state caret above still points at the\n // end (so an insert appends there), but the DOM is left alone.\n focused ? undefined : { tag: SKIP_DOM_SELECTION_TAG },\n );\n}\n\n/**\n * The caret to carry across a whole-document rebuild, as raw-source offsets.\n *\n * `null` means \"there is no caret worth carrying\" — an empty document (the\n * caret Lexical parks in the placeholder paragraph is not a position the user\n * chose) or a point this module's flat paragraph/leaf shape cannot address.\n * Both are legitimate: the caller's answer for both is the same, and it is the\n * documented default (end of document), not a silent failure.\n */\nfunction $captureCaret(\n extensions: readonly NodeExtension[],\n): { start: number; end: number } | null {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return null;\n if ($getRoot().getTextContentSize() === 0) return null;\n const start = $rawOffsetOfPoint(selection.anchor, extensions);\n const end = $rawOffsetOfPoint(selection.focus, extensions);\n if (start === null || end === null) return null;\n return { start, end };\n}\n\n/** Raw-source character offset of a Lexical point — the inverse of `locatePoint`. */\nfunction $rawOffsetOfPoint(\n point: PointType,\n extensions: readonly NodeExtension[],\n): number | null {\n const root = $getRoot();\n const paragraphs = root.getChildren();\n\n // Where each top-level line starts in the raw string (+1 for its \"\\n\").\n const lineStart = new Map();\n let total = 0;\n for (const para of paragraphs) {\n lineStart.set(para.getKey(), total);\n total += rawLineLength(para, extensions) + 1;\n }\n\n const node = point.getNode();\n if (node.getKey() === root.getKey()) {\n const index = Math.min(point.offset, paragraphs.length);\n const para = paragraphs[index];\n if (!para) return Math.max(0, total - 1);\n return lineStart.get(para.getKey()) ?? null;\n }\n\n const para = point.type === \"text\" ? node.getParent() : node;\n if (para === null || !$isElementNode(para)) return null;\n const base = lineStart.get(para.getKey());\n if (base === undefined) return null;\n\n const children = para.getChildren();\n if (point.type === \"text\") {\n let within = 0;\n for (const child of children) {\n if (child.getKey() === node.getKey()) return base + within + point.offset;\n within += rawNodeLength(child, extensions);\n }\n return null;\n }\n let within = 0;\n for (let i = 0; i < Math.min(point.offset, children.length); i++) {\n within += rawNodeLength(children[i]!, extensions);\n }\n return base + within;\n}\n\n// Insert a raw markdown snippet at the caret, deserialized through the node\n// extensions (so e.g. a `` tag lands as its chip, not as literal\n// text). With no live selection — the editor was never focused — the snippet\n// appends at the end of the document. Must run inside an `editor.update()`.\nexport function $insertMarkdownSnippet(\n snippet: string,\n extensions: readonly NodeExtension[] = getNodeExtensions(),\n): void {\n $insertTokenizedText(snippet, extensions);\n}\n\n// --- Selection mapping ------------------------------------------------------\n// Map a character offset in the raw markdown `value` back to a Lexical point.\n// This is the inverse of `applyMarkdownToEditor`: one paragraph per line,\n// extension (decorator) nodes occupy exactly their serialized-token length, so\n// offsets stay aligned with the source string the editor was built from.\n\ntype LexicalPoint = { key: string; offset: number; type: \"text\" | \"element\" };\n\n// Raw-source length a node contributes (must mirror serializeEditorToMarkdown).\nfunction rawNodeLength(\n node: LexicalNode,\n extensions: readonly NodeExtension[],\n): number {\n if ($isLineBreakNode(node)) return 1;\n if ($isTextNode(node)) return node.getTextContent().length;\n for (const ext of extensions) {\n const s = ext.serializeNode(node);\n if (s !== null) return s.length;\n }\n return node.getTextContent().length;\n}\n\n// Raw-source length of one top-level line (its children, no trailing \"\\n\").\nfunction rawLineLength(\n para: LexicalNode,\n extensions: readonly NodeExtension[],\n): number {\n if (!$isElementNode(para)) return rawNodeLength(para, extensions);\n return para\n .getChildren()\n .reduce((acc, child) => acc + rawNodeLength(child, extensions), 0);\n}\n\n// Resolve an offset within a single paragraph to a Lexical point. Text nodes\n// resolve to an exact intra-text offset; decorator nodes snap to the element\n// boundary before/after the node (you can't place a caret inside an image).\nfunction pointInParagraph(\n para: ElementNode,\n offset: number,\n extensions: readonly NodeExtension[],\n): LexicalPoint {\n const children = para.getChildren();\n let rem = offset;\n for (let i = 0; i < children.length; i++) {\n const child = children[i]!;\n if ($isTextNode(child)) {\n const len = child.getTextContent().length;\n if (rem <= len) return { key: child.getKey(), offset: rem, type: \"text\" };\n rem -= len;\n } else {\n const len = rawNodeLength(child, extensions);\n if (rem <= 0) return { key: para.getKey(), offset: i, type: \"element\" };\n if (rem < len)\n return { key: para.getKey(), offset: i + 1, type: \"element\" };\n rem -= len;\n }\n }\n return { key: para.getKey(), offset: children.length, type: \"element\" };\n}\n\nfunction locatePoint(\n paragraphs: LexicalNode[],\n offset: number,\n extensions: readonly NodeExtension[],\n): LexicalPoint | null {\n let rem = offset;\n let lastPara: ElementNode | null = null;\n for (const para of paragraphs) {\n if (!$isElementNode(para)) continue;\n lastPara = para;\n const lineLen = rawLineLength(para, extensions);\n if (rem <= lineLen) return pointInParagraph(para, rem, extensions);\n rem -= lineLen + 1; // consume the line plus its trailing \"\\n\" separator\n }\n if (!lastPara) return null;\n return pointInParagraph(\n lastPara,\n rawLineLength(lastPara, extensions),\n extensions,\n );\n}\n\n// Set the editor selection to the raw-string character range [start, end].\n// Must run inside an `editor.update()` (Lexical \"$\" convention).\nexport function $selectMarkdownRange(\n start: number,\n end: number,\n extensions: readonly NodeExtension[] = getNodeExtensions(),\n): void {\n const paragraphs = $getRoot().getChildren();\n const anchor = locatePoint(paragraphs, start, extensions);\n const focus = locatePoint(paragraphs, end, extensions);\n if (!anchor || !focus) return;\n const selection = $createRangeSelection();\n selection.anchor.set(anchor.key, anchor.offset, anchor.type);\n selection.focus.set(focus.key, focus.offset, focus.type);\n $setSelection(selection);\n}\n\nexport function clearEditor(editor: LexicalEditor): void {\n editor.update(() => {\n const root = $getRoot();\n root.clear();\n root.append($createParagraphNode());\n });\n}\n","import { useCallback } from \"react\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport { getNodeExtensions } from \"./node-extensions\";\nimport { $insertMarkdownSnippet } from \"./markdown\";\n\n/**\n * THE way to drop a raw markdown snippet into the editor at the caret.\n *\n * Every entry point routes through here so a snippet behaves identically\n * wherever it comes from: newlines become real line breaks (not literal \"\\n\"\n * inside a text node, whose caret rect the browser cannot place — which is what\n * makes the viewport jump), extension tokens deserialize into their nodes, and\n * with no live caret the snippet appends at the end instead of at the top.\n *\n * Must be called inside a `LexicalComposer` (the editor's own subtree).\n */\nexport function useInsertMarkdown(): (text: string) => void {\n const [editor] = useLexicalComposerContext();\n return useCallback(\n (text: string) => {\n editor.update(\n () => {\n // Read at insert time, not at render: the registry folds in lazy\n // sources, so the set an early render would have captured can still\n // be missing families that registered since.\n $insertMarkdownSnippet(text, getNodeExtensions());\n },\n // The caret belongs in the editor after an insert, whichever affordance\n // did the inserting — a toolbar chip, a picker, a dictation button.\n { onUpdate: () => editor.focus() },\n );\n },\n [editor],\n );\n}\n"],"mappings":"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"}