@relevaince/mentions 0.2.0 → 0.2.1

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/dist/index.js CHANGED
@@ -44,6 +44,7 @@ var import_react6 = require("@tiptap/react");
44
44
  var import_react = require("react");
45
45
  var import_react2 = require("@tiptap/react");
46
46
  var import_starter_kit = __toESM(require("@tiptap/starter-kit"));
47
+ var import_extension_placeholder = __toESM(require("@tiptap/extension-placeholder"));
47
48
  var import_core3 = require("@tiptap/core");
48
49
 
49
50
  // src/core/mentionExtension.ts
@@ -465,6 +466,9 @@ function useMentionsEditor({
465
466
  listItem: false,
466
467
  horizontalRule: false
467
468
  }),
469
+ import_extension_placeholder.default.configure({
470
+ placeholder: placeholder ?? "Type a message..."
471
+ }),
468
472
  MentionNode,
469
473
  suggestionExtension,
470
474
  submitExt,
@@ -475,7 +479,6 @@ function useMentionsEditor({
475
479
  editable,
476
480
  editorProps: {
477
481
  attributes: {
478
- "data-placeholder": placeholder ?? "",
479
482
  class: "mentions-editor"
480
483
  }
481
484
  },
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/components/MentionsInput.tsx","../src/hooks/useMentionsEditor.ts","../src/core/mentionExtension.ts","../src/core/suggestionPlugin.ts","../src/core/markdownSerializer.ts","../src/core/markdownParser.ts","../src/hooks/useSuggestion.ts","../src/components/SuggestionList.tsx","../src/utils/ariaHelpers.ts"],"sourcesContent":["/* ------------------------------------------------------------------ */\n/* Components */\n/* ------------------------------------------------------------------ */\nexport { MentionsInput } from \"./components/MentionsInput\";\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\nexport type { MentionToken } from \"./types/MentionToken\";\nexport type {\n MentionProvider,\n MentionItem,\n} from \"./types/MentionProvider\";\nexport type { MentionsOutput } from \"./types/MentionsOutput\";\nexport type {\n MentionsInputProps,\n MentionsInputHandle,\n} from \"./types/MentionsInputProps\";\n\n/* ------------------------------------------------------------------ */\n/* Utilities */\n/* ------------------------------------------------------------------ */\nexport { serializeToMarkdown } from \"./core/markdownSerializer\";\nexport { parseFromMarkdown } from \"./core/markdownParser\";\n","import React, { forwardRef, useCallback, useImperativeHandle } from \"react\";\nimport { EditorContent } from \"@tiptap/react\";\nimport { useMentionsEditor } from \"../hooks/useMentionsEditor\";\nimport { useSuggestion } from \"../hooks/useSuggestion\";\nimport { SuggestionList } from \"./SuggestionList\";\nimport { comboboxAttrs } from \"../utils/ariaHelpers\";\nimport type {\n MentionsInputProps,\n MentionsInputHandle,\n} from \"../types/MentionsInputProps\";\n\nconst LISTBOX_ID = \"mentions-suggestion-listbox\";\n\n/**\n * `<MentionsInput>` — the single public component.\n *\n * A structured text editor with typed entity tokens.\n * Consumers register `providers` for each trigger character,\n * and receive structured output via `onChange` and `onSubmit`.\n *\n * Supports an imperative ref handle for programmatic control:\n * ```tsx\n * const ref = useRef<MentionsInputHandle>(null);\n * ref.current.clear();\n * ref.current.setContent(\"@[Marketing](ws_123) summarize\");\n * ref.current.focus();\n * ```\n */\nexport const MentionsInput = forwardRef<MentionsInputHandle, MentionsInputProps>(\n function MentionsInput(\n {\n value,\n providers,\n onChange,\n placeholder = \"Type a message...\",\n autoFocus = false,\n disabled = false,\n className,\n onSubmit,\n clearOnSubmit = true,\n maxLength,\n renderItem,\n renderChip,\n },\n ref,\n ) {\n const { uiState, actions, callbacksRef } = useSuggestion(providers);\n\n const { editor, clear, setContent, focus } = useMentionsEditor({\n providers,\n value,\n onChange,\n onSubmit,\n clearOnSubmit,\n placeholder,\n autoFocus,\n editable: !disabled,\n callbacksRef,\n });\n\n /* ---------------------------------------------------------------- */\n /* Expose imperative handle */\n /* ---------------------------------------------------------------- */\n\n useImperativeHandle(\n ref,\n () => ({ clear, setContent, focus }),\n [clear, setContent, focus],\n );\n\n const isExpanded = uiState.state !== \"idle\";\n\n const handleHover = useCallback((_index: number) => {\n // Direct setActiveIndex can be exposed if needed\n }, []);\n\n return (\n <div\n className={className}\n data-mentions-input=\"\"\n data-disabled={disabled ? \"\" : undefined}\n {...comboboxAttrs(isExpanded, LISTBOX_ID)}\n aria-activedescendant={\n isExpanded && uiState.items[uiState.activeIndex]\n ? `mention-option-${uiState.items[uiState.activeIndex].id}`\n : undefined\n }\n >\n <EditorContent editor={editor} />\n\n {isExpanded && (\n <SuggestionList\n items={uiState.items}\n activeIndex={uiState.activeIndex}\n breadcrumbs={uiState.breadcrumbs}\n loading={uiState.loading}\n trigger={uiState.trigger}\n clientRect={uiState.clientRect}\n onSelect={(item) => actions.select(item)}\n onHover={handleHover}\n onGoBack={actions.goBack}\n renderItem={renderItem}\n />\n )}\n </div>\n );\n },\n);\n","import { useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { useEditor } from \"@tiptap/react\";\nimport StarterKit from \"@tiptap/starter-kit\";\nimport { Extension } from \"@tiptap/core\";\nimport { MentionNode } from \"../core/mentionExtension\";\nimport { createSuggestionExtension } from \"../core/suggestionPlugin\";\nimport {\n serializeToMarkdown,\n extractTokens,\n extractPlainText,\n} from \"../core/markdownSerializer\";\nimport { parseFromMarkdown } from \"../core/markdownParser\";\nimport type { MentionProvider } from \"../types/MentionProvider\";\nimport type { MentionsOutput } from \"../types/MentionsOutput\";\nimport type { SuggestionCallbacksRef } from \"../core/suggestionPlugin\";\n\n/* ------------------------------------------------------------------ */\n/* Helper: build MentionsOutput from the current editor */\n/* ------------------------------------------------------------------ */\n\nfunction buildOutput(editor: { getJSON: () => any }): MentionsOutput {\n const json = editor.getJSON();\n return {\n markdown: serializeToMarkdown(json),\n tokens: extractTokens(json),\n plainText: extractPlainText(json),\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Submit keyboard shortcut extension (Cmd+Enter) */\n/* ------------------------------------------------------------------ */\n\nfunction createSubmitExtension(\n onSubmitRef: React.RefObject<((output: MentionsOutput) => void) | undefined>,\n clearOnSubmitRef: React.RefObject<boolean>,\n) {\n return Extension.create({\n name: \"submitShortcut\",\n\n addKeyboardShortcuts() {\n return {\n \"Mod-Enter\": () => {\n if (onSubmitRef.current) {\n onSubmitRef.current(buildOutput(this.editor));\n if (clearOnSubmitRef.current) {\n this.editor.commands.clearContent(true);\n }\n }\n return true;\n },\n };\n },\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* Enter key — submit (only when suggestions are NOT active) */\n/* ------------------------------------------------------------------ */\n\nfunction createEnterExtension(\n onSubmitRef: React.RefObject<((output: MentionsOutput) => void) | undefined>,\n clearOnSubmitRef: React.RefObject<boolean>,\n) {\n return Extension.create({\n name: \"enterSubmit\",\n priority: 50,\n\n addKeyboardShortcuts() {\n return {\n Enter: () => {\n if (onSubmitRef.current) {\n onSubmitRef.current(buildOutput(this.editor));\n if (clearOnSubmitRef.current) {\n this.editor.commands.clearContent(true);\n }\n }\n return true;\n },\n };\n },\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* Hook */\n/* ------------------------------------------------------------------ */\n\ntype UseMentionsEditorOptions = {\n providers: MentionProvider[];\n value?: string;\n onChange?: (output: MentionsOutput) => void;\n onSubmit?: (output: MentionsOutput) => void;\n clearOnSubmit?: boolean;\n placeholder?: string;\n autoFocus?: boolean;\n editable?: boolean;\n callbacksRef: SuggestionCallbacksRef;\n};\n\nexport function useMentionsEditor({\n providers,\n value,\n onChange,\n onSubmit,\n clearOnSubmit = true,\n placeholder,\n autoFocus = false,\n editable = true,\n callbacksRef,\n}: UseMentionsEditorOptions) {\n // Stable refs for handlers that the PM plugin reads\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n const onSubmitRef = useRef(onSubmit);\n onSubmitRef.current = onSubmit;\n\n const clearOnSubmitRef = useRef(clearOnSubmit);\n clearOnSubmitRef.current = clearOnSubmit;\n\n // Build initial content from markdown value (only once)\n const initialContent = useMemo(() => {\n if (!value) return undefined;\n return parseFromMarkdown(value);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Extract trigger strings for memoisation key\n const triggersKey = providers.map((p) => p.trigger).join(\",\");\n const triggers = useMemo(\n () => providers.map((p) => p.trigger),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [triggersKey],\n );\n\n // Single suggestion extension — uses callbacksRef so always fresh\n const suggestionExtension = useMemo(\n () => createSuggestionExtension(triggers, callbacksRef),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [triggersKey],\n );\n\n // Submit extensions — use refs, stable across renders\n const submitExt = useMemo(\n () => createSubmitExtension(onSubmitRef, clearOnSubmitRef),\n [],\n );\n const enterExt = useMemo(\n () => createEnterExtension(onSubmitRef, clearOnSubmitRef),\n [],\n );\n\n const editor = useEditor({\n extensions: [\n StarterKit.configure({\n heading: false,\n blockquote: false,\n codeBlock: false,\n bulletList: false,\n orderedList: false,\n listItem: false,\n horizontalRule: false,\n }),\n MentionNode,\n suggestionExtension,\n submitExt,\n enterExt,\n ],\n content: initialContent,\n autofocus: autoFocus ? \"end\" : false,\n editable,\n editorProps: {\n attributes: {\n \"data-placeholder\": placeholder ?? \"\",\n class: \"mentions-editor\",\n },\n },\n onUpdate: ({ editor }) => {\n onChangeRef.current?.(buildOutput(editor));\n },\n });\n\n // Sync editable state\n useEffect(() => {\n if (editor && editor.isEditable !== editable) {\n editor.setEditable(editable);\n }\n }, [editor, editable]);\n\n /* ---------------------------------------------------------------- */\n /* Imperative methods */\n /* ---------------------------------------------------------------- */\n\n const clear = useCallback(() => {\n editor?.commands.clearContent(true);\n }, [editor]);\n\n const setContent = useCallback(\n (markdown: string) => {\n if (!editor) return;\n const doc = parseFromMarkdown(markdown);\n editor.commands.setContent(doc);\n },\n [editor],\n );\n\n const focus = useCallback(() => {\n editor?.commands.focus(\"end\");\n }, [editor]);\n\n const getOutput = useCallback((): MentionsOutput | null => {\n if (!editor) return null;\n return buildOutput(editor);\n }, [editor]);\n\n return { editor, getOutput, clear, setContent, focus };\n}\n","import { mergeAttributes, Node } from \"@tiptap/core\";\nimport { NodeViewRendererProps } from \"@tiptap/core\";\nimport { ReactNodeViewRenderer } from \"@tiptap/react\";\n\nexport interface MentionNodeAttrs {\n id: string;\n label: string;\n entityType: string;\n}\n\n/**\n * Trigger-character prefix map.\n * Used when rendering a mention chip to prepend the correct character.\n */\nconst DEFAULT_PREFIXES: Record<string, string> = {\n workspace: \"@\",\n contract: \"@\",\n file: \"#\",\n web: \":\",\n};\n\n/**\n * Custom Tiptap Node extension for inline mention tokens.\n *\n * Each mention is an atomic inline node with `id`, `label`, and `entityType`\n * attributes. Renders as a `<span>` with `data-mention` and `data-type`\n * attributes for styling.\n */\nexport const MentionNode = Node.create({\n name: \"mention\",\n group: \"inline\",\n inline: true,\n atom: true,\n selectable: true,\n draggable: false,\n\n addAttributes() {\n return {\n id: {\n default: null,\n parseHTML: (element) => element.getAttribute(\"data-id\"),\n renderHTML: (attributes) => ({ \"data-id\": attributes.id }),\n },\n label: {\n default: null,\n parseHTML: (element) => element.getAttribute(\"data-label\"),\n renderHTML: (attributes) => ({ \"data-label\": attributes.label }),\n },\n entityType: {\n default: null,\n parseHTML: (element) => element.getAttribute(\"data-type\"),\n renderHTML: (attributes) => ({ \"data-type\": attributes.entityType }),\n },\n };\n },\n\n parseHTML() {\n return [{ tag: 'span[data-mention]' }];\n },\n\n renderHTML({ node, HTMLAttributes }) {\n const entityType = node.attrs.entityType as string;\n const label = node.attrs.label as string;\n const prefix = DEFAULT_PREFIXES[entityType] ?? \"@\";\n\n return [\n \"span\",\n mergeAttributes(HTMLAttributes, {\n \"data-mention\": \"\",\n class: \"mention-chip\",\n }),\n `${prefix}${label}`,\n ];\n },\n\n renderText({ node }) {\n const entityType = node.attrs.entityType as string;\n const label = node.attrs.label as string;\n const prefix = DEFAULT_PREFIXES[entityType] ?? \"@\";\n return `${prefix}${label}`;\n },\n\n addKeyboardShortcuts() {\n return {\n Backspace: () =>\n this.editor.commands.command(({ tr, state }) => {\n let isMention = false;\n const { selection } = state;\n const { empty, anchor } = selection;\n\n if (!empty) return false;\n\n state.doc.nodesBetween(anchor - 1, anchor, (node, pos) => {\n if (node.type.name === this.name) {\n isMention = true;\n tr.insertText(\"\", pos, pos + node.nodeSize);\n }\n });\n\n return isMention;\n }),\n };\n },\n});\n","import { Extension } from \"@tiptap/core\";\nimport { Plugin, PluginKey } from \"@tiptap/pm/state\";\nimport type { EditorView } from \"@tiptap/pm/view\";\nimport type { MentionItem, MentionProvider } from \"../types/MentionProvider\";\n\n/* ------------------------------------------------------------------ */\n/* Suggestion state types */\n/* ------------------------------------------------------------------ */\n\nexport type SuggestionState =\n | \"idle\"\n | \"loading\"\n | \"showing\"\n | \"drilling\"\n | \"inserting\";\n\n/* ------------------------------------------------------------------ */\n/* Callbacks the React layer implements */\n/* ------------------------------------------------------------------ */\n\nexport type SuggestionCallbacks = {\n onStart: (props: SuggestionCallbackProps) => void;\n onUpdate: (props: SuggestionCallbackProps) => void;\n onExit: () => void;\n onKeyDown: (props: { event: KeyboardEvent }) => boolean;\n};\n\nexport type SuggestionCallbackProps = {\n query: string;\n trigger: string;\n clientRect: (() => DOMRect | null) | null;\n range: { from: number; to: number };\n command: (attrs: Record<string, unknown>) => void;\n};\n\n/* ------------------------------------------------------------------ */\n/* Trigger detection */\n/* ------------------------------------------------------------------ */\n\ntype TriggerMatch = {\n trigger: string;\n query: string;\n from: number;\n to: number;\n};\n\nfunction detectTrigger(\n text: string,\n cursorPos: number,\n docStartPos: number,\n triggers: string[],\n): TriggerMatch | null {\n const relCursor = cursorPos - docStartPos;\n const before = text.slice(0, relCursor);\n\n for (let i = before.length - 1; i >= 0; i--) {\n const ch = before[i];\n if (ch === \"\\n\") return null;\n\n for (const trigger of triggers) {\n if (before.substring(i, i + trigger.length) === trigger) {\n if (i === 0 || /\\s/.test(before[i - 1])) {\n const query = before.slice(i + trigger.length);\n return { trigger, query, from: docStartPos + i, to: cursorPos };\n }\n }\n }\n }\n\n return null;\n}\n\n/* ------------------------------------------------------------------ */\n/* Plugin key */\n/* ------------------------------------------------------------------ */\n\nconst suggestionPluginKey = new PluginKey(\"mentionSuggestion\");\n\n/* ------------------------------------------------------------------ */\n/* Ref-based callback container (avoids stale closure issues) */\n/* ------------------------------------------------------------------ */\n\nexport type SuggestionCallbacksRef = { current: SuggestionCallbacks };\n\n/* ------------------------------------------------------------------ */\n/* Build the single multi-trigger suggestion extension */\n/* ------------------------------------------------------------------ */\n\nexport function createSuggestionExtension(\n triggers: string[],\n callbacksRef: SuggestionCallbacksRef,\n) {\n return Extension.create({\n name: \"mentionSuggestion\",\n\n addProseMirrorPlugins() {\n const editor = this.editor;\n let active = false;\n let lastQuery: string | null = null;\n let lastTrigger: string | null = null;\n\n const getClientRect = (\n view: EditorView,\n from: number,\n ): (() => DOMRect | null) => {\n return () => {\n try {\n const coords = view.coordsAtPos(from);\n return new DOMRect(\n coords.left,\n coords.top,\n 0,\n coords.bottom - coords.top,\n );\n } catch {\n return null;\n }\n };\n };\n\n const makeCommand = (range: { from: number; to: number }) => {\n return (attrs: Record<string, unknown>) => {\n editor\n .chain()\n .focus()\n .insertContentAt(range, [\n {\n type: \"mention\",\n attrs: {\n id: attrs.id,\n label: attrs.label,\n entityType: attrs.entityType,\n },\n },\n { type: \"text\", text: \" \" },\n ])\n .run();\n };\n };\n\n const plugin = new Plugin({\n key: suggestionPluginKey,\n\n props: {\n handleKeyDown(_view, event) {\n if (!active) return false;\n // Always read from the ref — never a stale closure\n return callbacksRef.current.onKeyDown({ event });\n },\n },\n\n view() {\n return {\n update(view, _prevState) {\n const { state } = view;\n const { selection } = state;\n\n if (!selection.empty) {\n if (active) {\n active = false;\n lastQuery = null;\n lastTrigger = null;\n callbacksRef.current.onExit();\n }\n return;\n }\n\n const $pos = selection.$from;\n const textBlock = $pos.parent;\n\n if (!textBlock.isTextblock) {\n if (active) {\n active = false;\n lastQuery = null;\n lastTrigger = null;\n callbacksRef.current.onExit();\n }\n return;\n }\n\n const blockStart = $pos.start();\n const blockText = textBlock.textContent;\n const cursorPos = $pos.pos;\n\n const match = detectTrigger(blockText, cursorPos, blockStart, triggers);\n\n if (match) {\n const range = { from: match.from, to: match.to };\n const props: SuggestionCallbackProps = {\n query: match.query,\n trigger: match.trigger,\n clientRect: getClientRect(view, match.from),\n range,\n command: makeCommand(range),\n };\n\n if (!active) {\n active = true;\n lastQuery = match.query;\n lastTrigger = match.trigger;\n callbacksRef.current.onStart(props);\n } else if (\n match.query !== lastQuery ||\n match.trigger !== lastTrigger\n ) {\n // Only fire onUpdate when something actually changed\n lastQuery = match.query;\n lastTrigger = match.trigger;\n callbacksRef.current.onUpdate(props);\n }\n } else {\n if (active) {\n active = false;\n lastQuery = null;\n lastTrigger = null;\n callbacksRef.current.onExit();\n }\n }\n },\n\n destroy() {\n if (active) {\n callbacksRef.current.onExit();\n }\n },\n };\n },\n });\n\n return [plugin];\n },\n });\n}\n","import type { JSONContent } from \"@tiptap/core\";\nimport type { MentionToken } from \"../types/MentionToken\";\n\n/**\n * Serialize a Tiptap JSON document to a markdown string.\n *\n * Mention nodes are encoded as `@[label](id)` tokens.\n * All other text passes through verbatim.\n */\nexport function serializeToMarkdown(doc: JSONContent): string {\n if (!doc.content) return \"\";\n\n const parts: string[] = [];\n\n for (const block of doc.content) {\n if (block.type === \"paragraph\") {\n parts.push(serializeParagraph(block));\n } else if (block.type === \"text\") {\n parts.push(block.text ?? \"\");\n }\n }\n\n return parts.join(\"\\n\");\n}\n\nfunction serializeParagraph(node: JSONContent): string {\n if (!node.content) return \"\";\n\n return node.content\n .map((child) => {\n if (child.type === \"mention\") {\n const { id, label } = child.attrs ?? {};\n return `@[${label}](${id})`;\n }\n return child.text ?? \"\";\n })\n .join(\"\");\n}\n\n/**\n * Extract all `MentionToken`s from a Tiptap JSON document, in document order.\n */\nexport function extractTokens(doc: JSONContent): MentionToken[] {\n const tokens: MentionToken[] = [];\n\n function walk(node: JSONContent) {\n if (node.type === \"mention\" && node.attrs) {\n tokens.push({\n id: node.attrs.id as string,\n type: node.attrs.entityType as string,\n label: node.attrs.label as string,\n });\n }\n if (node.content) {\n for (const child of node.content) {\n walk(child);\n }\n }\n }\n\n walk(doc);\n return tokens;\n}\n\n/**\n * Extract plain text from a Tiptap JSON document.\n * Mention nodes are replaced with their label (no trigger prefix in plain text).\n */\nexport function extractPlainText(doc: JSONContent): string {\n if (!doc.content) return \"\";\n\n const parts: string[] = [];\n\n for (const block of doc.content) {\n if (block.type === \"paragraph\") {\n parts.push(extractParagraphText(block));\n }\n }\n\n return parts.join(\"\\n\");\n}\n\nfunction extractParagraphText(node: JSONContent): string {\n if (!node.content) return \"\";\n\n return node.content\n .map((child) => {\n if (child.type === \"mention\") {\n return child.attrs?.label ?? \"\";\n }\n return child.text ?? \"\";\n })\n .join(\"\");\n}\n","import type { JSONContent } from \"@tiptap/core\";\n\n/**\n * Regex matching the `@[label](id)` mention token syntax.\n *\n * Optionally captures an `entityType` when encoded as `@[label](type:id)`.\n * Falls back to `\"unknown\"` when no type prefix is present.\n */\nconst MENTION_RE = /@\\[([^\\]]+)\\]\\((?:([^:)]+):)?([^)]+)\\)/g;\n\n/**\n * Parse a markdown string (with `@[label](id)` or `@[label](type:id)` tokens)\n * into a Tiptap-compatible JSON document.\n */\nexport function parseFromMarkdown(markdown: string): JSONContent {\n const lines = markdown.split(\"\\n\");\n\n const content: JSONContent[] = lines.map((line) => ({\n type: \"paragraph\",\n content: parseLine(line),\n }));\n\n return { type: \"doc\", content };\n}\n\nfunction parseLine(line: string): JSONContent[] {\n const nodes: JSONContent[] = [];\n let lastIndex = 0;\n\n // Reset regex state\n MENTION_RE.lastIndex = 0;\n\n let match: RegExpExecArray | null;\n while ((match = MENTION_RE.exec(line)) !== null) {\n const fullMatch = match[0];\n const label = match[1];\n const entityType = match[2] ?? \"unknown\";\n const id = match[3];\n\n // Text before this mention\n if (match.index > lastIndex) {\n nodes.push({\n type: \"text\",\n text: line.slice(lastIndex, match.index),\n });\n }\n\n // Mention node\n nodes.push({\n type: \"mention\",\n attrs: {\n id,\n label,\n entityType,\n },\n });\n\n lastIndex = match.index + fullMatch.length;\n }\n\n // Trailing text\n if (lastIndex < line.length) {\n nodes.push({\n type: \"text\",\n text: line.slice(lastIndex),\n });\n }\n\n // Empty line — ProseMirror needs at least one node\n if (nodes.length === 0) {\n nodes.push({ type: \"text\", text: \"\" });\n }\n\n return nodes;\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport type { MentionItem, MentionProvider } from \"../types/MentionProvider\";\nimport type {\n SuggestionCallbackProps,\n SuggestionCallbacks,\n SuggestionCallbacksRef,\n SuggestionState,\n} from \"../core/suggestionPlugin\";\n\n/* ------------------------------------------------------------------ */\n/* Public state exposed to the UI layer */\n/* ------------------------------------------------------------------ */\n\nexport type SuggestionUIState = {\n state: SuggestionState;\n items: MentionItem[];\n breadcrumbs: MentionItem[];\n activeIndex: number;\n loading: boolean;\n clientRect: (() => DOMRect | null) | null;\n trigger: string | null;\n query: string;\n};\n\nexport type SuggestionActions = {\n navigateUp: () => void;\n navigateDown: () => void;\n select: (item?: MentionItem) => void;\n goBack: () => void;\n close: () => void;\n};\n\nconst IDLE_STATE: SuggestionUIState = {\n state: \"idle\",\n items: [],\n breadcrumbs: [],\n activeIndex: 0,\n loading: false,\n clientRect: null,\n trigger: null,\n query: \"\",\n};\n\n/* ------------------------------------------------------------------ */\n/* Hook */\n/* ------------------------------------------------------------------ */\n\nexport function useSuggestion(providers: MentionProvider[]) {\n const [uiState, setUIState] = useState<SuggestionUIState>(IDLE_STATE);\n\n // --- Refs for values that callbacks need to read (avoids stale closures) ---\n const stateRef = useRef(uiState);\n stateRef.current = uiState;\n\n const providersRef = useRef(providers);\n providersRef.current = providers;\n\n const commandRef = useRef<((attrs: Record<string, unknown>) => void) | null>(\n null,\n );\n const providerRef = useRef<MentionProvider | null>(null);\n\n /* ---------------------------------------------------------------- */\n /* Fetch items from the provider */\n /* ---------------------------------------------------------------- */\n\n const fetchItems = useCallback(\n async (\n provider: MentionProvider,\n query: string,\n parent?: MentionItem,\n ) => {\n setUIState((prev) => ({ ...prev, loading: true, state: \"loading\" }));\n\n try {\n const items =\n parent && provider.getChildren\n ? await provider.getChildren(parent, query)\n : await provider.getRootItems(query);\n\n setUIState((prev) => ({\n ...prev,\n items,\n loading: false,\n state: \"showing\",\n activeIndex: 0,\n }));\n } catch {\n setUIState((prev) => ({\n ...prev,\n items: [],\n loading: false,\n state: \"showing\",\n }));\n }\n },\n [],\n );\n\n /* ---------------------------------------------------------------- */\n /* Suggestion plugin callbacks */\n /* ---------------------------------------------------------------- */\n\n const onStart = useCallback(\n (props: SuggestionCallbackProps) => {\n const provider = providersRef.current.find(\n (p) => p.trigger === props.trigger,\n );\n if (!provider) return;\n\n providerRef.current = provider;\n commandRef.current = props.command;\n\n setUIState({\n state: \"loading\",\n items: [],\n breadcrumbs: [],\n activeIndex: 0,\n loading: true,\n clientRect: props.clientRect,\n trigger: props.trigger,\n query: props.query,\n });\n\n fetchItems(provider, props.query);\n },\n [fetchItems],\n );\n\n const onUpdate = useCallback(\n (props: SuggestionCallbackProps) => {\n const provider = providerRef.current;\n if (!provider) return;\n\n commandRef.current = props.command;\n\n setUIState((prev) => ({\n ...prev,\n clientRect: props.clientRect,\n query: props.query,\n }));\n\n // Only refetch at root level — nested levels manage their own queries\n // Read from ref to avoid stale closure\n if (stateRef.current.breadcrumbs.length === 0) {\n fetchItems(provider, props.query);\n }\n },\n [fetchItems],\n );\n\n const onExit = useCallback(() => {\n providerRef.current = null;\n commandRef.current = null;\n setUIState(IDLE_STATE);\n }, []);\n\n /* ---------------------------------------------------------------- */\n /* Navigation actions */\n /* ---------------------------------------------------------------- */\n\n const navigateUp = useCallback(() => {\n setUIState((prev) => ({\n ...prev,\n activeIndex: Math.max(0, prev.activeIndex - 1),\n }));\n }, []);\n\n const navigateDown = useCallback(() => {\n setUIState((prev) => ({\n ...prev,\n activeIndex: Math.min(prev.items.length - 1, prev.activeIndex + 1),\n }));\n }, []);\n\n const select = useCallback(\n (item?: MentionItem) => {\n const current = stateRef.current;\n const selected = item ?? current.items[current.activeIndex];\n if (!selected) return;\n\n const provider = providerRef.current;\n\n // If the item has children and the provider supports it, drill down\n if (selected.hasChildren && provider?.getChildren) {\n setUIState((prev) => ({\n ...prev,\n state: \"drilling\",\n breadcrumbs: [...prev.breadcrumbs, selected],\n items: [],\n activeIndex: 0,\n query: \"\",\n }));\n\n fetchItems(provider, \"\", selected);\n return;\n }\n\n // Otherwise insert the mention\n if (commandRef.current) {\n commandRef.current({\n id: selected.id,\n label: selected.label,\n entityType: selected.type,\n });\n }\n },\n [fetchItems],\n );\n\n const goBack = useCallback(() => {\n const provider = providerRef.current;\n if (!provider) return;\n\n setUIState((prev) => {\n const newBreadcrumbs = prev.breadcrumbs.slice(0, -1);\n const parent = newBreadcrumbs[newBreadcrumbs.length - 1];\n\n if (parent) {\n fetchItems(provider, \"\", parent);\n } else {\n fetchItems(provider, prev.query);\n }\n\n return {\n ...prev,\n breadcrumbs: newBreadcrumbs,\n items: [],\n activeIndex: 0,\n state: \"loading\" as const,\n };\n });\n }, [fetchItems]);\n\n const close = useCallback(() => {\n setUIState(IDLE_STATE);\n }, []);\n\n /* ---------------------------------------------------------------- */\n /* Keyboard handler */\n /* ---------------------------------------------------------------- */\n\n const onKeyDown = useCallback(\n ({ event }: { event: KeyboardEvent }): boolean => {\n const current = stateRef.current;\n if (current.state === \"idle\") return false;\n\n switch (event.key) {\n case \"ArrowUp\":\n event.preventDefault();\n navigateUp();\n return true;\n case \"ArrowDown\":\n event.preventDefault();\n navigateDown();\n return true;\n case \"Enter\": {\n event.preventDefault();\n const selectedItem = current.items[current.activeIndex];\n if (selectedItem) {\n select(selectedItem);\n }\n return true;\n }\n case \"ArrowRight\": {\n const activeItem = current.items[current.activeIndex];\n if (activeItem?.hasChildren) {\n event.preventDefault();\n select(activeItem);\n return true;\n }\n return false;\n }\n case \"ArrowLeft\":\n if (current.breadcrumbs.length > 0) {\n event.preventDefault();\n goBack();\n return true;\n }\n return false;\n case \"Escape\":\n event.preventDefault();\n close();\n return true;\n default:\n return false;\n }\n },\n [navigateUp, navigateDown, select, goBack, close],\n );\n\n /* ---------------------------------------------------------------- */\n /* Build a ref that always points to the latest callbacks. */\n /* The ProseMirror plugin reads from this ref — no stale closures. */\n /* ---------------------------------------------------------------- */\n\n const callbacksRef: SuggestionCallbacksRef = useRef<SuggestionCallbacks>({\n onStart,\n onUpdate,\n onExit,\n onKeyDown,\n });\n\n // Update on every render so the PM plugin always sees fresh functions\n callbacksRef.current = { onStart, onUpdate, onExit, onKeyDown };\n\n const actions: SuggestionActions = {\n navigateUp,\n navigateDown,\n select,\n goBack,\n close,\n };\n\n return { uiState, actions, callbacksRef };\n}\n","import React, { useEffect, useRef } from \"react\";\nimport type { ReactNode } from \"react\";\nimport type { MentionItem } from \"../types/MentionProvider\";\nimport { listboxAttrs, optionAttrs } from \"../utils/ariaHelpers\";\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\nexport type SuggestionListProps = {\n items: MentionItem[];\n activeIndex: number;\n breadcrumbs: MentionItem[];\n loading: boolean;\n trigger: string | null;\n clientRect: (() => DOMRect | null) | null;\n onSelect: (item: MentionItem) => void;\n onHover: (index: number) => void;\n onGoBack: () => void;\n renderItem?: (item: MentionItem, depth: number) => ReactNode;\n};\n\nconst LISTBOX_ID = \"mentions-suggestion-listbox\";\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nexport function SuggestionList({\n items,\n activeIndex,\n breadcrumbs,\n loading,\n trigger,\n clientRect,\n onSelect,\n onHover,\n onGoBack,\n renderItem,\n}: SuggestionListProps) {\n const listRef = useRef<HTMLDivElement>(null);\n const depth = breadcrumbs.length;\n\n // Scroll the active item into view\n useEffect(() => {\n if (!listRef.current) return;\n const active = listRef.current.querySelector('[aria-selected=\"true\"]');\n active?.scrollIntoView({ block: \"nearest\" });\n }, [activeIndex]);\n\n // Position the popover based on clientRect\n const style = usePopoverPosition(clientRect);\n\n if (items.length === 0 && !loading) return null;\n\n return (\n <div\n data-suggestions=\"\"\n data-trigger={trigger}\n style={style}\n ref={listRef}\n >\n {/* Breadcrumbs for nested navigation */}\n {breadcrumbs.length > 0 && (\n <div data-suggestion-breadcrumb=\"\">\n <button\n type=\"button\"\n data-suggestion-back=\"\"\n onClick={onGoBack}\n aria-label=\"Go back\"\n >\n &larr;\n </button>\n {breadcrumbs.map((crumb, i) => (\n <span key={crumb.id} data-suggestion-breadcrumb-item=\"\">\n {i > 0 && <span data-suggestion-breadcrumb-sep=\"\">/</span>}\n {crumb.label}\n </span>\n ))}\n </div>\n )}\n\n {/* Loading indicator */}\n {loading && (\n <div data-suggestion-loading=\"\">Loading...</div>\n )}\n\n {/* Item list */}\n {!loading && (\n <div {...listboxAttrs(LISTBOX_ID, `${trigger ?? \"\"} suggestions`)}>\n {items.map((item, index) => {\n const isActive = index === activeIndex;\n const itemId = `mention-option-${item.id}`;\n\n return (\n <div\n key={item.id}\n {...optionAttrs(itemId, isActive, index)}\n data-suggestion-item=\"\"\n data-suggestion-item-active={isActive ? \"\" : undefined}\n data-has-children={item.hasChildren ? \"\" : undefined}\n onMouseEnter={() => onHover(index)}\n onClick={() => onSelect(item)}\n >\n {renderItem ? (\n renderItem(item, depth)\n ) : (\n <DefaultSuggestionItem item={item} />\n )}\n </div>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Default item render */\n/* ------------------------------------------------------------------ */\n\nfunction DefaultSuggestionItem({ item }: { item: MentionItem }) {\n return (\n <>\n {item.icon && (\n <span data-suggestion-item-icon=\"\">{item.icon}</span>\n )}\n <span data-suggestion-item-label=\"\">{item.label}</span>\n {item.description && (\n <span data-suggestion-item-description=\"\">{item.description}</span>\n )}\n {item.hasChildren && (\n <span data-suggestion-item-chevron=\"\" aria-hidden=\"true\">\n &rsaquo;\n </span>\n )}\n </>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Popover positioning */\n/* ------------------------------------------------------------------ */\n\nfunction usePopoverPosition(\n clientRect: (() => DOMRect | null) | null,\n): React.CSSProperties {\n if (!clientRect) {\n return { display: \"none\" };\n }\n\n const rect = clientRect();\n if (!rect) {\n return { display: \"none\" };\n }\n\n return {\n position: \"fixed\",\n left: `${rect.left}px`,\n top: `${rect.bottom + 4}px`,\n zIndex: 50,\n };\n}\n","/**\n * Generates ARIA attributes for the suggestion combobox pattern.\n */\n\nexport function comboboxAttrs(expanded: boolean, listboxId: string) {\n return {\n role: \"combobox\" as const,\n \"aria-haspopup\": \"listbox\" as const,\n \"aria-expanded\": expanded,\n \"aria-owns\": expanded ? listboxId : undefined,\n };\n}\n\nexport function listboxAttrs(id: string, label: string) {\n return {\n id,\n role: \"listbox\" as const,\n \"aria-label\": label,\n };\n}\n\nexport function optionAttrs(\n id: string,\n selected: boolean,\n index: number,\n) {\n return {\n id,\n role: \"option\" as const,\n \"aria-selected\": selected,\n \"aria-posinset\": index + 1,\n };\n}\n"],"mappings":"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","names":["import_react","import_react","import_core","import_core","StarterKit","editor","import_react","import_react","import_jsx_runtime","LISTBOX_ID","MentionsInput"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/components/MentionsInput.tsx","../src/hooks/useMentionsEditor.ts","../src/core/mentionExtension.ts","../src/core/suggestionPlugin.ts","../src/core/markdownSerializer.ts","../src/core/markdownParser.ts","../src/hooks/useSuggestion.ts","../src/components/SuggestionList.tsx","../src/utils/ariaHelpers.ts"],"sourcesContent":["/* ------------------------------------------------------------------ */\n/* Components */\n/* ------------------------------------------------------------------ */\nexport { MentionsInput } from \"./components/MentionsInput\";\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\nexport type { MentionToken } from \"./types/MentionToken\";\nexport type {\n MentionProvider,\n MentionItem,\n} from \"./types/MentionProvider\";\nexport type { MentionsOutput } from \"./types/MentionsOutput\";\nexport type {\n MentionsInputProps,\n MentionsInputHandle,\n} from \"./types/MentionsInputProps\";\n\n/* ------------------------------------------------------------------ */\n/* Utilities */\n/* ------------------------------------------------------------------ */\nexport { serializeToMarkdown } from \"./core/markdownSerializer\";\nexport { parseFromMarkdown } from \"./core/markdownParser\";\n","import React, { forwardRef, useCallback, useImperativeHandle } from \"react\";\nimport { EditorContent } from \"@tiptap/react\";\nimport { useMentionsEditor } from \"../hooks/useMentionsEditor\";\nimport { useSuggestion } from \"../hooks/useSuggestion\";\nimport { SuggestionList } from \"./SuggestionList\";\nimport { comboboxAttrs } from \"../utils/ariaHelpers\";\nimport type {\n MentionsInputProps,\n MentionsInputHandle,\n} from \"../types/MentionsInputProps\";\n\nconst LISTBOX_ID = \"mentions-suggestion-listbox\";\n\n/**\n * `<MentionsInput>` — the single public component.\n *\n * A structured text editor with typed entity tokens.\n * Consumers register `providers` for each trigger character,\n * and receive structured output via `onChange` and `onSubmit`.\n *\n * Supports an imperative ref handle for programmatic control:\n * ```tsx\n * const ref = useRef<MentionsInputHandle>(null);\n * ref.current.clear();\n * ref.current.setContent(\"@[Marketing](ws_123) summarize\");\n * ref.current.focus();\n * ```\n */\nexport const MentionsInput = forwardRef<MentionsInputHandle, MentionsInputProps>(\n function MentionsInput(\n {\n value,\n providers,\n onChange,\n placeholder = \"Type a message...\",\n autoFocus = false,\n disabled = false,\n className,\n onSubmit,\n clearOnSubmit = true,\n maxLength,\n renderItem,\n renderChip,\n },\n ref,\n ) {\n const { uiState, actions, callbacksRef } = useSuggestion(providers);\n\n const { editor, clear, setContent, focus } = useMentionsEditor({\n providers,\n value,\n onChange,\n onSubmit,\n clearOnSubmit,\n placeholder,\n autoFocus,\n editable: !disabled,\n callbacksRef,\n });\n\n /* ---------------------------------------------------------------- */\n /* Expose imperative handle */\n /* ---------------------------------------------------------------- */\n\n useImperativeHandle(\n ref,\n () => ({ clear, setContent, focus }),\n [clear, setContent, focus],\n );\n\n const isExpanded = uiState.state !== \"idle\";\n\n const handleHover = useCallback((_index: number) => {\n // Direct setActiveIndex can be exposed if needed\n }, []);\n\n return (\n <div\n className={className}\n data-mentions-input=\"\"\n data-disabled={disabled ? \"\" : undefined}\n {...comboboxAttrs(isExpanded, LISTBOX_ID)}\n aria-activedescendant={\n isExpanded && uiState.items[uiState.activeIndex]\n ? `mention-option-${uiState.items[uiState.activeIndex].id}`\n : undefined\n }\n >\n <EditorContent editor={editor} />\n\n {isExpanded && (\n <SuggestionList\n items={uiState.items}\n activeIndex={uiState.activeIndex}\n breadcrumbs={uiState.breadcrumbs}\n loading={uiState.loading}\n trigger={uiState.trigger}\n clientRect={uiState.clientRect}\n onSelect={(item) => actions.select(item)}\n onHover={handleHover}\n onGoBack={actions.goBack}\n renderItem={renderItem}\n />\n )}\n </div>\n );\n },\n);\n","import { useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { useEditor } from \"@tiptap/react\";\nimport StarterKit from \"@tiptap/starter-kit\";\nimport Placeholder from \"@tiptap/extension-placeholder\";\nimport { Extension } from \"@tiptap/core\";\nimport { MentionNode } from \"../core/mentionExtension\";\nimport { createSuggestionExtension } from \"../core/suggestionPlugin\";\nimport {\n serializeToMarkdown,\n extractTokens,\n extractPlainText,\n} from \"../core/markdownSerializer\";\nimport { parseFromMarkdown } from \"../core/markdownParser\";\nimport type { MentionProvider } from \"../types/MentionProvider\";\nimport type { MentionsOutput } from \"../types/MentionsOutput\";\nimport type { SuggestionCallbacksRef } from \"../core/suggestionPlugin\";\n\n/* ------------------------------------------------------------------ */\n/* Helper: build MentionsOutput from the current editor */\n/* ------------------------------------------------------------------ */\n\nfunction buildOutput(editor: { getJSON: () => any }): MentionsOutput {\n const json = editor.getJSON();\n return {\n markdown: serializeToMarkdown(json),\n tokens: extractTokens(json),\n plainText: extractPlainText(json),\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Submit keyboard shortcut extension (Cmd+Enter) */\n/* ------------------------------------------------------------------ */\n\nfunction createSubmitExtension(\n onSubmitRef: React.RefObject<((output: MentionsOutput) => void) | undefined>,\n clearOnSubmitRef: React.RefObject<boolean>,\n) {\n return Extension.create({\n name: \"submitShortcut\",\n\n addKeyboardShortcuts() {\n return {\n \"Mod-Enter\": () => {\n if (onSubmitRef.current) {\n onSubmitRef.current(buildOutput(this.editor));\n if (clearOnSubmitRef.current) {\n this.editor.commands.clearContent(true);\n }\n }\n return true;\n },\n };\n },\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* Enter key — submit (only when suggestions are NOT active) */\n/* ------------------------------------------------------------------ */\n\nfunction createEnterExtension(\n onSubmitRef: React.RefObject<((output: MentionsOutput) => void) | undefined>,\n clearOnSubmitRef: React.RefObject<boolean>,\n) {\n return Extension.create({\n name: \"enterSubmit\",\n priority: 50,\n\n addKeyboardShortcuts() {\n return {\n Enter: () => {\n if (onSubmitRef.current) {\n onSubmitRef.current(buildOutput(this.editor));\n if (clearOnSubmitRef.current) {\n this.editor.commands.clearContent(true);\n }\n }\n return true;\n },\n };\n },\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* Hook */\n/* ------------------------------------------------------------------ */\n\ntype UseMentionsEditorOptions = {\n providers: MentionProvider[];\n value?: string;\n onChange?: (output: MentionsOutput) => void;\n onSubmit?: (output: MentionsOutput) => void;\n clearOnSubmit?: boolean;\n placeholder?: string;\n autoFocus?: boolean;\n editable?: boolean;\n callbacksRef: SuggestionCallbacksRef;\n};\n\nexport function useMentionsEditor({\n providers,\n value,\n onChange,\n onSubmit,\n clearOnSubmit = true,\n placeholder,\n autoFocus = false,\n editable = true,\n callbacksRef,\n}: UseMentionsEditorOptions) {\n // Stable refs for handlers that the PM plugin reads\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n const onSubmitRef = useRef(onSubmit);\n onSubmitRef.current = onSubmit;\n\n const clearOnSubmitRef = useRef(clearOnSubmit);\n clearOnSubmitRef.current = clearOnSubmit;\n\n // Build initial content from markdown value (only once)\n const initialContent = useMemo(() => {\n if (!value) return undefined;\n return parseFromMarkdown(value);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Extract trigger strings for memoisation key\n const triggersKey = providers.map((p) => p.trigger).join(\",\");\n const triggers = useMemo(\n () => providers.map((p) => p.trigger),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [triggersKey],\n );\n\n // Single suggestion extension — uses callbacksRef so always fresh\n const suggestionExtension = useMemo(\n () => createSuggestionExtension(triggers, callbacksRef),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [triggersKey],\n );\n\n // Submit extensions — use refs, stable across renders\n const submitExt = useMemo(\n () => createSubmitExtension(onSubmitRef, clearOnSubmitRef),\n [],\n );\n const enterExt = useMemo(\n () => createEnterExtension(onSubmitRef, clearOnSubmitRef),\n [],\n );\n\n const editor = useEditor({\n extensions: [\n StarterKit.configure({\n heading: false,\n blockquote: false,\n codeBlock: false,\n bulletList: false,\n orderedList: false,\n listItem: false,\n horizontalRule: false,\n }),\n Placeholder.configure({\n placeholder: placeholder ?? \"Type a message...\",\n }),\n MentionNode,\n suggestionExtension,\n submitExt,\n enterExt,\n ],\n content: initialContent,\n autofocus: autoFocus ? \"end\" : false,\n editable,\n editorProps: {\n attributes: {\n class: \"mentions-editor\",\n },\n },\n onUpdate: ({ editor }) => {\n onChangeRef.current?.(buildOutput(editor));\n },\n });\n\n // Sync editable state\n useEffect(() => {\n if (editor && editor.isEditable !== editable) {\n editor.setEditable(editable);\n }\n }, [editor, editable]);\n\n /* ---------------------------------------------------------------- */\n /* Imperative methods */\n /* ---------------------------------------------------------------- */\n\n const clear = useCallback(() => {\n editor?.commands.clearContent(true);\n }, [editor]);\n\n const setContent = useCallback(\n (markdown: string) => {\n if (!editor) return;\n const doc = parseFromMarkdown(markdown);\n editor.commands.setContent(doc);\n },\n [editor],\n );\n\n const focus = useCallback(() => {\n editor?.commands.focus(\"end\");\n }, [editor]);\n\n const getOutput = useCallback((): MentionsOutput | null => {\n if (!editor) return null;\n return buildOutput(editor);\n }, [editor]);\n\n return { editor, getOutput, clear, setContent, focus };\n}\n","import { mergeAttributes, Node } from \"@tiptap/core\";\nimport { NodeViewRendererProps } from \"@tiptap/core\";\nimport { ReactNodeViewRenderer } from \"@tiptap/react\";\n\nexport interface MentionNodeAttrs {\n id: string;\n label: string;\n entityType: string;\n}\n\n/**\n * Trigger-character prefix map.\n * Used when rendering a mention chip to prepend the correct character.\n */\nconst DEFAULT_PREFIXES: Record<string, string> = {\n workspace: \"@\",\n contract: \"@\",\n file: \"#\",\n web: \":\",\n};\n\n/**\n * Custom Tiptap Node extension for inline mention tokens.\n *\n * Each mention is an atomic inline node with `id`, `label`, and `entityType`\n * attributes. Renders as a `<span>` with `data-mention` and `data-type`\n * attributes for styling.\n */\nexport const MentionNode = Node.create({\n name: \"mention\",\n group: \"inline\",\n inline: true,\n atom: true,\n selectable: true,\n draggable: false,\n\n addAttributes() {\n return {\n id: {\n default: null,\n parseHTML: (element) => element.getAttribute(\"data-id\"),\n renderHTML: (attributes) => ({ \"data-id\": attributes.id }),\n },\n label: {\n default: null,\n parseHTML: (element) => element.getAttribute(\"data-label\"),\n renderHTML: (attributes) => ({ \"data-label\": attributes.label }),\n },\n entityType: {\n default: null,\n parseHTML: (element) => element.getAttribute(\"data-type\"),\n renderHTML: (attributes) => ({ \"data-type\": attributes.entityType }),\n },\n };\n },\n\n parseHTML() {\n return [{ tag: 'span[data-mention]' }];\n },\n\n renderHTML({ node, HTMLAttributes }) {\n const entityType = node.attrs.entityType as string;\n const label = node.attrs.label as string;\n const prefix = DEFAULT_PREFIXES[entityType] ?? \"@\";\n\n return [\n \"span\",\n mergeAttributes(HTMLAttributes, {\n \"data-mention\": \"\",\n class: \"mention-chip\",\n }),\n `${prefix}${label}`,\n ];\n },\n\n renderText({ node }) {\n const entityType = node.attrs.entityType as string;\n const label = node.attrs.label as string;\n const prefix = DEFAULT_PREFIXES[entityType] ?? \"@\";\n return `${prefix}${label}`;\n },\n\n addKeyboardShortcuts() {\n return {\n Backspace: () =>\n this.editor.commands.command(({ tr, state }) => {\n let isMention = false;\n const { selection } = state;\n const { empty, anchor } = selection;\n\n if (!empty) return false;\n\n state.doc.nodesBetween(anchor - 1, anchor, (node, pos) => {\n if (node.type.name === this.name) {\n isMention = true;\n tr.insertText(\"\", pos, pos + node.nodeSize);\n }\n });\n\n return isMention;\n }),\n };\n },\n});\n","import { Extension } from \"@tiptap/core\";\nimport { Plugin, PluginKey } from \"@tiptap/pm/state\";\nimport type { EditorView } from \"@tiptap/pm/view\";\nimport type { MentionItem, MentionProvider } from \"../types/MentionProvider\";\n\n/* ------------------------------------------------------------------ */\n/* Suggestion state types */\n/* ------------------------------------------------------------------ */\n\nexport type SuggestionState =\n | \"idle\"\n | \"loading\"\n | \"showing\"\n | \"drilling\"\n | \"inserting\";\n\n/* ------------------------------------------------------------------ */\n/* Callbacks the React layer implements */\n/* ------------------------------------------------------------------ */\n\nexport type SuggestionCallbacks = {\n onStart: (props: SuggestionCallbackProps) => void;\n onUpdate: (props: SuggestionCallbackProps) => void;\n onExit: () => void;\n onKeyDown: (props: { event: KeyboardEvent }) => boolean;\n};\n\nexport type SuggestionCallbackProps = {\n query: string;\n trigger: string;\n clientRect: (() => DOMRect | null) | null;\n range: { from: number; to: number };\n command: (attrs: Record<string, unknown>) => void;\n};\n\n/* ------------------------------------------------------------------ */\n/* Trigger detection */\n/* ------------------------------------------------------------------ */\n\ntype TriggerMatch = {\n trigger: string;\n query: string;\n from: number;\n to: number;\n};\n\nfunction detectTrigger(\n text: string,\n cursorPos: number,\n docStartPos: number,\n triggers: string[],\n): TriggerMatch | null {\n const relCursor = cursorPos - docStartPos;\n const before = text.slice(0, relCursor);\n\n for (let i = before.length - 1; i >= 0; i--) {\n const ch = before[i];\n if (ch === \"\\n\") return null;\n\n for (const trigger of triggers) {\n if (before.substring(i, i + trigger.length) === trigger) {\n if (i === 0 || /\\s/.test(before[i - 1])) {\n const query = before.slice(i + trigger.length);\n return { trigger, query, from: docStartPos + i, to: cursorPos };\n }\n }\n }\n }\n\n return null;\n}\n\n/* ------------------------------------------------------------------ */\n/* Plugin key */\n/* ------------------------------------------------------------------ */\n\nconst suggestionPluginKey = new PluginKey(\"mentionSuggestion\");\n\n/* ------------------------------------------------------------------ */\n/* Ref-based callback container (avoids stale closure issues) */\n/* ------------------------------------------------------------------ */\n\nexport type SuggestionCallbacksRef = { current: SuggestionCallbacks };\n\n/* ------------------------------------------------------------------ */\n/* Build the single multi-trigger suggestion extension */\n/* ------------------------------------------------------------------ */\n\nexport function createSuggestionExtension(\n triggers: string[],\n callbacksRef: SuggestionCallbacksRef,\n) {\n return Extension.create({\n name: \"mentionSuggestion\",\n\n addProseMirrorPlugins() {\n const editor = this.editor;\n let active = false;\n let lastQuery: string | null = null;\n let lastTrigger: string | null = null;\n\n const getClientRect = (\n view: EditorView,\n from: number,\n ): (() => DOMRect | null) => {\n return () => {\n try {\n const coords = view.coordsAtPos(from);\n return new DOMRect(\n coords.left,\n coords.top,\n 0,\n coords.bottom - coords.top,\n );\n } catch {\n return null;\n }\n };\n };\n\n const makeCommand = (range: { from: number; to: number }) => {\n return (attrs: Record<string, unknown>) => {\n editor\n .chain()\n .focus()\n .insertContentAt(range, [\n {\n type: \"mention\",\n attrs: {\n id: attrs.id,\n label: attrs.label,\n entityType: attrs.entityType,\n },\n },\n { type: \"text\", text: \" \" },\n ])\n .run();\n };\n };\n\n const plugin = new Plugin({\n key: suggestionPluginKey,\n\n props: {\n handleKeyDown(_view, event) {\n if (!active) return false;\n // Always read from the ref — never a stale closure\n return callbacksRef.current.onKeyDown({ event });\n },\n },\n\n view() {\n return {\n update(view, _prevState) {\n const { state } = view;\n const { selection } = state;\n\n if (!selection.empty) {\n if (active) {\n active = false;\n lastQuery = null;\n lastTrigger = null;\n callbacksRef.current.onExit();\n }\n return;\n }\n\n const $pos = selection.$from;\n const textBlock = $pos.parent;\n\n if (!textBlock.isTextblock) {\n if (active) {\n active = false;\n lastQuery = null;\n lastTrigger = null;\n callbacksRef.current.onExit();\n }\n return;\n }\n\n const blockStart = $pos.start();\n const blockText = textBlock.textContent;\n const cursorPos = $pos.pos;\n\n const match = detectTrigger(blockText, cursorPos, blockStart, triggers);\n\n if (match) {\n const range = { from: match.from, to: match.to };\n const props: SuggestionCallbackProps = {\n query: match.query,\n trigger: match.trigger,\n clientRect: getClientRect(view, match.from),\n range,\n command: makeCommand(range),\n };\n\n if (!active) {\n active = true;\n lastQuery = match.query;\n lastTrigger = match.trigger;\n callbacksRef.current.onStart(props);\n } else if (\n match.query !== lastQuery ||\n match.trigger !== lastTrigger\n ) {\n // Only fire onUpdate when something actually changed\n lastQuery = match.query;\n lastTrigger = match.trigger;\n callbacksRef.current.onUpdate(props);\n }\n } else {\n if (active) {\n active = false;\n lastQuery = null;\n lastTrigger = null;\n callbacksRef.current.onExit();\n }\n }\n },\n\n destroy() {\n if (active) {\n callbacksRef.current.onExit();\n }\n },\n };\n },\n });\n\n return [plugin];\n },\n });\n}\n","import type { JSONContent } from \"@tiptap/core\";\nimport type { MentionToken } from \"../types/MentionToken\";\n\n/**\n * Serialize a Tiptap JSON document to a markdown string.\n *\n * Mention nodes are encoded as `@[label](id)` tokens.\n * All other text passes through verbatim.\n */\nexport function serializeToMarkdown(doc: JSONContent): string {\n if (!doc.content) return \"\";\n\n const parts: string[] = [];\n\n for (const block of doc.content) {\n if (block.type === \"paragraph\") {\n parts.push(serializeParagraph(block));\n } else if (block.type === \"text\") {\n parts.push(block.text ?? \"\");\n }\n }\n\n return parts.join(\"\\n\");\n}\n\nfunction serializeParagraph(node: JSONContent): string {\n if (!node.content) return \"\";\n\n return node.content\n .map((child) => {\n if (child.type === \"mention\") {\n const { id, label } = child.attrs ?? {};\n return `@[${label}](${id})`;\n }\n return child.text ?? \"\";\n })\n .join(\"\");\n}\n\n/**\n * Extract all `MentionToken`s from a Tiptap JSON document, in document order.\n */\nexport function extractTokens(doc: JSONContent): MentionToken[] {\n const tokens: MentionToken[] = [];\n\n function walk(node: JSONContent) {\n if (node.type === \"mention\" && node.attrs) {\n tokens.push({\n id: node.attrs.id as string,\n type: node.attrs.entityType as string,\n label: node.attrs.label as string,\n });\n }\n if (node.content) {\n for (const child of node.content) {\n walk(child);\n }\n }\n }\n\n walk(doc);\n return tokens;\n}\n\n/**\n * Extract plain text from a Tiptap JSON document.\n * Mention nodes are replaced with their label (no trigger prefix in plain text).\n */\nexport function extractPlainText(doc: JSONContent): string {\n if (!doc.content) return \"\";\n\n const parts: string[] = [];\n\n for (const block of doc.content) {\n if (block.type === \"paragraph\") {\n parts.push(extractParagraphText(block));\n }\n }\n\n return parts.join(\"\\n\");\n}\n\nfunction extractParagraphText(node: JSONContent): string {\n if (!node.content) return \"\";\n\n return node.content\n .map((child) => {\n if (child.type === \"mention\") {\n return child.attrs?.label ?? \"\";\n }\n return child.text ?? \"\";\n })\n .join(\"\");\n}\n","import type { JSONContent } from \"@tiptap/core\";\n\n/**\n * Regex matching the `@[label](id)` mention token syntax.\n *\n * Optionally captures an `entityType` when encoded as `@[label](type:id)`.\n * Falls back to `\"unknown\"` when no type prefix is present.\n */\nconst MENTION_RE = /@\\[([^\\]]+)\\]\\((?:([^:)]+):)?([^)]+)\\)/g;\n\n/**\n * Parse a markdown string (with `@[label](id)` or `@[label](type:id)` tokens)\n * into a Tiptap-compatible JSON document.\n */\nexport function parseFromMarkdown(markdown: string): JSONContent {\n const lines = markdown.split(\"\\n\");\n\n const content: JSONContent[] = lines.map((line) => ({\n type: \"paragraph\",\n content: parseLine(line),\n }));\n\n return { type: \"doc\", content };\n}\n\nfunction parseLine(line: string): JSONContent[] {\n const nodes: JSONContent[] = [];\n let lastIndex = 0;\n\n // Reset regex state\n MENTION_RE.lastIndex = 0;\n\n let match: RegExpExecArray | null;\n while ((match = MENTION_RE.exec(line)) !== null) {\n const fullMatch = match[0];\n const label = match[1];\n const entityType = match[2] ?? \"unknown\";\n const id = match[3];\n\n // Text before this mention\n if (match.index > lastIndex) {\n nodes.push({\n type: \"text\",\n text: line.slice(lastIndex, match.index),\n });\n }\n\n // Mention node\n nodes.push({\n type: \"mention\",\n attrs: {\n id,\n label,\n entityType,\n },\n });\n\n lastIndex = match.index + fullMatch.length;\n }\n\n // Trailing text\n if (lastIndex < line.length) {\n nodes.push({\n type: \"text\",\n text: line.slice(lastIndex),\n });\n }\n\n // Empty line — ProseMirror needs at least one node\n if (nodes.length === 0) {\n nodes.push({ type: \"text\", text: \"\" });\n }\n\n return nodes;\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport type { MentionItem, MentionProvider } from \"../types/MentionProvider\";\nimport type {\n SuggestionCallbackProps,\n SuggestionCallbacks,\n SuggestionCallbacksRef,\n SuggestionState,\n} from \"../core/suggestionPlugin\";\n\n/* ------------------------------------------------------------------ */\n/* Public state exposed to the UI layer */\n/* ------------------------------------------------------------------ */\n\nexport type SuggestionUIState = {\n state: SuggestionState;\n items: MentionItem[];\n breadcrumbs: MentionItem[];\n activeIndex: number;\n loading: boolean;\n clientRect: (() => DOMRect | null) | null;\n trigger: string | null;\n query: string;\n};\n\nexport type SuggestionActions = {\n navigateUp: () => void;\n navigateDown: () => void;\n select: (item?: MentionItem) => void;\n goBack: () => void;\n close: () => void;\n};\n\nconst IDLE_STATE: SuggestionUIState = {\n state: \"idle\",\n items: [],\n breadcrumbs: [],\n activeIndex: 0,\n loading: false,\n clientRect: null,\n trigger: null,\n query: \"\",\n};\n\n/* ------------------------------------------------------------------ */\n/* Hook */\n/* ------------------------------------------------------------------ */\n\nexport function useSuggestion(providers: MentionProvider[]) {\n const [uiState, setUIState] = useState<SuggestionUIState>(IDLE_STATE);\n\n // --- Refs for values that callbacks need to read (avoids stale closures) ---\n const stateRef = useRef(uiState);\n stateRef.current = uiState;\n\n const providersRef = useRef(providers);\n providersRef.current = providers;\n\n const commandRef = useRef<((attrs: Record<string, unknown>) => void) | null>(\n null,\n );\n const providerRef = useRef<MentionProvider | null>(null);\n\n /* ---------------------------------------------------------------- */\n /* Fetch items from the provider */\n /* ---------------------------------------------------------------- */\n\n const fetchItems = useCallback(\n async (\n provider: MentionProvider,\n query: string,\n parent?: MentionItem,\n ) => {\n setUIState((prev) => ({ ...prev, loading: true, state: \"loading\" }));\n\n try {\n const items =\n parent && provider.getChildren\n ? await provider.getChildren(parent, query)\n : await provider.getRootItems(query);\n\n setUIState((prev) => ({\n ...prev,\n items,\n loading: false,\n state: \"showing\",\n activeIndex: 0,\n }));\n } catch {\n setUIState((prev) => ({\n ...prev,\n items: [],\n loading: false,\n state: \"showing\",\n }));\n }\n },\n [],\n );\n\n /* ---------------------------------------------------------------- */\n /* Suggestion plugin callbacks */\n /* ---------------------------------------------------------------- */\n\n const onStart = useCallback(\n (props: SuggestionCallbackProps) => {\n const provider = providersRef.current.find(\n (p) => p.trigger === props.trigger,\n );\n if (!provider) return;\n\n providerRef.current = provider;\n commandRef.current = props.command;\n\n setUIState({\n state: \"loading\",\n items: [],\n breadcrumbs: [],\n activeIndex: 0,\n loading: true,\n clientRect: props.clientRect,\n trigger: props.trigger,\n query: props.query,\n });\n\n fetchItems(provider, props.query);\n },\n [fetchItems],\n );\n\n const onUpdate = useCallback(\n (props: SuggestionCallbackProps) => {\n const provider = providerRef.current;\n if (!provider) return;\n\n commandRef.current = props.command;\n\n setUIState((prev) => ({\n ...prev,\n clientRect: props.clientRect,\n query: props.query,\n }));\n\n // Only refetch at root level — nested levels manage their own queries\n // Read from ref to avoid stale closure\n if (stateRef.current.breadcrumbs.length === 0) {\n fetchItems(provider, props.query);\n }\n },\n [fetchItems],\n );\n\n const onExit = useCallback(() => {\n providerRef.current = null;\n commandRef.current = null;\n setUIState(IDLE_STATE);\n }, []);\n\n /* ---------------------------------------------------------------- */\n /* Navigation actions */\n /* ---------------------------------------------------------------- */\n\n const navigateUp = useCallback(() => {\n setUIState((prev) => ({\n ...prev,\n activeIndex: Math.max(0, prev.activeIndex - 1),\n }));\n }, []);\n\n const navigateDown = useCallback(() => {\n setUIState((prev) => ({\n ...prev,\n activeIndex: Math.min(prev.items.length - 1, prev.activeIndex + 1),\n }));\n }, []);\n\n const select = useCallback(\n (item?: MentionItem) => {\n const current = stateRef.current;\n const selected = item ?? current.items[current.activeIndex];\n if (!selected) return;\n\n const provider = providerRef.current;\n\n // If the item has children and the provider supports it, drill down\n if (selected.hasChildren && provider?.getChildren) {\n setUIState((prev) => ({\n ...prev,\n state: \"drilling\",\n breadcrumbs: [...prev.breadcrumbs, selected],\n items: [],\n activeIndex: 0,\n query: \"\",\n }));\n\n fetchItems(provider, \"\", selected);\n return;\n }\n\n // Otherwise insert the mention\n if (commandRef.current) {\n commandRef.current({\n id: selected.id,\n label: selected.label,\n entityType: selected.type,\n });\n }\n },\n [fetchItems],\n );\n\n const goBack = useCallback(() => {\n const provider = providerRef.current;\n if (!provider) return;\n\n setUIState((prev) => {\n const newBreadcrumbs = prev.breadcrumbs.slice(0, -1);\n const parent = newBreadcrumbs[newBreadcrumbs.length - 1];\n\n if (parent) {\n fetchItems(provider, \"\", parent);\n } else {\n fetchItems(provider, prev.query);\n }\n\n return {\n ...prev,\n breadcrumbs: newBreadcrumbs,\n items: [],\n activeIndex: 0,\n state: \"loading\" as const,\n };\n });\n }, [fetchItems]);\n\n const close = useCallback(() => {\n setUIState(IDLE_STATE);\n }, []);\n\n /* ---------------------------------------------------------------- */\n /* Keyboard handler */\n /* ---------------------------------------------------------------- */\n\n const onKeyDown = useCallback(\n ({ event }: { event: KeyboardEvent }): boolean => {\n const current = stateRef.current;\n if (current.state === \"idle\") return false;\n\n switch (event.key) {\n case \"ArrowUp\":\n event.preventDefault();\n navigateUp();\n return true;\n case \"ArrowDown\":\n event.preventDefault();\n navigateDown();\n return true;\n case \"Enter\": {\n event.preventDefault();\n const selectedItem = current.items[current.activeIndex];\n if (selectedItem) {\n select(selectedItem);\n }\n return true;\n }\n case \"ArrowRight\": {\n const activeItem = current.items[current.activeIndex];\n if (activeItem?.hasChildren) {\n event.preventDefault();\n select(activeItem);\n return true;\n }\n return false;\n }\n case \"ArrowLeft\":\n if (current.breadcrumbs.length > 0) {\n event.preventDefault();\n goBack();\n return true;\n }\n return false;\n case \"Escape\":\n event.preventDefault();\n close();\n return true;\n default:\n return false;\n }\n },\n [navigateUp, navigateDown, select, goBack, close],\n );\n\n /* ---------------------------------------------------------------- */\n /* Build a ref that always points to the latest callbacks. */\n /* The ProseMirror plugin reads from this ref — no stale closures. */\n /* ---------------------------------------------------------------- */\n\n const callbacksRef: SuggestionCallbacksRef = useRef<SuggestionCallbacks>({\n onStart,\n onUpdate,\n onExit,\n onKeyDown,\n });\n\n // Update on every render so the PM plugin always sees fresh functions\n callbacksRef.current = { onStart, onUpdate, onExit, onKeyDown };\n\n const actions: SuggestionActions = {\n navigateUp,\n navigateDown,\n select,\n goBack,\n close,\n };\n\n return { uiState, actions, callbacksRef };\n}\n","import React, { useEffect, useRef } from \"react\";\nimport type { ReactNode } from \"react\";\nimport type { MentionItem } from \"../types/MentionProvider\";\nimport { listboxAttrs, optionAttrs } from \"../utils/ariaHelpers\";\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\nexport type SuggestionListProps = {\n items: MentionItem[];\n activeIndex: number;\n breadcrumbs: MentionItem[];\n loading: boolean;\n trigger: string | null;\n clientRect: (() => DOMRect | null) | null;\n onSelect: (item: MentionItem) => void;\n onHover: (index: number) => void;\n onGoBack: () => void;\n renderItem?: (item: MentionItem, depth: number) => ReactNode;\n};\n\nconst LISTBOX_ID = \"mentions-suggestion-listbox\";\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nexport function SuggestionList({\n items,\n activeIndex,\n breadcrumbs,\n loading,\n trigger,\n clientRect,\n onSelect,\n onHover,\n onGoBack,\n renderItem,\n}: SuggestionListProps) {\n const listRef = useRef<HTMLDivElement>(null);\n const depth = breadcrumbs.length;\n\n // Scroll the active item into view\n useEffect(() => {\n if (!listRef.current) return;\n const active = listRef.current.querySelector('[aria-selected=\"true\"]');\n active?.scrollIntoView({ block: \"nearest\" });\n }, [activeIndex]);\n\n // Position the popover based on clientRect\n const style = usePopoverPosition(clientRect);\n\n if (items.length === 0 && !loading) return null;\n\n return (\n <div\n data-suggestions=\"\"\n data-trigger={trigger}\n style={style}\n ref={listRef}\n >\n {/* Breadcrumbs for nested navigation */}\n {breadcrumbs.length > 0 && (\n <div data-suggestion-breadcrumb=\"\">\n <button\n type=\"button\"\n data-suggestion-back=\"\"\n onClick={onGoBack}\n aria-label=\"Go back\"\n >\n &larr;\n </button>\n {breadcrumbs.map((crumb, i) => (\n <span key={crumb.id} data-suggestion-breadcrumb-item=\"\">\n {i > 0 && <span data-suggestion-breadcrumb-sep=\"\">/</span>}\n {crumb.label}\n </span>\n ))}\n </div>\n )}\n\n {/* Loading indicator */}\n {loading && (\n <div data-suggestion-loading=\"\">Loading...</div>\n )}\n\n {/* Item list */}\n {!loading && (\n <div {...listboxAttrs(LISTBOX_ID, `${trigger ?? \"\"} suggestions`)}>\n {items.map((item, index) => {\n const isActive = index === activeIndex;\n const itemId = `mention-option-${item.id}`;\n\n return (\n <div\n key={item.id}\n {...optionAttrs(itemId, isActive, index)}\n data-suggestion-item=\"\"\n data-suggestion-item-active={isActive ? \"\" : undefined}\n data-has-children={item.hasChildren ? \"\" : undefined}\n onMouseEnter={() => onHover(index)}\n onClick={() => onSelect(item)}\n >\n {renderItem ? (\n renderItem(item, depth)\n ) : (\n <DefaultSuggestionItem item={item} />\n )}\n </div>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Default item render */\n/* ------------------------------------------------------------------ */\n\nfunction DefaultSuggestionItem({ item }: { item: MentionItem }) {\n return (\n <>\n {item.icon && (\n <span data-suggestion-item-icon=\"\">{item.icon}</span>\n )}\n <span data-suggestion-item-label=\"\">{item.label}</span>\n {item.description && (\n <span data-suggestion-item-description=\"\">{item.description}</span>\n )}\n {item.hasChildren && (\n <span data-suggestion-item-chevron=\"\" aria-hidden=\"true\">\n &rsaquo;\n </span>\n )}\n </>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Popover positioning */\n/* ------------------------------------------------------------------ */\n\nfunction usePopoverPosition(\n clientRect: (() => DOMRect | null) | null,\n): React.CSSProperties {\n if (!clientRect) {\n return { display: \"none\" };\n }\n\n const rect = clientRect();\n if (!rect) {\n return { display: \"none\" };\n }\n\n return {\n position: \"fixed\",\n left: `${rect.left}px`,\n top: `${rect.bottom + 4}px`,\n zIndex: 50,\n };\n}\n","/**\n * Generates ARIA attributes for the suggestion combobox pattern.\n */\n\nexport function comboboxAttrs(expanded: boolean, listboxId: string) {\n return {\n role: \"combobox\" as const,\n \"aria-haspopup\": \"listbox\" as const,\n \"aria-expanded\": expanded,\n \"aria-owns\": expanded ? listboxId : undefined,\n };\n}\n\nexport function listboxAttrs(id: string, label: string) {\n return {\n id,\n role: \"listbox\" as const,\n \"aria-label\": label,\n };\n}\n\nexport function optionAttrs(\n id: string,\n selected: boolean,\n index: number,\n) {\n return {\n id,\n role: \"option\" as const,\n \"aria-selected\": selected,\n \"aria-posinset\": index + 1,\n };\n}\n"],"mappings":"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","names":["import_react","import_react","import_core","import_core","StarterKit","Placeholder","editor","import_react","import_react","import_jsx_runtime","LISTBOX_ID","MentionsInput"]}
package/dist/index.mjs CHANGED
@@ -6,6 +6,7 @@ import { EditorContent } from "@tiptap/react";
6
6
  import { useCallback, useEffect, useMemo, useRef } from "react";
7
7
  import { useEditor } from "@tiptap/react";
8
8
  import StarterKit from "@tiptap/starter-kit";
9
+ import Placeholder from "@tiptap/extension-placeholder";
9
10
  import { Extension as Extension2 } from "@tiptap/core";
10
11
 
11
12
  // src/core/mentionExtension.ts
@@ -427,6 +428,9 @@ function useMentionsEditor({
427
428
  listItem: false,
428
429
  horizontalRule: false
429
430
  }),
431
+ Placeholder.configure({
432
+ placeholder: placeholder ?? "Type a message..."
433
+ }),
430
434
  MentionNode,
431
435
  suggestionExtension,
432
436
  submitExt,
@@ -437,7 +441,6 @@ function useMentionsEditor({
437
441
  editable,
438
442
  editorProps: {
439
443
  attributes: {
440
- "data-placeholder": placeholder ?? "",
441
444
  class: "mentions-editor"
442
445
  }
443
446
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/MentionsInput.tsx","../src/hooks/useMentionsEditor.ts","../src/core/mentionExtension.ts","../src/core/suggestionPlugin.ts","../src/core/markdownSerializer.ts","../src/core/markdownParser.ts","../src/hooks/useSuggestion.ts","../src/components/SuggestionList.tsx","../src/utils/ariaHelpers.ts"],"sourcesContent":["import React, { forwardRef, useCallback, useImperativeHandle } from \"react\";\nimport { EditorContent } from \"@tiptap/react\";\nimport { useMentionsEditor } from \"../hooks/useMentionsEditor\";\nimport { useSuggestion } from \"../hooks/useSuggestion\";\nimport { SuggestionList } from \"./SuggestionList\";\nimport { comboboxAttrs } from \"../utils/ariaHelpers\";\nimport type {\n MentionsInputProps,\n MentionsInputHandle,\n} from \"../types/MentionsInputProps\";\n\nconst LISTBOX_ID = \"mentions-suggestion-listbox\";\n\n/**\n * `<MentionsInput>` — the single public component.\n *\n * A structured text editor with typed entity tokens.\n * Consumers register `providers` for each trigger character,\n * and receive structured output via `onChange` and `onSubmit`.\n *\n * Supports an imperative ref handle for programmatic control:\n * ```tsx\n * const ref = useRef<MentionsInputHandle>(null);\n * ref.current.clear();\n * ref.current.setContent(\"@[Marketing](ws_123) summarize\");\n * ref.current.focus();\n * ```\n */\nexport const MentionsInput = forwardRef<MentionsInputHandle, MentionsInputProps>(\n function MentionsInput(\n {\n value,\n providers,\n onChange,\n placeholder = \"Type a message...\",\n autoFocus = false,\n disabled = false,\n className,\n onSubmit,\n clearOnSubmit = true,\n maxLength,\n renderItem,\n renderChip,\n },\n ref,\n ) {\n const { uiState, actions, callbacksRef } = useSuggestion(providers);\n\n const { editor, clear, setContent, focus } = useMentionsEditor({\n providers,\n value,\n onChange,\n onSubmit,\n clearOnSubmit,\n placeholder,\n autoFocus,\n editable: !disabled,\n callbacksRef,\n });\n\n /* ---------------------------------------------------------------- */\n /* Expose imperative handle */\n /* ---------------------------------------------------------------- */\n\n useImperativeHandle(\n ref,\n () => ({ clear, setContent, focus }),\n [clear, setContent, focus],\n );\n\n const isExpanded = uiState.state !== \"idle\";\n\n const handleHover = useCallback((_index: number) => {\n // Direct setActiveIndex can be exposed if needed\n }, []);\n\n return (\n <div\n className={className}\n data-mentions-input=\"\"\n data-disabled={disabled ? \"\" : undefined}\n {...comboboxAttrs(isExpanded, LISTBOX_ID)}\n aria-activedescendant={\n isExpanded && uiState.items[uiState.activeIndex]\n ? `mention-option-${uiState.items[uiState.activeIndex].id}`\n : undefined\n }\n >\n <EditorContent editor={editor} />\n\n {isExpanded && (\n <SuggestionList\n items={uiState.items}\n activeIndex={uiState.activeIndex}\n breadcrumbs={uiState.breadcrumbs}\n loading={uiState.loading}\n trigger={uiState.trigger}\n clientRect={uiState.clientRect}\n onSelect={(item) => actions.select(item)}\n onHover={handleHover}\n onGoBack={actions.goBack}\n renderItem={renderItem}\n />\n )}\n </div>\n );\n },\n);\n","import { useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { useEditor } from \"@tiptap/react\";\nimport StarterKit from \"@tiptap/starter-kit\";\nimport { Extension } from \"@tiptap/core\";\nimport { MentionNode } from \"../core/mentionExtension\";\nimport { createSuggestionExtension } from \"../core/suggestionPlugin\";\nimport {\n serializeToMarkdown,\n extractTokens,\n extractPlainText,\n} from \"../core/markdownSerializer\";\nimport { parseFromMarkdown } from \"../core/markdownParser\";\nimport type { MentionProvider } from \"../types/MentionProvider\";\nimport type { MentionsOutput } from \"../types/MentionsOutput\";\nimport type { SuggestionCallbacksRef } from \"../core/suggestionPlugin\";\n\n/* ------------------------------------------------------------------ */\n/* Helper: build MentionsOutput from the current editor */\n/* ------------------------------------------------------------------ */\n\nfunction buildOutput(editor: { getJSON: () => any }): MentionsOutput {\n const json = editor.getJSON();\n return {\n markdown: serializeToMarkdown(json),\n tokens: extractTokens(json),\n plainText: extractPlainText(json),\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Submit keyboard shortcut extension (Cmd+Enter) */\n/* ------------------------------------------------------------------ */\n\nfunction createSubmitExtension(\n onSubmitRef: React.RefObject<((output: MentionsOutput) => void) | undefined>,\n clearOnSubmitRef: React.RefObject<boolean>,\n) {\n return Extension.create({\n name: \"submitShortcut\",\n\n addKeyboardShortcuts() {\n return {\n \"Mod-Enter\": () => {\n if (onSubmitRef.current) {\n onSubmitRef.current(buildOutput(this.editor));\n if (clearOnSubmitRef.current) {\n this.editor.commands.clearContent(true);\n }\n }\n return true;\n },\n };\n },\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* Enter key — submit (only when suggestions are NOT active) */\n/* ------------------------------------------------------------------ */\n\nfunction createEnterExtension(\n onSubmitRef: React.RefObject<((output: MentionsOutput) => void) | undefined>,\n clearOnSubmitRef: React.RefObject<boolean>,\n) {\n return Extension.create({\n name: \"enterSubmit\",\n priority: 50,\n\n addKeyboardShortcuts() {\n return {\n Enter: () => {\n if (onSubmitRef.current) {\n onSubmitRef.current(buildOutput(this.editor));\n if (clearOnSubmitRef.current) {\n this.editor.commands.clearContent(true);\n }\n }\n return true;\n },\n };\n },\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* Hook */\n/* ------------------------------------------------------------------ */\n\ntype UseMentionsEditorOptions = {\n providers: MentionProvider[];\n value?: string;\n onChange?: (output: MentionsOutput) => void;\n onSubmit?: (output: MentionsOutput) => void;\n clearOnSubmit?: boolean;\n placeholder?: string;\n autoFocus?: boolean;\n editable?: boolean;\n callbacksRef: SuggestionCallbacksRef;\n};\n\nexport function useMentionsEditor({\n providers,\n value,\n onChange,\n onSubmit,\n clearOnSubmit = true,\n placeholder,\n autoFocus = false,\n editable = true,\n callbacksRef,\n}: UseMentionsEditorOptions) {\n // Stable refs for handlers that the PM plugin reads\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n const onSubmitRef = useRef(onSubmit);\n onSubmitRef.current = onSubmit;\n\n const clearOnSubmitRef = useRef(clearOnSubmit);\n clearOnSubmitRef.current = clearOnSubmit;\n\n // Build initial content from markdown value (only once)\n const initialContent = useMemo(() => {\n if (!value) return undefined;\n return parseFromMarkdown(value);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Extract trigger strings for memoisation key\n const triggersKey = providers.map((p) => p.trigger).join(\",\");\n const triggers = useMemo(\n () => providers.map((p) => p.trigger),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [triggersKey],\n );\n\n // Single suggestion extension — uses callbacksRef so always fresh\n const suggestionExtension = useMemo(\n () => createSuggestionExtension(triggers, callbacksRef),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [triggersKey],\n );\n\n // Submit extensions — use refs, stable across renders\n const submitExt = useMemo(\n () => createSubmitExtension(onSubmitRef, clearOnSubmitRef),\n [],\n );\n const enterExt = useMemo(\n () => createEnterExtension(onSubmitRef, clearOnSubmitRef),\n [],\n );\n\n const editor = useEditor({\n extensions: [\n StarterKit.configure({\n heading: false,\n blockquote: false,\n codeBlock: false,\n bulletList: false,\n orderedList: false,\n listItem: false,\n horizontalRule: false,\n }),\n MentionNode,\n suggestionExtension,\n submitExt,\n enterExt,\n ],\n content: initialContent,\n autofocus: autoFocus ? \"end\" : false,\n editable,\n editorProps: {\n attributes: {\n \"data-placeholder\": placeholder ?? \"\",\n class: \"mentions-editor\",\n },\n },\n onUpdate: ({ editor }) => {\n onChangeRef.current?.(buildOutput(editor));\n },\n });\n\n // Sync editable state\n useEffect(() => {\n if (editor && editor.isEditable !== editable) {\n editor.setEditable(editable);\n }\n }, [editor, editable]);\n\n /* ---------------------------------------------------------------- */\n /* Imperative methods */\n /* ---------------------------------------------------------------- */\n\n const clear = useCallback(() => {\n editor?.commands.clearContent(true);\n }, [editor]);\n\n const setContent = useCallback(\n (markdown: string) => {\n if (!editor) return;\n const doc = parseFromMarkdown(markdown);\n editor.commands.setContent(doc);\n },\n [editor],\n );\n\n const focus = useCallback(() => {\n editor?.commands.focus(\"end\");\n }, [editor]);\n\n const getOutput = useCallback((): MentionsOutput | null => {\n if (!editor) return null;\n return buildOutput(editor);\n }, [editor]);\n\n return { editor, getOutput, clear, setContent, focus };\n}\n","import { mergeAttributes, Node } from \"@tiptap/core\";\nimport { NodeViewRendererProps } from \"@tiptap/core\";\nimport { ReactNodeViewRenderer } from \"@tiptap/react\";\n\nexport interface MentionNodeAttrs {\n id: string;\n label: string;\n entityType: string;\n}\n\n/**\n * Trigger-character prefix map.\n * Used when rendering a mention chip to prepend the correct character.\n */\nconst DEFAULT_PREFIXES: Record<string, string> = {\n workspace: \"@\",\n contract: \"@\",\n file: \"#\",\n web: \":\",\n};\n\n/**\n * Custom Tiptap Node extension for inline mention tokens.\n *\n * Each mention is an atomic inline node with `id`, `label`, and `entityType`\n * attributes. Renders as a `<span>` with `data-mention` and `data-type`\n * attributes for styling.\n */\nexport const MentionNode = Node.create({\n name: \"mention\",\n group: \"inline\",\n inline: true,\n atom: true,\n selectable: true,\n draggable: false,\n\n addAttributes() {\n return {\n id: {\n default: null,\n parseHTML: (element) => element.getAttribute(\"data-id\"),\n renderHTML: (attributes) => ({ \"data-id\": attributes.id }),\n },\n label: {\n default: null,\n parseHTML: (element) => element.getAttribute(\"data-label\"),\n renderHTML: (attributes) => ({ \"data-label\": attributes.label }),\n },\n entityType: {\n default: null,\n parseHTML: (element) => element.getAttribute(\"data-type\"),\n renderHTML: (attributes) => ({ \"data-type\": attributes.entityType }),\n },\n };\n },\n\n parseHTML() {\n return [{ tag: 'span[data-mention]' }];\n },\n\n renderHTML({ node, HTMLAttributes }) {\n const entityType = node.attrs.entityType as string;\n const label = node.attrs.label as string;\n const prefix = DEFAULT_PREFIXES[entityType] ?? \"@\";\n\n return [\n \"span\",\n mergeAttributes(HTMLAttributes, {\n \"data-mention\": \"\",\n class: \"mention-chip\",\n }),\n `${prefix}${label}`,\n ];\n },\n\n renderText({ node }) {\n const entityType = node.attrs.entityType as string;\n const label = node.attrs.label as string;\n const prefix = DEFAULT_PREFIXES[entityType] ?? \"@\";\n return `${prefix}${label}`;\n },\n\n addKeyboardShortcuts() {\n return {\n Backspace: () =>\n this.editor.commands.command(({ tr, state }) => {\n let isMention = false;\n const { selection } = state;\n const { empty, anchor } = selection;\n\n if (!empty) return false;\n\n state.doc.nodesBetween(anchor - 1, anchor, (node, pos) => {\n if (node.type.name === this.name) {\n isMention = true;\n tr.insertText(\"\", pos, pos + node.nodeSize);\n }\n });\n\n return isMention;\n }),\n };\n },\n});\n","import { Extension } from \"@tiptap/core\";\nimport { Plugin, PluginKey } from \"@tiptap/pm/state\";\nimport type { EditorView } from \"@tiptap/pm/view\";\nimport type { MentionItem, MentionProvider } from \"../types/MentionProvider\";\n\n/* ------------------------------------------------------------------ */\n/* Suggestion state types */\n/* ------------------------------------------------------------------ */\n\nexport type SuggestionState =\n | \"idle\"\n | \"loading\"\n | \"showing\"\n | \"drilling\"\n | \"inserting\";\n\n/* ------------------------------------------------------------------ */\n/* Callbacks the React layer implements */\n/* ------------------------------------------------------------------ */\n\nexport type SuggestionCallbacks = {\n onStart: (props: SuggestionCallbackProps) => void;\n onUpdate: (props: SuggestionCallbackProps) => void;\n onExit: () => void;\n onKeyDown: (props: { event: KeyboardEvent }) => boolean;\n};\n\nexport type SuggestionCallbackProps = {\n query: string;\n trigger: string;\n clientRect: (() => DOMRect | null) | null;\n range: { from: number; to: number };\n command: (attrs: Record<string, unknown>) => void;\n};\n\n/* ------------------------------------------------------------------ */\n/* Trigger detection */\n/* ------------------------------------------------------------------ */\n\ntype TriggerMatch = {\n trigger: string;\n query: string;\n from: number;\n to: number;\n};\n\nfunction detectTrigger(\n text: string,\n cursorPos: number,\n docStartPos: number,\n triggers: string[],\n): TriggerMatch | null {\n const relCursor = cursorPos - docStartPos;\n const before = text.slice(0, relCursor);\n\n for (let i = before.length - 1; i >= 0; i--) {\n const ch = before[i];\n if (ch === \"\\n\") return null;\n\n for (const trigger of triggers) {\n if (before.substring(i, i + trigger.length) === trigger) {\n if (i === 0 || /\\s/.test(before[i - 1])) {\n const query = before.slice(i + trigger.length);\n return { trigger, query, from: docStartPos + i, to: cursorPos };\n }\n }\n }\n }\n\n return null;\n}\n\n/* ------------------------------------------------------------------ */\n/* Plugin key */\n/* ------------------------------------------------------------------ */\n\nconst suggestionPluginKey = new PluginKey(\"mentionSuggestion\");\n\n/* ------------------------------------------------------------------ */\n/* Ref-based callback container (avoids stale closure issues) */\n/* ------------------------------------------------------------------ */\n\nexport type SuggestionCallbacksRef = { current: SuggestionCallbacks };\n\n/* ------------------------------------------------------------------ */\n/* Build the single multi-trigger suggestion extension */\n/* ------------------------------------------------------------------ */\n\nexport function createSuggestionExtension(\n triggers: string[],\n callbacksRef: SuggestionCallbacksRef,\n) {\n return Extension.create({\n name: \"mentionSuggestion\",\n\n addProseMirrorPlugins() {\n const editor = this.editor;\n let active = false;\n let lastQuery: string | null = null;\n let lastTrigger: string | null = null;\n\n const getClientRect = (\n view: EditorView,\n from: number,\n ): (() => DOMRect | null) => {\n return () => {\n try {\n const coords = view.coordsAtPos(from);\n return new DOMRect(\n coords.left,\n coords.top,\n 0,\n coords.bottom - coords.top,\n );\n } catch {\n return null;\n }\n };\n };\n\n const makeCommand = (range: { from: number; to: number }) => {\n return (attrs: Record<string, unknown>) => {\n editor\n .chain()\n .focus()\n .insertContentAt(range, [\n {\n type: \"mention\",\n attrs: {\n id: attrs.id,\n label: attrs.label,\n entityType: attrs.entityType,\n },\n },\n { type: \"text\", text: \" \" },\n ])\n .run();\n };\n };\n\n const plugin = new Plugin({\n key: suggestionPluginKey,\n\n props: {\n handleKeyDown(_view, event) {\n if (!active) return false;\n // Always read from the ref — never a stale closure\n return callbacksRef.current.onKeyDown({ event });\n },\n },\n\n view() {\n return {\n update(view, _prevState) {\n const { state } = view;\n const { selection } = state;\n\n if (!selection.empty) {\n if (active) {\n active = false;\n lastQuery = null;\n lastTrigger = null;\n callbacksRef.current.onExit();\n }\n return;\n }\n\n const $pos = selection.$from;\n const textBlock = $pos.parent;\n\n if (!textBlock.isTextblock) {\n if (active) {\n active = false;\n lastQuery = null;\n lastTrigger = null;\n callbacksRef.current.onExit();\n }\n return;\n }\n\n const blockStart = $pos.start();\n const blockText = textBlock.textContent;\n const cursorPos = $pos.pos;\n\n const match = detectTrigger(blockText, cursorPos, blockStart, triggers);\n\n if (match) {\n const range = { from: match.from, to: match.to };\n const props: SuggestionCallbackProps = {\n query: match.query,\n trigger: match.trigger,\n clientRect: getClientRect(view, match.from),\n range,\n command: makeCommand(range),\n };\n\n if (!active) {\n active = true;\n lastQuery = match.query;\n lastTrigger = match.trigger;\n callbacksRef.current.onStart(props);\n } else if (\n match.query !== lastQuery ||\n match.trigger !== lastTrigger\n ) {\n // Only fire onUpdate when something actually changed\n lastQuery = match.query;\n lastTrigger = match.trigger;\n callbacksRef.current.onUpdate(props);\n }\n } else {\n if (active) {\n active = false;\n lastQuery = null;\n lastTrigger = null;\n callbacksRef.current.onExit();\n }\n }\n },\n\n destroy() {\n if (active) {\n callbacksRef.current.onExit();\n }\n },\n };\n },\n });\n\n return [plugin];\n },\n });\n}\n","import type { JSONContent } from \"@tiptap/core\";\nimport type { MentionToken } from \"../types/MentionToken\";\n\n/**\n * Serialize a Tiptap JSON document to a markdown string.\n *\n * Mention nodes are encoded as `@[label](id)` tokens.\n * All other text passes through verbatim.\n */\nexport function serializeToMarkdown(doc: JSONContent): string {\n if (!doc.content) return \"\";\n\n const parts: string[] = [];\n\n for (const block of doc.content) {\n if (block.type === \"paragraph\") {\n parts.push(serializeParagraph(block));\n } else if (block.type === \"text\") {\n parts.push(block.text ?? \"\");\n }\n }\n\n return parts.join(\"\\n\");\n}\n\nfunction serializeParagraph(node: JSONContent): string {\n if (!node.content) return \"\";\n\n return node.content\n .map((child) => {\n if (child.type === \"mention\") {\n const { id, label } = child.attrs ?? {};\n return `@[${label}](${id})`;\n }\n return child.text ?? \"\";\n })\n .join(\"\");\n}\n\n/**\n * Extract all `MentionToken`s from a Tiptap JSON document, in document order.\n */\nexport function extractTokens(doc: JSONContent): MentionToken[] {\n const tokens: MentionToken[] = [];\n\n function walk(node: JSONContent) {\n if (node.type === \"mention\" && node.attrs) {\n tokens.push({\n id: node.attrs.id as string,\n type: node.attrs.entityType as string,\n label: node.attrs.label as string,\n });\n }\n if (node.content) {\n for (const child of node.content) {\n walk(child);\n }\n }\n }\n\n walk(doc);\n return tokens;\n}\n\n/**\n * Extract plain text from a Tiptap JSON document.\n * Mention nodes are replaced with their label (no trigger prefix in plain text).\n */\nexport function extractPlainText(doc: JSONContent): string {\n if (!doc.content) return \"\";\n\n const parts: string[] = [];\n\n for (const block of doc.content) {\n if (block.type === \"paragraph\") {\n parts.push(extractParagraphText(block));\n }\n }\n\n return parts.join(\"\\n\");\n}\n\nfunction extractParagraphText(node: JSONContent): string {\n if (!node.content) return \"\";\n\n return node.content\n .map((child) => {\n if (child.type === \"mention\") {\n return child.attrs?.label ?? \"\";\n }\n return child.text ?? \"\";\n })\n .join(\"\");\n}\n","import type { JSONContent } from \"@tiptap/core\";\n\n/**\n * Regex matching the `@[label](id)` mention token syntax.\n *\n * Optionally captures an `entityType` when encoded as `@[label](type:id)`.\n * Falls back to `\"unknown\"` when no type prefix is present.\n */\nconst MENTION_RE = /@\\[([^\\]]+)\\]\\((?:([^:)]+):)?([^)]+)\\)/g;\n\n/**\n * Parse a markdown string (with `@[label](id)` or `@[label](type:id)` tokens)\n * into a Tiptap-compatible JSON document.\n */\nexport function parseFromMarkdown(markdown: string): JSONContent {\n const lines = markdown.split(\"\\n\");\n\n const content: JSONContent[] = lines.map((line) => ({\n type: \"paragraph\",\n content: parseLine(line),\n }));\n\n return { type: \"doc\", content };\n}\n\nfunction parseLine(line: string): JSONContent[] {\n const nodes: JSONContent[] = [];\n let lastIndex = 0;\n\n // Reset regex state\n MENTION_RE.lastIndex = 0;\n\n let match: RegExpExecArray | null;\n while ((match = MENTION_RE.exec(line)) !== null) {\n const fullMatch = match[0];\n const label = match[1];\n const entityType = match[2] ?? \"unknown\";\n const id = match[3];\n\n // Text before this mention\n if (match.index > lastIndex) {\n nodes.push({\n type: \"text\",\n text: line.slice(lastIndex, match.index),\n });\n }\n\n // Mention node\n nodes.push({\n type: \"mention\",\n attrs: {\n id,\n label,\n entityType,\n },\n });\n\n lastIndex = match.index + fullMatch.length;\n }\n\n // Trailing text\n if (lastIndex < line.length) {\n nodes.push({\n type: \"text\",\n text: line.slice(lastIndex),\n });\n }\n\n // Empty line — ProseMirror needs at least one node\n if (nodes.length === 0) {\n nodes.push({ type: \"text\", text: \"\" });\n }\n\n return nodes;\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport type { MentionItem, MentionProvider } from \"../types/MentionProvider\";\nimport type {\n SuggestionCallbackProps,\n SuggestionCallbacks,\n SuggestionCallbacksRef,\n SuggestionState,\n} from \"../core/suggestionPlugin\";\n\n/* ------------------------------------------------------------------ */\n/* Public state exposed to the UI layer */\n/* ------------------------------------------------------------------ */\n\nexport type SuggestionUIState = {\n state: SuggestionState;\n items: MentionItem[];\n breadcrumbs: MentionItem[];\n activeIndex: number;\n loading: boolean;\n clientRect: (() => DOMRect | null) | null;\n trigger: string | null;\n query: string;\n};\n\nexport type SuggestionActions = {\n navigateUp: () => void;\n navigateDown: () => void;\n select: (item?: MentionItem) => void;\n goBack: () => void;\n close: () => void;\n};\n\nconst IDLE_STATE: SuggestionUIState = {\n state: \"idle\",\n items: [],\n breadcrumbs: [],\n activeIndex: 0,\n loading: false,\n clientRect: null,\n trigger: null,\n query: \"\",\n};\n\n/* ------------------------------------------------------------------ */\n/* Hook */\n/* ------------------------------------------------------------------ */\n\nexport function useSuggestion(providers: MentionProvider[]) {\n const [uiState, setUIState] = useState<SuggestionUIState>(IDLE_STATE);\n\n // --- Refs for values that callbacks need to read (avoids stale closures) ---\n const stateRef = useRef(uiState);\n stateRef.current = uiState;\n\n const providersRef = useRef(providers);\n providersRef.current = providers;\n\n const commandRef = useRef<((attrs: Record<string, unknown>) => void) | null>(\n null,\n );\n const providerRef = useRef<MentionProvider | null>(null);\n\n /* ---------------------------------------------------------------- */\n /* Fetch items from the provider */\n /* ---------------------------------------------------------------- */\n\n const fetchItems = useCallback(\n async (\n provider: MentionProvider,\n query: string,\n parent?: MentionItem,\n ) => {\n setUIState((prev) => ({ ...prev, loading: true, state: \"loading\" }));\n\n try {\n const items =\n parent && provider.getChildren\n ? await provider.getChildren(parent, query)\n : await provider.getRootItems(query);\n\n setUIState((prev) => ({\n ...prev,\n items,\n loading: false,\n state: \"showing\",\n activeIndex: 0,\n }));\n } catch {\n setUIState((prev) => ({\n ...prev,\n items: [],\n loading: false,\n state: \"showing\",\n }));\n }\n },\n [],\n );\n\n /* ---------------------------------------------------------------- */\n /* Suggestion plugin callbacks */\n /* ---------------------------------------------------------------- */\n\n const onStart = useCallback(\n (props: SuggestionCallbackProps) => {\n const provider = providersRef.current.find(\n (p) => p.trigger === props.trigger,\n );\n if (!provider) return;\n\n providerRef.current = provider;\n commandRef.current = props.command;\n\n setUIState({\n state: \"loading\",\n items: [],\n breadcrumbs: [],\n activeIndex: 0,\n loading: true,\n clientRect: props.clientRect,\n trigger: props.trigger,\n query: props.query,\n });\n\n fetchItems(provider, props.query);\n },\n [fetchItems],\n );\n\n const onUpdate = useCallback(\n (props: SuggestionCallbackProps) => {\n const provider = providerRef.current;\n if (!provider) return;\n\n commandRef.current = props.command;\n\n setUIState((prev) => ({\n ...prev,\n clientRect: props.clientRect,\n query: props.query,\n }));\n\n // Only refetch at root level — nested levels manage their own queries\n // Read from ref to avoid stale closure\n if (stateRef.current.breadcrumbs.length === 0) {\n fetchItems(provider, props.query);\n }\n },\n [fetchItems],\n );\n\n const onExit = useCallback(() => {\n providerRef.current = null;\n commandRef.current = null;\n setUIState(IDLE_STATE);\n }, []);\n\n /* ---------------------------------------------------------------- */\n /* Navigation actions */\n /* ---------------------------------------------------------------- */\n\n const navigateUp = useCallback(() => {\n setUIState((prev) => ({\n ...prev,\n activeIndex: Math.max(0, prev.activeIndex - 1),\n }));\n }, []);\n\n const navigateDown = useCallback(() => {\n setUIState((prev) => ({\n ...prev,\n activeIndex: Math.min(prev.items.length - 1, prev.activeIndex + 1),\n }));\n }, []);\n\n const select = useCallback(\n (item?: MentionItem) => {\n const current = stateRef.current;\n const selected = item ?? current.items[current.activeIndex];\n if (!selected) return;\n\n const provider = providerRef.current;\n\n // If the item has children and the provider supports it, drill down\n if (selected.hasChildren && provider?.getChildren) {\n setUIState((prev) => ({\n ...prev,\n state: \"drilling\",\n breadcrumbs: [...prev.breadcrumbs, selected],\n items: [],\n activeIndex: 0,\n query: \"\",\n }));\n\n fetchItems(provider, \"\", selected);\n return;\n }\n\n // Otherwise insert the mention\n if (commandRef.current) {\n commandRef.current({\n id: selected.id,\n label: selected.label,\n entityType: selected.type,\n });\n }\n },\n [fetchItems],\n );\n\n const goBack = useCallback(() => {\n const provider = providerRef.current;\n if (!provider) return;\n\n setUIState((prev) => {\n const newBreadcrumbs = prev.breadcrumbs.slice(0, -1);\n const parent = newBreadcrumbs[newBreadcrumbs.length - 1];\n\n if (parent) {\n fetchItems(provider, \"\", parent);\n } else {\n fetchItems(provider, prev.query);\n }\n\n return {\n ...prev,\n breadcrumbs: newBreadcrumbs,\n items: [],\n activeIndex: 0,\n state: \"loading\" as const,\n };\n });\n }, [fetchItems]);\n\n const close = useCallback(() => {\n setUIState(IDLE_STATE);\n }, []);\n\n /* ---------------------------------------------------------------- */\n /* Keyboard handler */\n /* ---------------------------------------------------------------- */\n\n const onKeyDown = useCallback(\n ({ event }: { event: KeyboardEvent }): boolean => {\n const current = stateRef.current;\n if (current.state === \"idle\") return false;\n\n switch (event.key) {\n case \"ArrowUp\":\n event.preventDefault();\n navigateUp();\n return true;\n case \"ArrowDown\":\n event.preventDefault();\n navigateDown();\n return true;\n case \"Enter\": {\n event.preventDefault();\n const selectedItem = current.items[current.activeIndex];\n if (selectedItem) {\n select(selectedItem);\n }\n return true;\n }\n case \"ArrowRight\": {\n const activeItem = current.items[current.activeIndex];\n if (activeItem?.hasChildren) {\n event.preventDefault();\n select(activeItem);\n return true;\n }\n return false;\n }\n case \"ArrowLeft\":\n if (current.breadcrumbs.length > 0) {\n event.preventDefault();\n goBack();\n return true;\n }\n return false;\n case \"Escape\":\n event.preventDefault();\n close();\n return true;\n default:\n return false;\n }\n },\n [navigateUp, navigateDown, select, goBack, close],\n );\n\n /* ---------------------------------------------------------------- */\n /* Build a ref that always points to the latest callbacks. */\n /* The ProseMirror plugin reads from this ref — no stale closures. */\n /* ---------------------------------------------------------------- */\n\n const callbacksRef: SuggestionCallbacksRef = useRef<SuggestionCallbacks>({\n onStart,\n onUpdate,\n onExit,\n onKeyDown,\n });\n\n // Update on every render so the PM plugin always sees fresh functions\n callbacksRef.current = { onStart, onUpdate, onExit, onKeyDown };\n\n const actions: SuggestionActions = {\n navigateUp,\n navigateDown,\n select,\n goBack,\n close,\n };\n\n return { uiState, actions, callbacksRef };\n}\n","import React, { useEffect, useRef } from \"react\";\nimport type { ReactNode } from \"react\";\nimport type { MentionItem } from \"../types/MentionProvider\";\nimport { listboxAttrs, optionAttrs } from \"../utils/ariaHelpers\";\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\nexport type SuggestionListProps = {\n items: MentionItem[];\n activeIndex: number;\n breadcrumbs: MentionItem[];\n loading: boolean;\n trigger: string | null;\n clientRect: (() => DOMRect | null) | null;\n onSelect: (item: MentionItem) => void;\n onHover: (index: number) => void;\n onGoBack: () => void;\n renderItem?: (item: MentionItem, depth: number) => ReactNode;\n};\n\nconst LISTBOX_ID = \"mentions-suggestion-listbox\";\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nexport function SuggestionList({\n items,\n activeIndex,\n breadcrumbs,\n loading,\n trigger,\n clientRect,\n onSelect,\n onHover,\n onGoBack,\n renderItem,\n}: SuggestionListProps) {\n const listRef = useRef<HTMLDivElement>(null);\n const depth = breadcrumbs.length;\n\n // Scroll the active item into view\n useEffect(() => {\n if (!listRef.current) return;\n const active = listRef.current.querySelector('[aria-selected=\"true\"]');\n active?.scrollIntoView({ block: \"nearest\" });\n }, [activeIndex]);\n\n // Position the popover based on clientRect\n const style = usePopoverPosition(clientRect);\n\n if (items.length === 0 && !loading) return null;\n\n return (\n <div\n data-suggestions=\"\"\n data-trigger={trigger}\n style={style}\n ref={listRef}\n >\n {/* Breadcrumbs for nested navigation */}\n {breadcrumbs.length > 0 && (\n <div data-suggestion-breadcrumb=\"\">\n <button\n type=\"button\"\n data-suggestion-back=\"\"\n onClick={onGoBack}\n aria-label=\"Go back\"\n >\n &larr;\n </button>\n {breadcrumbs.map((crumb, i) => (\n <span key={crumb.id} data-suggestion-breadcrumb-item=\"\">\n {i > 0 && <span data-suggestion-breadcrumb-sep=\"\">/</span>}\n {crumb.label}\n </span>\n ))}\n </div>\n )}\n\n {/* Loading indicator */}\n {loading && (\n <div data-suggestion-loading=\"\">Loading...</div>\n )}\n\n {/* Item list */}\n {!loading && (\n <div {...listboxAttrs(LISTBOX_ID, `${trigger ?? \"\"} suggestions`)}>\n {items.map((item, index) => {\n const isActive = index === activeIndex;\n const itemId = `mention-option-${item.id}`;\n\n return (\n <div\n key={item.id}\n {...optionAttrs(itemId, isActive, index)}\n data-suggestion-item=\"\"\n data-suggestion-item-active={isActive ? \"\" : undefined}\n data-has-children={item.hasChildren ? \"\" : undefined}\n onMouseEnter={() => onHover(index)}\n onClick={() => onSelect(item)}\n >\n {renderItem ? (\n renderItem(item, depth)\n ) : (\n <DefaultSuggestionItem item={item} />\n )}\n </div>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Default item render */\n/* ------------------------------------------------------------------ */\n\nfunction DefaultSuggestionItem({ item }: { item: MentionItem }) {\n return (\n <>\n {item.icon && (\n <span data-suggestion-item-icon=\"\">{item.icon}</span>\n )}\n <span data-suggestion-item-label=\"\">{item.label}</span>\n {item.description && (\n <span data-suggestion-item-description=\"\">{item.description}</span>\n )}\n {item.hasChildren && (\n <span data-suggestion-item-chevron=\"\" aria-hidden=\"true\">\n &rsaquo;\n </span>\n )}\n </>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Popover positioning */\n/* ------------------------------------------------------------------ */\n\nfunction usePopoverPosition(\n clientRect: (() => DOMRect | null) | null,\n): React.CSSProperties {\n if (!clientRect) {\n return { display: \"none\" };\n }\n\n const rect = clientRect();\n if (!rect) {\n return { display: \"none\" };\n }\n\n return {\n position: \"fixed\",\n left: `${rect.left}px`,\n top: `${rect.bottom + 4}px`,\n zIndex: 50,\n };\n}\n","/**\n * Generates ARIA attributes for the suggestion combobox pattern.\n */\n\nexport function comboboxAttrs(expanded: boolean, listboxId: string) {\n return {\n role: \"combobox\" as const,\n \"aria-haspopup\": \"listbox\" as const,\n \"aria-expanded\": expanded,\n \"aria-owns\": expanded ? listboxId : undefined,\n };\n}\n\nexport function listboxAttrs(id: string, label: string) {\n return {\n id,\n role: \"listbox\" as const,\n \"aria-label\": label,\n };\n}\n\nexport function optionAttrs(\n id: string,\n selected: boolean,\n index: number,\n) {\n return {\n id,\n role: \"option\" as const,\n \"aria-selected\": selected,\n \"aria-posinset\": index + 1,\n };\n}\n"],"mappings":"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","names":["useCallback","Extension","Extension","editor","useCallback","useRef","useEffect","useRef","useRef","useEffect","jsx","jsxs","LISTBOX_ID","MentionsInput","useCallback"]}
1
+ {"version":3,"sources":["../src/components/MentionsInput.tsx","../src/hooks/useMentionsEditor.ts","../src/core/mentionExtension.ts","../src/core/suggestionPlugin.ts","../src/core/markdownSerializer.ts","../src/core/markdownParser.ts","../src/hooks/useSuggestion.ts","../src/components/SuggestionList.tsx","../src/utils/ariaHelpers.ts"],"sourcesContent":["import React, { forwardRef, useCallback, useImperativeHandle } from \"react\";\nimport { EditorContent } from \"@tiptap/react\";\nimport { useMentionsEditor } from \"../hooks/useMentionsEditor\";\nimport { useSuggestion } from \"../hooks/useSuggestion\";\nimport { SuggestionList } from \"./SuggestionList\";\nimport { comboboxAttrs } from \"../utils/ariaHelpers\";\nimport type {\n MentionsInputProps,\n MentionsInputHandle,\n} from \"../types/MentionsInputProps\";\n\nconst LISTBOX_ID = \"mentions-suggestion-listbox\";\n\n/**\n * `<MentionsInput>` — the single public component.\n *\n * A structured text editor with typed entity tokens.\n * Consumers register `providers` for each trigger character,\n * and receive structured output via `onChange` and `onSubmit`.\n *\n * Supports an imperative ref handle for programmatic control:\n * ```tsx\n * const ref = useRef<MentionsInputHandle>(null);\n * ref.current.clear();\n * ref.current.setContent(\"@[Marketing](ws_123) summarize\");\n * ref.current.focus();\n * ```\n */\nexport const MentionsInput = forwardRef<MentionsInputHandle, MentionsInputProps>(\n function MentionsInput(\n {\n value,\n providers,\n onChange,\n placeholder = \"Type a message...\",\n autoFocus = false,\n disabled = false,\n className,\n onSubmit,\n clearOnSubmit = true,\n maxLength,\n renderItem,\n renderChip,\n },\n ref,\n ) {\n const { uiState, actions, callbacksRef } = useSuggestion(providers);\n\n const { editor, clear, setContent, focus } = useMentionsEditor({\n providers,\n value,\n onChange,\n onSubmit,\n clearOnSubmit,\n placeholder,\n autoFocus,\n editable: !disabled,\n callbacksRef,\n });\n\n /* ---------------------------------------------------------------- */\n /* Expose imperative handle */\n /* ---------------------------------------------------------------- */\n\n useImperativeHandle(\n ref,\n () => ({ clear, setContent, focus }),\n [clear, setContent, focus],\n );\n\n const isExpanded = uiState.state !== \"idle\";\n\n const handleHover = useCallback((_index: number) => {\n // Direct setActiveIndex can be exposed if needed\n }, []);\n\n return (\n <div\n className={className}\n data-mentions-input=\"\"\n data-disabled={disabled ? \"\" : undefined}\n {...comboboxAttrs(isExpanded, LISTBOX_ID)}\n aria-activedescendant={\n isExpanded && uiState.items[uiState.activeIndex]\n ? `mention-option-${uiState.items[uiState.activeIndex].id}`\n : undefined\n }\n >\n <EditorContent editor={editor} />\n\n {isExpanded && (\n <SuggestionList\n items={uiState.items}\n activeIndex={uiState.activeIndex}\n breadcrumbs={uiState.breadcrumbs}\n loading={uiState.loading}\n trigger={uiState.trigger}\n clientRect={uiState.clientRect}\n onSelect={(item) => actions.select(item)}\n onHover={handleHover}\n onGoBack={actions.goBack}\n renderItem={renderItem}\n />\n )}\n </div>\n );\n },\n);\n","import { useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { useEditor } from \"@tiptap/react\";\nimport StarterKit from \"@tiptap/starter-kit\";\nimport Placeholder from \"@tiptap/extension-placeholder\";\nimport { Extension } from \"@tiptap/core\";\nimport { MentionNode } from \"../core/mentionExtension\";\nimport { createSuggestionExtension } from \"../core/suggestionPlugin\";\nimport {\n serializeToMarkdown,\n extractTokens,\n extractPlainText,\n} from \"../core/markdownSerializer\";\nimport { parseFromMarkdown } from \"../core/markdownParser\";\nimport type { MentionProvider } from \"../types/MentionProvider\";\nimport type { MentionsOutput } from \"../types/MentionsOutput\";\nimport type { SuggestionCallbacksRef } from \"../core/suggestionPlugin\";\n\n/* ------------------------------------------------------------------ */\n/* Helper: build MentionsOutput from the current editor */\n/* ------------------------------------------------------------------ */\n\nfunction buildOutput(editor: { getJSON: () => any }): MentionsOutput {\n const json = editor.getJSON();\n return {\n markdown: serializeToMarkdown(json),\n tokens: extractTokens(json),\n plainText: extractPlainText(json),\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Submit keyboard shortcut extension (Cmd+Enter) */\n/* ------------------------------------------------------------------ */\n\nfunction createSubmitExtension(\n onSubmitRef: React.RefObject<((output: MentionsOutput) => void) | undefined>,\n clearOnSubmitRef: React.RefObject<boolean>,\n) {\n return Extension.create({\n name: \"submitShortcut\",\n\n addKeyboardShortcuts() {\n return {\n \"Mod-Enter\": () => {\n if (onSubmitRef.current) {\n onSubmitRef.current(buildOutput(this.editor));\n if (clearOnSubmitRef.current) {\n this.editor.commands.clearContent(true);\n }\n }\n return true;\n },\n };\n },\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* Enter key — submit (only when suggestions are NOT active) */\n/* ------------------------------------------------------------------ */\n\nfunction createEnterExtension(\n onSubmitRef: React.RefObject<((output: MentionsOutput) => void) | undefined>,\n clearOnSubmitRef: React.RefObject<boolean>,\n) {\n return Extension.create({\n name: \"enterSubmit\",\n priority: 50,\n\n addKeyboardShortcuts() {\n return {\n Enter: () => {\n if (onSubmitRef.current) {\n onSubmitRef.current(buildOutput(this.editor));\n if (clearOnSubmitRef.current) {\n this.editor.commands.clearContent(true);\n }\n }\n return true;\n },\n };\n },\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* Hook */\n/* ------------------------------------------------------------------ */\n\ntype UseMentionsEditorOptions = {\n providers: MentionProvider[];\n value?: string;\n onChange?: (output: MentionsOutput) => void;\n onSubmit?: (output: MentionsOutput) => void;\n clearOnSubmit?: boolean;\n placeholder?: string;\n autoFocus?: boolean;\n editable?: boolean;\n callbacksRef: SuggestionCallbacksRef;\n};\n\nexport function useMentionsEditor({\n providers,\n value,\n onChange,\n onSubmit,\n clearOnSubmit = true,\n placeholder,\n autoFocus = false,\n editable = true,\n callbacksRef,\n}: UseMentionsEditorOptions) {\n // Stable refs for handlers that the PM plugin reads\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n const onSubmitRef = useRef(onSubmit);\n onSubmitRef.current = onSubmit;\n\n const clearOnSubmitRef = useRef(clearOnSubmit);\n clearOnSubmitRef.current = clearOnSubmit;\n\n // Build initial content from markdown value (only once)\n const initialContent = useMemo(() => {\n if (!value) return undefined;\n return parseFromMarkdown(value);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Extract trigger strings for memoisation key\n const triggersKey = providers.map((p) => p.trigger).join(\",\");\n const triggers = useMemo(\n () => providers.map((p) => p.trigger),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [triggersKey],\n );\n\n // Single suggestion extension — uses callbacksRef so always fresh\n const suggestionExtension = useMemo(\n () => createSuggestionExtension(triggers, callbacksRef),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [triggersKey],\n );\n\n // Submit extensions — use refs, stable across renders\n const submitExt = useMemo(\n () => createSubmitExtension(onSubmitRef, clearOnSubmitRef),\n [],\n );\n const enterExt = useMemo(\n () => createEnterExtension(onSubmitRef, clearOnSubmitRef),\n [],\n );\n\n const editor = useEditor({\n extensions: [\n StarterKit.configure({\n heading: false,\n blockquote: false,\n codeBlock: false,\n bulletList: false,\n orderedList: false,\n listItem: false,\n horizontalRule: false,\n }),\n Placeholder.configure({\n placeholder: placeholder ?? \"Type a message...\",\n }),\n MentionNode,\n suggestionExtension,\n submitExt,\n enterExt,\n ],\n content: initialContent,\n autofocus: autoFocus ? \"end\" : false,\n editable,\n editorProps: {\n attributes: {\n class: \"mentions-editor\",\n },\n },\n onUpdate: ({ editor }) => {\n onChangeRef.current?.(buildOutput(editor));\n },\n });\n\n // Sync editable state\n useEffect(() => {\n if (editor && editor.isEditable !== editable) {\n editor.setEditable(editable);\n }\n }, [editor, editable]);\n\n /* ---------------------------------------------------------------- */\n /* Imperative methods */\n /* ---------------------------------------------------------------- */\n\n const clear = useCallback(() => {\n editor?.commands.clearContent(true);\n }, [editor]);\n\n const setContent = useCallback(\n (markdown: string) => {\n if (!editor) return;\n const doc = parseFromMarkdown(markdown);\n editor.commands.setContent(doc);\n },\n [editor],\n );\n\n const focus = useCallback(() => {\n editor?.commands.focus(\"end\");\n }, [editor]);\n\n const getOutput = useCallback((): MentionsOutput | null => {\n if (!editor) return null;\n return buildOutput(editor);\n }, [editor]);\n\n return { editor, getOutput, clear, setContent, focus };\n}\n","import { mergeAttributes, Node } from \"@tiptap/core\";\nimport { NodeViewRendererProps } from \"@tiptap/core\";\nimport { ReactNodeViewRenderer } from \"@tiptap/react\";\n\nexport interface MentionNodeAttrs {\n id: string;\n label: string;\n entityType: string;\n}\n\n/**\n * Trigger-character prefix map.\n * Used when rendering a mention chip to prepend the correct character.\n */\nconst DEFAULT_PREFIXES: Record<string, string> = {\n workspace: \"@\",\n contract: \"@\",\n file: \"#\",\n web: \":\",\n};\n\n/**\n * Custom Tiptap Node extension for inline mention tokens.\n *\n * Each mention is an atomic inline node with `id`, `label`, and `entityType`\n * attributes. Renders as a `<span>` with `data-mention` and `data-type`\n * attributes for styling.\n */\nexport const MentionNode = Node.create({\n name: \"mention\",\n group: \"inline\",\n inline: true,\n atom: true,\n selectable: true,\n draggable: false,\n\n addAttributes() {\n return {\n id: {\n default: null,\n parseHTML: (element) => element.getAttribute(\"data-id\"),\n renderHTML: (attributes) => ({ \"data-id\": attributes.id }),\n },\n label: {\n default: null,\n parseHTML: (element) => element.getAttribute(\"data-label\"),\n renderHTML: (attributes) => ({ \"data-label\": attributes.label }),\n },\n entityType: {\n default: null,\n parseHTML: (element) => element.getAttribute(\"data-type\"),\n renderHTML: (attributes) => ({ \"data-type\": attributes.entityType }),\n },\n };\n },\n\n parseHTML() {\n return [{ tag: 'span[data-mention]' }];\n },\n\n renderHTML({ node, HTMLAttributes }) {\n const entityType = node.attrs.entityType as string;\n const label = node.attrs.label as string;\n const prefix = DEFAULT_PREFIXES[entityType] ?? \"@\";\n\n return [\n \"span\",\n mergeAttributes(HTMLAttributes, {\n \"data-mention\": \"\",\n class: \"mention-chip\",\n }),\n `${prefix}${label}`,\n ];\n },\n\n renderText({ node }) {\n const entityType = node.attrs.entityType as string;\n const label = node.attrs.label as string;\n const prefix = DEFAULT_PREFIXES[entityType] ?? \"@\";\n return `${prefix}${label}`;\n },\n\n addKeyboardShortcuts() {\n return {\n Backspace: () =>\n this.editor.commands.command(({ tr, state }) => {\n let isMention = false;\n const { selection } = state;\n const { empty, anchor } = selection;\n\n if (!empty) return false;\n\n state.doc.nodesBetween(anchor - 1, anchor, (node, pos) => {\n if (node.type.name === this.name) {\n isMention = true;\n tr.insertText(\"\", pos, pos + node.nodeSize);\n }\n });\n\n return isMention;\n }),\n };\n },\n});\n","import { Extension } from \"@tiptap/core\";\nimport { Plugin, PluginKey } from \"@tiptap/pm/state\";\nimport type { EditorView } from \"@tiptap/pm/view\";\nimport type { MentionItem, MentionProvider } from \"../types/MentionProvider\";\n\n/* ------------------------------------------------------------------ */\n/* Suggestion state types */\n/* ------------------------------------------------------------------ */\n\nexport type SuggestionState =\n | \"idle\"\n | \"loading\"\n | \"showing\"\n | \"drilling\"\n | \"inserting\";\n\n/* ------------------------------------------------------------------ */\n/* Callbacks the React layer implements */\n/* ------------------------------------------------------------------ */\n\nexport type SuggestionCallbacks = {\n onStart: (props: SuggestionCallbackProps) => void;\n onUpdate: (props: SuggestionCallbackProps) => void;\n onExit: () => void;\n onKeyDown: (props: { event: KeyboardEvent }) => boolean;\n};\n\nexport type SuggestionCallbackProps = {\n query: string;\n trigger: string;\n clientRect: (() => DOMRect | null) | null;\n range: { from: number; to: number };\n command: (attrs: Record<string, unknown>) => void;\n};\n\n/* ------------------------------------------------------------------ */\n/* Trigger detection */\n/* ------------------------------------------------------------------ */\n\ntype TriggerMatch = {\n trigger: string;\n query: string;\n from: number;\n to: number;\n};\n\nfunction detectTrigger(\n text: string,\n cursorPos: number,\n docStartPos: number,\n triggers: string[],\n): TriggerMatch | null {\n const relCursor = cursorPos - docStartPos;\n const before = text.slice(0, relCursor);\n\n for (let i = before.length - 1; i >= 0; i--) {\n const ch = before[i];\n if (ch === \"\\n\") return null;\n\n for (const trigger of triggers) {\n if (before.substring(i, i + trigger.length) === trigger) {\n if (i === 0 || /\\s/.test(before[i - 1])) {\n const query = before.slice(i + trigger.length);\n return { trigger, query, from: docStartPos + i, to: cursorPos };\n }\n }\n }\n }\n\n return null;\n}\n\n/* ------------------------------------------------------------------ */\n/* Plugin key */\n/* ------------------------------------------------------------------ */\n\nconst suggestionPluginKey = new PluginKey(\"mentionSuggestion\");\n\n/* ------------------------------------------------------------------ */\n/* Ref-based callback container (avoids stale closure issues) */\n/* ------------------------------------------------------------------ */\n\nexport type SuggestionCallbacksRef = { current: SuggestionCallbacks };\n\n/* ------------------------------------------------------------------ */\n/* Build the single multi-trigger suggestion extension */\n/* ------------------------------------------------------------------ */\n\nexport function createSuggestionExtension(\n triggers: string[],\n callbacksRef: SuggestionCallbacksRef,\n) {\n return Extension.create({\n name: \"mentionSuggestion\",\n\n addProseMirrorPlugins() {\n const editor = this.editor;\n let active = false;\n let lastQuery: string | null = null;\n let lastTrigger: string | null = null;\n\n const getClientRect = (\n view: EditorView,\n from: number,\n ): (() => DOMRect | null) => {\n return () => {\n try {\n const coords = view.coordsAtPos(from);\n return new DOMRect(\n coords.left,\n coords.top,\n 0,\n coords.bottom - coords.top,\n );\n } catch {\n return null;\n }\n };\n };\n\n const makeCommand = (range: { from: number; to: number }) => {\n return (attrs: Record<string, unknown>) => {\n editor\n .chain()\n .focus()\n .insertContentAt(range, [\n {\n type: \"mention\",\n attrs: {\n id: attrs.id,\n label: attrs.label,\n entityType: attrs.entityType,\n },\n },\n { type: \"text\", text: \" \" },\n ])\n .run();\n };\n };\n\n const plugin = new Plugin({\n key: suggestionPluginKey,\n\n props: {\n handleKeyDown(_view, event) {\n if (!active) return false;\n // Always read from the ref — never a stale closure\n return callbacksRef.current.onKeyDown({ event });\n },\n },\n\n view() {\n return {\n update(view, _prevState) {\n const { state } = view;\n const { selection } = state;\n\n if (!selection.empty) {\n if (active) {\n active = false;\n lastQuery = null;\n lastTrigger = null;\n callbacksRef.current.onExit();\n }\n return;\n }\n\n const $pos = selection.$from;\n const textBlock = $pos.parent;\n\n if (!textBlock.isTextblock) {\n if (active) {\n active = false;\n lastQuery = null;\n lastTrigger = null;\n callbacksRef.current.onExit();\n }\n return;\n }\n\n const blockStart = $pos.start();\n const blockText = textBlock.textContent;\n const cursorPos = $pos.pos;\n\n const match = detectTrigger(blockText, cursorPos, blockStart, triggers);\n\n if (match) {\n const range = { from: match.from, to: match.to };\n const props: SuggestionCallbackProps = {\n query: match.query,\n trigger: match.trigger,\n clientRect: getClientRect(view, match.from),\n range,\n command: makeCommand(range),\n };\n\n if (!active) {\n active = true;\n lastQuery = match.query;\n lastTrigger = match.trigger;\n callbacksRef.current.onStart(props);\n } else if (\n match.query !== lastQuery ||\n match.trigger !== lastTrigger\n ) {\n // Only fire onUpdate when something actually changed\n lastQuery = match.query;\n lastTrigger = match.trigger;\n callbacksRef.current.onUpdate(props);\n }\n } else {\n if (active) {\n active = false;\n lastQuery = null;\n lastTrigger = null;\n callbacksRef.current.onExit();\n }\n }\n },\n\n destroy() {\n if (active) {\n callbacksRef.current.onExit();\n }\n },\n };\n },\n });\n\n return [plugin];\n },\n });\n}\n","import type { JSONContent } from \"@tiptap/core\";\nimport type { MentionToken } from \"../types/MentionToken\";\n\n/**\n * Serialize a Tiptap JSON document to a markdown string.\n *\n * Mention nodes are encoded as `@[label](id)` tokens.\n * All other text passes through verbatim.\n */\nexport function serializeToMarkdown(doc: JSONContent): string {\n if (!doc.content) return \"\";\n\n const parts: string[] = [];\n\n for (const block of doc.content) {\n if (block.type === \"paragraph\") {\n parts.push(serializeParagraph(block));\n } else if (block.type === \"text\") {\n parts.push(block.text ?? \"\");\n }\n }\n\n return parts.join(\"\\n\");\n}\n\nfunction serializeParagraph(node: JSONContent): string {\n if (!node.content) return \"\";\n\n return node.content\n .map((child) => {\n if (child.type === \"mention\") {\n const { id, label } = child.attrs ?? {};\n return `@[${label}](${id})`;\n }\n return child.text ?? \"\";\n })\n .join(\"\");\n}\n\n/**\n * Extract all `MentionToken`s from a Tiptap JSON document, in document order.\n */\nexport function extractTokens(doc: JSONContent): MentionToken[] {\n const tokens: MentionToken[] = [];\n\n function walk(node: JSONContent) {\n if (node.type === \"mention\" && node.attrs) {\n tokens.push({\n id: node.attrs.id as string,\n type: node.attrs.entityType as string,\n label: node.attrs.label as string,\n });\n }\n if (node.content) {\n for (const child of node.content) {\n walk(child);\n }\n }\n }\n\n walk(doc);\n return tokens;\n}\n\n/**\n * Extract plain text from a Tiptap JSON document.\n * Mention nodes are replaced with their label (no trigger prefix in plain text).\n */\nexport function extractPlainText(doc: JSONContent): string {\n if (!doc.content) return \"\";\n\n const parts: string[] = [];\n\n for (const block of doc.content) {\n if (block.type === \"paragraph\") {\n parts.push(extractParagraphText(block));\n }\n }\n\n return parts.join(\"\\n\");\n}\n\nfunction extractParagraphText(node: JSONContent): string {\n if (!node.content) return \"\";\n\n return node.content\n .map((child) => {\n if (child.type === \"mention\") {\n return child.attrs?.label ?? \"\";\n }\n return child.text ?? \"\";\n })\n .join(\"\");\n}\n","import type { JSONContent } from \"@tiptap/core\";\n\n/**\n * Regex matching the `@[label](id)` mention token syntax.\n *\n * Optionally captures an `entityType` when encoded as `@[label](type:id)`.\n * Falls back to `\"unknown\"` when no type prefix is present.\n */\nconst MENTION_RE = /@\\[([^\\]]+)\\]\\((?:([^:)]+):)?([^)]+)\\)/g;\n\n/**\n * Parse a markdown string (with `@[label](id)` or `@[label](type:id)` tokens)\n * into a Tiptap-compatible JSON document.\n */\nexport function parseFromMarkdown(markdown: string): JSONContent {\n const lines = markdown.split(\"\\n\");\n\n const content: JSONContent[] = lines.map((line) => ({\n type: \"paragraph\",\n content: parseLine(line),\n }));\n\n return { type: \"doc\", content };\n}\n\nfunction parseLine(line: string): JSONContent[] {\n const nodes: JSONContent[] = [];\n let lastIndex = 0;\n\n // Reset regex state\n MENTION_RE.lastIndex = 0;\n\n let match: RegExpExecArray | null;\n while ((match = MENTION_RE.exec(line)) !== null) {\n const fullMatch = match[0];\n const label = match[1];\n const entityType = match[2] ?? \"unknown\";\n const id = match[3];\n\n // Text before this mention\n if (match.index > lastIndex) {\n nodes.push({\n type: \"text\",\n text: line.slice(lastIndex, match.index),\n });\n }\n\n // Mention node\n nodes.push({\n type: \"mention\",\n attrs: {\n id,\n label,\n entityType,\n },\n });\n\n lastIndex = match.index + fullMatch.length;\n }\n\n // Trailing text\n if (lastIndex < line.length) {\n nodes.push({\n type: \"text\",\n text: line.slice(lastIndex),\n });\n }\n\n // Empty line — ProseMirror needs at least one node\n if (nodes.length === 0) {\n nodes.push({ type: \"text\", text: \"\" });\n }\n\n return nodes;\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport type { MentionItem, MentionProvider } from \"../types/MentionProvider\";\nimport type {\n SuggestionCallbackProps,\n SuggestionCallbacks,\n SuggestionCallbacksRef,\n SuggestionState,\n} from \"../core/suggestionPlugin\";\n\n/* ------------------------------------------------------------------ */\n/* Public state exposed to the UI layer */\n/* ------------------------------------------------------------------ */\n\nexport type SuggestionUIState = {\n state: SuggestionState;\n items: MentionItem[];\n breadcrumbs: MentionItem[];\n activeIndex: number;\n loading: boolean;\n clientRect: (() => DOMRect | null) | null;\n trigger: string | null;\n query: string;\n};\n\nexport type SuggestionActions = {\n navigateUp: () => void;\n navigateDown: () => void;\n select: (item?: MentionItem) => void;\n goBack: () => void;\n close: () => void;\n};\n\nconst IDLE_STATE: SuggestionUIState = {\n state: \"idle\",\n items: [],\n breadcrumbs: [],\n activeIndex: 0,\n loading: false,\n clientRect: null,\n trigger: null,\n query: \"\",\n};\n\n/* ------------------------------------------------------------------ */\n/* Hook */\n/* ------------------------------------------------------------------ */\n\nexport function useSuggestion(providers: MentionProvider[]) {\n const [uiState, setUIState] = useState<SuggestionUIState>(IDLE_STATE);\n\n // --- Refs for values that callbacks need to read (avoids stale closures) ---\n const stateRef = useRef(uiState);\n stateRef.current = uiState;\n\n const providersRef = useRef(providers);\n providersRef.current = providers;\n\n const commandRef = useRef<((attrs: Record<string, unknown>) => void) | null>(\n null,\n );\n const providerRef = useRef<MentionProvider | null>(null);\n\n /* ---------------------------------------------------------------- */\n /* Fetch items from the provider */\n /* ---------------------------------------------------------------- */\n\n const fetchItems = useCallback(\n async (\n provider: MentionProvider,\n query: string,\n parent?: MentionItem,\n ) => {\n setUIState((prev) => ({ ...prev, loading: true, state: \"loading\" }));\n\n try {\n const items =\n parent && provider.getChildren\n ? await provider.getChildren(parent, query)\n : await provider.getRootItems(query);\n\n setUIState((prev) => ({\n ...prev,\n items,\n loading: false,\n state: \"showing\",\n activeIndex: 0,\n }));\n } catch {\n setUIState((prev) => ({\n ...prev,\n items: [],\n loading: false,\n state: \"showing\",\n }));\n }\n },\n [],\n );\n\n /* ---------------------------------------------------------------- */\n /* Suggestion plugin callbacks */\n /* ---------------------------------------------------------------- */\n\n const onStart = useCallback(\n (props: SuggestionCallbackProps) => {\n const provider = providersRef.current.find(\n (p) => p.trigger === props.trigger,\n );\n if (!provider) return;\n\n providerRef.current = provider;\n commandRef.current = props.command;\n\n setUIState({\n state: \"loading\",\n items: [],\n breadcrumbs: [],\n activeIndex: 0,\n loading: true,\n clientRect: props.clientRect,\n trigger: props.trigger,\n query: props.query,\n });\n\n fetchItems(provider, props.query);\n },\n [fetchItems],\n );\n\n const onUpdate = useCallback(\n (props: SuggestionCallbackProps) => {\n const provider = providerRef.current;\n if (!provider) return;\n\n commandRef.current = props.command;\n\n setUIState((prev) => ({\n ...prev,\n clientRect: props.clientRect,\n query: props.query,\n }));\n\n // Only refetch at root level — nested levels manage their own queries\n // Read from ref to avoid stale closure\n if (stateRef.current.breadcrumbs.length === 0) {\n fetchItems(provider, props.query);\n }\n },\n [fetchItems],\n );\n\n const onExit = useCallback(() => {\n providerRef.current = null;\n commandRef.current = null;\n setUIState(IDLE_STATE);\n }, []);\n\n /* ---------------------------------------------------------------- */\n /* Navigation actions */\n /* ---------------------------------------------------------------- */\n\n const navigateUp = useCallback(() => {\n setUIState((prev) => ({\n ...prev,\n activeIndex: Math.max(0, prev.activeIndex - 1),\n }));\n }, []);\n\n const navigateDown = useCallback(() => {\n setUIState((prev) => ({\n ...prev,\n activeIndex: Math.min(prev.items.length - 1, prev.activeIndex + 1),\n }));\n }, []);\n\n const select = useCallback(\n (item?: MentionItem) => {\n const current = stateRef.current;\n const selected = item ?? current.items[current.activeIndex];\n if (!selected) return;\n\n const provider = providerRef.current;\n\n // If the item has children and the provider supports it, drill down\n if (selected.hasChildren && provider?.getChildren) {\n setUIState((prev) => ({\n ...prev,\n state: \"drilling\",\n breadcrumbs: [...prev.breadcrumbs, selected],\n items: [],\n activeIndex: 0,\n query: \"\",\n }));\n\n fetchItems(provider, \"\", selected);\n return;\n }\n\n // Otherwise insert the mention\n if (commandRef.current) {\n commandRef.current({\n id: selected.id,\n label: selected.label,\n entityType: selected.type,\n });\n }\n },\n [fetchItems],\n );\n\n const goBack = useCallback(() => {\n const provider = providerRef.current;\n if (!provider) return;\n\n setUIState((prev) => {\n const newBreadcrumbs = prev.breadcrumbs.slice(0, -1);\n const parent = newBreadcrumbs[newBreadcrumbs.length - 1];\n\n if (parent) {\n fetchItems(provider, \"\", parent);\n } else {\n fetchItems(provider, prev.query);\n }\n\n return {\n ...prev,\n breadcrumbs: newBreadcrumbs,\n items: [],\n activeIndex: 0,\n state: \"loading\" as const,\n };\n });\n }, [fetchItems]);\n\n const close = useCallback(() => {\n setUIState(IDLE_STATE);\n }, []);\n\n /* ---------------------------------------------------------------- */\n /* Keyboard handler */\n /* ---------------------------------------------------------------- */\n\n const onKeyDown = useCallback(\n ({ event }: { event: KeyboardEvent }): boolean => {\n const current = stateRef.current;\n if (current.state === \"idle\") return false;\n\n switch (event.key) {\n case \"ArrowUp\":\n event.preventDefault();\n navigateUp();\n return true;\n case \"ArrowDown\":\n event.preventDefault();\n navigateDown();\n return true;\n case \"Enter\": {\n event.preventDefault();\n const selectedItem = current.items[current.activeIndex];\n if (selectedItem) {\n select(selectedItem);\n }\n return true;\n }\n case \"ArrowRight\": {\n const activeItem = current.items[current.activeIndex];\n if (activeItem?.hasChildren) {\n event.preventDefault();\n select(activeItem);\n return true;\n }\n return false;\n }\n case \"ArrowLeft\":\n if (current.breadcrumbs.length > 0) {\n event.preventDefault();\n goBack();\n return true;\n }\n return false;\n case \"Escape\":\n event.preventDefault();\n close();\n return true;\n default:\n return false;\n }\n },\n [navigateUp, navigateDown, select, goBack, close],\n );\n\n /* ---------------------------------------------------------------- */\n /* Build a ref that always points to the latest callbacks. */\n /* The ProseMirror plugin reads from this ref — no stale closures. */\n /* ---------------------------------------------------------------- */\n\n const callbacksRef: SuggestionCallbacksRef = useRef<SuggestionCallbacks>({\n onStart,\n onUpdate,\n onExit,\n onKeyDown,\n });\n\n // Update on every render so the PM plugin always sees fresh functions\n callbacksRef.current = { onStart, onUpdate, onExit, onKeyDown };\n\n const actions: SuggestionActions = {\n navigateUp,\n navigateDown,\n select,\n goBack,\n close,\n };\n\n return { uiState, actions, callbacksRef };\n}\n","import React, { useEffect, useRef } from \"react\";\nimport type { ReactNode } from \"react\";\nimport type { MentionItem } from \"../types/MentionProvider\";\nimport { listboxAttrs, optionAttrs } from \"../utils/ariaHelpers\";\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\nexport type SuggestionListProps = {\n items: MentionItem[];\n activeIndex: number;\n breadcrumbs: MentionItem[];\n loading: boolean;\n trigger: string | null;\n clientRect: (() => DOMRect | null) | null;\n onSelect: (item: MentionItem) => void;\n onHover: (index: number) => void;\n onGoBack: () => void;\n renderItem?: (item: MentionItem, depth: number) => ReactNode;\n};\n\nconst LISTBOX_ID = \"mentions-suggestion-listbox\";\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nexport function SuggestionList({\n items,\n activeIndex,\n breadcrumbs,\n loading,\n trigger,\n clientRect,\n onSelect,\n onHover,\n onGoBack,\n renderItem,\n}: SuggestionListProps) {\n const listRef = useRef<HTMLDivElement>(null);\n const depth = breadcrumbs.length;\n\n // Scroll the active item into view\n useEffect(() => {\n if (!listRef.current) return;\n const active = listRef.current.querySelector('[aria-selected=\"true\"]');\n active?.scrollIntoView({ block: \"nearest\" });\n }, [activeIndex]);\n\n // Position the popover based on clientRect\n const style = usePopoverPosition(clientRect);\n\n if (items.length === 0 && !loading) return null;\n\n return (\n <div\n data-suggestions=\"\"\n data-trigger={trigger}\n style={style}\n ref={listRef}\n >\n {/* Breadcrumbs for nested navigation */}\n {breadcrumbs.length > 0 && (\n <div data-suggestion-breadcrumb=\"\">\n <button\n type=\"button\"\n data-suggestion-back=\"\"\n onClick={onGoBack}\n aria-label=\"Go back\"\n >\n &larr;\n </button>\n {breadcrumbs.map((crumb, i) => (\n <span key={crumb.id} data-suggestion-breadcrumb-item=\"\">\n {i > 0 && <span data-suggestion-breadcrumb-sep=\"\">/</span>}\n {crumb.label}\n </span>\n ))}\n </div>\n )}\n\n {/* Loading indicator */}\n {loading && (\n <div data-suggestion-loading=\"\">Loading...</div>\n )}\n\n {/* Item list */}\n {!loading && (\n <div {...listboxAttrs(LISTBOX_ID, `${trigger ?? \"\"} suggestions`)}>\n {items.map((item, index) => {\n const isActive = index === activeIndex;\n const itemId = `mention-option-${item.id}`;\n\n return (\n <div\n key={item.id}\n {...optionAttrs(itemId, isActive, index)}\n data-suggestion-item=\"\"\n data-suggestion-item-active={isActive ? \"\" : undefined}\n data-has-children={item.hasChildren ? \"\" : undefined}\n onMouseEnter={() => onHover(index)}\n onClick={() => onSelect(item)}\n >\n {renderItem ? (\n renderItem(item, depth)\n ) : (\n <DefaultSuggestionItem item={item} />\n )}\n </div>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Default item render */\n/* ------------------------------------------------------------------ */\n\nfunction DefaultSuggestionItem({ item }: { item: MentionItem }) {\n return (\n <>\n {item.icon && (\n <span data-suggestion-item-icon=\"\">{item.icon}</span>\n )}\n <span data-suggestion-item-label=\"\">{item.label}</span>\n {item.description && (\n <span data-suggestion-item-description=\"\">{item.description}</span>\n )}\n {item.hasChildren && (\n <span data-suggestion-item-chevron=\"\" aria-hidden=\"true\">\n &rsaquo;\n </span>\n )}\n </>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Popover positioning */\n/* ------------------------------------------------------------------ */\n\nfunction usePopoverPosition(\n clientRect: (() => DOMRect | null) | null,\n): React.CSSProperties {\n if (!clientRect) {\n return { display: \"none\" };\n }\n\n const rect = clientRect();\n if (!rect) {\n return { display: \"none\" };\n }\n\n return {\n position: \"fixed\",\n left: `${rect.left}px`,\n top: `${rect.bottom + 4}px`,\n zIndex: 50,\n };\n}\n","/**\n * Generates ARIA attributes for the suggestion combobox pattern.\n */\n\nexport function comboboxAttrs(expanded: boolean, listboxId: string) {\n return {\n role: \"combobox\" as const,\n \"aria-haspopup\": \"listbox\" as const,\n \"aria-expanded\": expanded,\n \"aria-owns\": expanded ? listboxId : undefined,\n };\n}\n\nexport function listboxAttrs(id: string, label: string) {\n return {\n id,\n role: \"listbox\" as const,\n \"aria-label\": label,\n };\n}\n\nexport function optionAttrs(\n id: string,\n selected: boolean,\n index: number,\n) {\n return {\n id,\n role: \"option\" as const,\n \"aria-selected\": selected,\n \"aria-posinset\": index + 1,\n };\n}\n"],"mappings":"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","names":["useCallback","Extension","Extension","editor","useCallback","useRef","useEffect","useRef","useRef","useEffect","jsx","jsxs","LISTBOX_ID","MentionsInput","useCallback"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@relevaince/mentions",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Structured mention engine for Relevaince OMNI chat input",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -25,6 +25,7 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "@tiptap/core": "^2.11.5",
28
+ "@tiptap/extension-placeholder": "^2.27.2",
28
29
  "@tiptap/pm": "^2.11.5",
29
30
  "@tiptap/react": "^2.11.5",
30
31
  "@tiptap/starter-kit": "^2.11.5",