{"version":3,"sources":["../src/index.ts","../src/suggestion.ts","../src/findSuggestionMatch.ts"],"sourcesContent":["import { exitSuggestion, Suggestion } from './suggestion.js'\n\nexport * from './findSuggestionMatch.js'\nexport * from './suggestion.js'\n\nexport { exitSuggestion }\n\nexport default Suggestion\n","import type { Editor, Range } from '@tiptap/core'\nimport type { EditorState, Transaction } from '@tiptap/pm/state'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport type { EditorView } from '@tiptap/pm/view'\nimport { Decoration, DecorationSet } from '@tiptap/pm/view'\n\nimport type { SuggestionMatch } from './findSuggestionMatch.js'\nimport { findSuggestionMatch as defaultFindSuggestionMatch } from './findSuggestionMatch.js'\n\n/**\n * Returns true if the transaction inserted any whitespace or newline character.\n * Used to determine when a dismissed suggestion should become active again.\n */\nfunction hasInsertedWhitespace(transaction: Transaction): boolean {\n  if (!transaction.docChanged) {\n    return false\n  }\n  return transaction.steps.some(step => {\n    const slice = (step as any).slice\n    if (!slice?.content) {\n      return false\n    }\n    // textBetween with '\\n' as block separator catches both inline spaces and newlines\n    const inserted = slice.content.textBetween(0, slice.content.size, '\\n')\n    return /\\s/.test(inserted)\n  })\n}\n\nexport interface SuggestionOptions<I = any, TSelected = any> {\n  /**\n   * The plugin key for the suggestion plugin.\n   * @default 'suggestion'\n   * @example 'mention'\n   */\n  pluginKey?: PluginKey\n\n  /**\n   * A function that returns a boolean to indicate if the suggestion should be active.\n   * This is useful to prevent suggestions from opening for remote users in collaborative environments.\n   * @param props The props object.\n   * @param props.editor The editor instance.\n   * @param props.range The range of the suggestion.\n   * @param props.query The current suggestion query.\n   * @param props.text The current suggestion text.\n   * @param props.transaction The current transaction.\n   * @returns {boolean}\n   * @example ({ transaction }) => isChangeOrigin(transaction)\n   */\n  shouldShow?: (props: {\n    editor: Editor\n    range: Range\n    query: string\n    text: string\n    transaction: Transaction\n  }) => boolean\n\n  /**\n   * Controls when a dismissed suggestion becomes active again.\n   * Return `true` to clear the dismissed context for the current transaction.\n   */\n  shouldResetDismissed?: (props: {\n    editor: Editor\n    state: EditorState\n    range: Range\n    match: Exclude<SuggestionMatch, null>\n    transaction: Transaction\n    allowSpaces: boolean\n  }) => boolean\n\n  /**\n   * The editor instance.\n   * @default null\n   */\n  editor: Editor\n\n  /**\n   * The character that triggers the suggestion.\n   * @default '@'\n   * @example '#'\n   */\n  char?: string\n\n  /**\n   * Allow spaces in the suggestion query. Not compatible with `allowToIncludeChar`. Will be disabled if `allowToIncludeChar` is set to `true`.\n   * @default false\n   * @example true\n   */\n  allowSpaces?: boolean\n\n  /**\n   * Allow the character to be included in the suggestion query. Not compatible with `allowSpaces`.\n   * @default false\n   */\n  allowToIncludeChar?: boolean\n\n  /**\n   * Allow prefixes in the suggestion query.\n   * @default [' ']\n   * @example [' ', '@']\n   */\n  allowedPrefixes?: string[] | null\n\n  /**\n   * Only match suggestions at the start of the line.\n   * @default false\n   * @example true\n   */\n  startOfLine?: boolean\n\n  /**\n   * The tag name of the decoration node.\n   * @default 'span'\n   * @example 'div'\n   */\n  decorationTag?: string\n\n  /**\n   * The class name of the decoration node.\n   * @default 'suggestion'\n   * @example 'mention'\n   */\n  decorationClass?: string\n\n  /**\n   * Creates a decoration with the provided content.\n   * @param decorationContent - The content to display in the decoration\n   * @default \"\" - Creates an empty decoration if no content provided\n   */\n  decorationContent?: string\n\n  /**\n   * The class name of the decoration node when it is empty.\n   * @default 'is-empty'\n   * @example 'is-empty'\n   */\n  decorationEmptyClass?: string\n\n  /**\n   * A function that is called when a suggestion is selected.\n   * @param props The props object.\n   * @param props.editor The editor instance.\n   * @param props.range The range of the suggestion.\n   * @param props.props The props of the selected suggestion.\n   * @returns void\n   * @example ({ editor, range, props }) => { props.command(props.props) }\n   */\n  command?: (props: { editor: Editor; range: Range; props: TSelected }) => void\n\n  /**\n   * A function that returns the suggestion items in form of an array.\n   * @param props The props object.\n   * @param props.editor The editor instance.\n   * @param props.query The current suggestion query.\n   * @returns An array of suggestion items.\n   * @example ({ editor, query }) => [{ id: 1, label: 'John Doe' }]\n   */\n  items?: (props: { query: string; editor: Editor }) => I[] | Promise<I[]>\n\n  /**\n   * The render function for the suggestion.\n   * @returns An object with render functions.\n   */\n  render?: () => {\n    onBeforeStart?: (props: SuggestionProps<I, TSelected>) => void\n    onStart?: (props: SuggestionProps<I, TSelected>) => void\n    onBeforeUpdate?: (props: SuggestionProps<I, TSelected>) => void\n    onUpdate?: (props: SuggestionProps<I, TSelected>) => void\n    onExit?: (props: SuggestionProps<I, TSelected>) => void\n    onKeyDown?: (props: SuggestionKeyDownProps) => boolean\n  }\n\n  /**\n   * A function that returns a boolean to indicate if the suggestion should be active.\n   * @param props The props object.\n   * @returns {boolean}\n   */\n  allow?: (props: {\n    editor: Editor\n    state: EditorState\n    range: Range\n    isActive?: boolean\n  }) => boolean\n  findSuggestionMatch?: typeof defaultFindSuggestionMatch\n}\n\nexport interface SuggestionProps<I = any, TSelected = any> {\n  /**\n   * The editor instance.\n   */\n  editor: Editor\n\n  /**\n   * The range of the suggestion.\n   */\n  range: Range\n\n  /**\n   * The current suggestion query.\n   */\n  query: string\n\n  /**\n   * The current suggestion text.\n   */\n  text: string\n\n  /**\n   * The suggestion items array.\n   */\n  items: I[]\n\n  /**\n   * A function that is called when a suggestion is selected.\n   * @param props The props object.\n   * @returns void\n   */\n  command: (props: TSelected) => void\n\n  /**\n   * The decoration node HTML element\n   * @default null\n   */\n  decorationNode: Element | null\n\n  /**\n   * The function that returns the client rect\n   * @default null\n   * @example () => new DOMRect(0, 0, 0, 0)\n   */\n  clientRect?: (() => DOMRect | null) | null\n}\n\nexport interface SuggestionKeyDownProps {\n  view: EditorView\n  event: KeyboardEvent\n  range: Range\n}\n\nexport const SuggestionPluginKey = new PluginKey('suggestion')\n\n/**\n * This utility allows you to create suggestions.\n * @see https://tiptap.dev/api/utilities/suggestion\n */\nexport function Suggestion<I = any, TSelected = any>({\n  pluginKey = SuggestionPluginKey,\n  editor,\n  char = '@',\n  allowSpaces = false,\n  allowToIncludeChar = false,\n  allowedPrefixes = [' '],\n  startOfLine = false,\n  decorationTag = 'span',\n  decorationClass = 'suggestion',\n  decorationContent = '',\n  decorationEmptyClass = 'is-empty',\n  command = () => null,\n  items = () => [],\n  render = () => ({}),\n  allow = () => true,\n  findSuggestionMatch = defaultFindSuggestionMatch,\n  shouldShow,\n  shouldResetDismissed,\n}: SuggestionOptions<I, TSelected>) {\n  let props: SuggestionProps<I, TSelected> | undefined\n  const renderer = render?.()\n  const effectiveAllowSpaces = allowSpaces && !allowToIncludeChar\n\n  // Gets the DOM rectangle corresponding to the current editor cursor anchor position\n  // Calculates screen coordinates based on Tiptap's cursor position and converts to a DOMRect object\n  const getAnchorClientRect = () => {\n    const pos = editor.state.selection.$anchor.pos\n    const coords = editor.view.coordsAtPos(pos)\n    const { top, right, bottom, left } = coords\n\n    try {\n      return new DOMRect(left, top, right - left, bottom - top)\n    } catch {\n      return null\n    }\n  }\n\n  // Helper to create a clientRect callback for a given decoration node.\n  // Returns null when no decoration node is present. Uses the pluginKey's\n  // state to resolve the current decoration node on demand, avoiding a\n  // duplicated implementation in multiple places.\n  const clientRectFor = (view: EditorView, decorationNode: Element | null) => {\n    if (!decorationNode) {\n      return getAnchorClientRect\n    }\n\n    return () => {\n      const state = pluginKey.getState(editor.state)\n      const decorationId = state?.decorationId\n      const currentDecorationNode = view.dom.querySelector(`[data-decoration-id=\"${decorationId}\"]`)\n\n      return currentDecorationNode?.getBoundingClientRect() || null\n    }\n  }\n\n  const shouldKeepDismissed = ({\n    match,\n    dismissedRange,\n    state,\n    transaction,\n  }: {\n    match: Exclude<SuggestionMatch, null>\n    dismissedRange: Range\n    state: EditorState\n    transaction: Transaction\n  }) => {\n    if (\n      shouldResetDismissed?.({\n        editor,\n        state,\n        range: dismissedRange,\n        match,\n        transaction,\n        allowSpaces: effectiveAllowSpaces,\n      })\n    ) {\n      return false\n    }\n\n    if (effectiveAllowSpaces) {\n      return match.range.from === dismissedRange.from\n    }\n\n    return match.range.from === dismissedRange.from && !hasInsertedWhitespace(transaction)\n  }\n\n  // small helper used internally by the view to dispatch an exit\n  function dispatchExit(view: EditorView, pluginKeyRef: PluginKey) {\n    try {\n      const state = pluginKey.getState(view.state)\n      const decorationNode = state?.decorationId\n        ? view.dom.querySelector(`[data-decoration-id=\"${state.decorationId}\"]`)\n        : null\n\n      const exitProps: SuggestionProps = {\n        // @ts-ignore editor is available in closure\n        editor,\n        range: state?.range || { from: 0, to: 0 },\n        query: state?.query || null,\n        text: state?.text || null,\n        items: [],\n        command: commandProps => {\n          return command({\n            editor,\n            range: state?.range || { from: 0, to: 0 },\n            props: commandProps as any,\n          })\n        },\n        decorationNode,\n        clientRect: clientRectFor(view, decorationNode),\n      }\n\n      renderer?.onExit?.(exitProps)\n    } catch {\n      // ignore errors from consumer renderers\n    }\n\n    const tr = view.state.tr.setMeta(pluginKeyRef, { exit: true })\n    // Dispatch a metadata-only transaction to signal the plugin to exit\n    view.dispatch(tr)\n  }\n\n  const plugin: Plugin<any> = new Plugin({\n    key: pluginKey,\n\n    view() {\n      return {\n        update: async (view, prevState) => {\n          const prev = this.key?.getState(prevState)\n          const next = this.key?.getState(view.state)\n\n          // See how the state changed\n          const moved = prev.active && next.active && prev.range.from !== next.range.from\n          const started = !prev.active && next.active\n          const stopped = prev.active && !next.active\n          const changed = !started && !stopped && prev.query !== next.query\n\n          const handleStart = started || (moved && changed)\n          const handleChange = changed || moved\n          const handleExit = stopped || (moved && changed)\n\n          // Cancel when suggestion isn't active\n          if (!handleStart && !handleChange && !handleExit) {\n            return\n          }\n\n          const state = handleExit && !handleStart ? prev : next\n          const decorationNode = view.dom.querySelector(\n            `[data-decoration-id=\"${state.decorationId}\"]`,\n          )\n\n          props = {\n            editor,\n            range: state.range,\n            query: state.query,\n            text: state.text,\n            items: [],\n            command: commandProps => {\n              return command({\n                editor,\n                range: state.range,\n                props: commandProps,\n              })\n            },\n            decorationNode,\n            clientRect: clientRectFor(view, decorationNode),\n          }\n\n          if (handleStart) {\n            renderer?.onBeforeStart?.(props)\n          }\n\n          if (handleChange) {\n            renderer?.onBeforeUpdate?.(props)\n          }\n\n          if (handleChange || handleStart) {\n            props.items = await items({\n              editor,\n              query: state.query,\n            })\n          }\n\n          if (handleExit) {\n            renderer?.onExit?.(props)\n          }\n\n          if (handleChange) {\n            renderer?.onUpdate?.(props)\n          }\n\n          if (handleStart) {\n            renderer?.onStart?.(props)\n          }\n        },\n\n        destroy: () => {\n          if (!props) {\n            return\n          }\n\n          renderer?.onExit?.(props)\n        },\n      }\n    },\n\n    state: {\n      // Initialize the plugin's internal state.\n      init() {\n        const state: {\n          active: boolean\n          range: Range\n          query: null | string\n          text: null | string\n          composing: boolean\n          decorationId?: string | null\n          dismissedRange: Range | null\n        } = {\n          active: false,\n          range: {\n            from: 0,\n            to: 0,\n          },\n          query: null,\n          text: null,\n          composing: false,\n          dismissedRange: null,\n        }\n\n        return state\n      },\n\n      // Apply changes to the plugin state from a view transaction.\n      apply(transaction, prev, _oldState, state) {\n        const { isEditable } = editor\n        const { composing } = editor.view\n        const { selection } = transaction\n        const { empty, from } = selection\n        const next = { ...prev }\n\n        // If a transaction carries the exit meta for this plugin, immediately\n        // deactivate the suggestion. This allows metadata-only transactions\n        // (dispatched by escape or programmatic exit) to deterministically\n        // clear decorations without changing the document.\n        const meta = transaction.getMeta(pluginKey)\n        if (meta && meta.exit) {\n          next.active = false\n          next.decorationId = null\n          next.range = { from: 0, to: 0 }\n          next.query = null\n          next.text = null\n          next.dismissedRange = prev.active ? { ...prev.range } : prev.dismissedRange\n\n          return next\n        }\n\n        next.composing = composing\n\n        if (transaction.docChanged && next.dismissedRange !== null) {\n          next.dismissedRange = {\n            from: transaction.mapping.map(next.dismissedRange.from),\n            to: transaction.mapping.map(next.dismissedRange.to),\n          }\n        }\n\n        // We can only be suggesting if the view is editable, and:\n        //   * there is no selection, or\n        //   * a composition is active (see: https://github.com/ueberdosis/tiptap/issues/1449)\n        if (isEditable && (empty || editor.view.composing)) {\n          // Reset active state if we just left the previous suggestion range\n          if ((from < prev.range.from || from > prev.range.to) && !composing && !prev.composing) {\n            next.active = false\n          }\n\n          // Try to match against where our cursor currently is\n          const match = findSuggestionMatch({\n            char,\n            allowSpaces,\n            allowToIncludeChar,\n            allowedPrefixes,\n            startOfLine,\n            $position: selection.$from,\n          })\n          const decorationId = `id_${Math.floor(Math.random() * 0xffffffff)}`\n\n          // If we found a match, update the current state to show it\n          if (\n            match &&\n            allow({\n              editor,\n              state,\n              range: match.range,\n              isActive: prev.active,\n            }) &&\n            (!shouldShow ||\n              shouldShow({\n                editor,\n                range: match.range,\n                query: match.query,\n                text: match.text,\n                transaction,\n              }))\n          ) {\n            if (\n              next.dismissedRange !== null &&\n              !shouldKeepDismissed({\n                match,\n                dismissedRange: next.dismissedRange,\n                state,\n                transaction,\n              })\n            ) {\n              next.dismissedRange = null\n            }\n\n            if (next.dismissedRange === null) {\n              next.active = true\n              next.decorationId = prev.decorationId ? prev.decorationId : decorationId\n              next.range = match.range\n              next.query = match.query\n              next.text = match.text\n            } else {\n              next.active = false\n            }\n          } else {\n            if (!match) {\n              next.dismissedRange = null\n            }\n            next.active = false\n          }\n        } else {\n          next.active = false\n        }\n\n        // Make sure to empty the range if suggestion is inactive\n        if (!next.active) {\n          next.decorationId = null\n          next.range = { from: 0, to: 0 }\n          next.query = null\n          next.text = null\n        }\n\n        return next\n      },\n    },\n\n    props: {\n      // Call the keydown hook if suggestion is active.\n      handleKeyDown(view, event) {\n        const { active, range } = plugin.getState(view.state)\n\n        if (!active) {\n          return false\n        }\n\n        // If Escape is pressed, call onExit and dispatch a metadata-only\n        // transaction to unset the suggestion state. This provides a safe\n        // and deterministic way to exit the suggestion without altering the\n        // document (avoids transaction mapping/mismatch issues).\n        if (event.key === 'Escape' || event.key === 'Esc') {\n          const state = plugin.getState(view.state)\n\n          // Allow the consumer to react to Escape, but always clear the\n          // suggestion state afterward so the decoration is removed too.\n          renderer?.onKeyDown?.({ view, event, range: state.range })\n\n          // dispatch metadata-only transaction to unset the plugin state\n          dispatchExit(view, pluginKey)\n\n          return true\n        }\n\n        const handled = renderer?.onKeyDown?.({ view, event, range }) || false\n        return handled\n      },\n\n      // Setup decorator on the currently active suggestion.\n      decorations(state) {\n        const { active, range, decorationId, query } = plugin.getState(state)\n\n        if (!active) {\n          return null\n        }\n\n        const isEmpty = !query?.length\n        const classNames = [decorationClass]\n\n        if (isEmpty) {\n          classNames.push(decorationEmptyClass)\n        }\n\n        return DecorationSet.create(state.doc, [\n          Decoration.inline(range.from, range.to, {\n            nodeName: decorationTag,\n            class: classNames.join(' '),\n            'data-decoration-id': decorationId,\n            'data-decoration-content': decorationContent,\n          }),\n        ])\n      },\n    },\n  })\n\n  return plugin\n}\n\n/**\n * Programmatically exit a suggestion plugin by dispatching a metadata-only\n * transaction. This is the safe, recommended API to remove suggestion\n * decorations without touching the document or causing mapping errors.\n */\nexport function exitSuggestion(view: EditorView, pluginKeyRef: PluginKey = SuggestionPluginKey) {\n  const tr = view.state.tr.setMeta(pluginKeyRef, { exit: true })\n  view.dispatch(tr)\n}\n","import type { Range } from '@tiptap/core'\nimport { escapeForRegEx } from '@tiptap/core'\nimport type { ResolvedPos } from '@tiptap/pm/model'\n\nexport interface Trigger {\n  char: string\n  allowSpaces: boolean\n  allowToIncludeChar: boolean\n  allowedPrefixes: string[] | null\n  startOfLine: boolean\n  $position: ResolvedPos\n}\n\nexport type SuggestionMatch = {\n  range: Range\n  query: string\n  text: string\n} | null\n\nexport function findSuggestionMatch(config: Trigger): SuggestionMatch {\n  const {\n    char,\n    allowSpaces: allowSpacesOption,\n    allowToIncludeChar,\n    allowedPrefixes,\n    startOfLine,\n    $position,\n  } = config\n\n  const allowSpaces = allowSpacesOption && !allowToIncludeChar\n\n  const escapedChar = escapeForRegEx(char)\n  const suffix = new RegExp(`\\\\s${escapedChar}$`)\n  const prefix = startOfLine ? '^' : ''\n  const finalEscapedChar = allowToIncludeChar ? '' : escapedChar\n  const regexp = allowSpaces\n    ? new RegExp(`${prefix}${escapedChar}.*?(?=\\\\s${finalEscapedChar}|$)`, 'gm')\n    : new RegExp(`${prefix}(?:^)?${escapedChar}[^\\\\s${finalEscapedChar}]*`, 'gm')\n\n  const text = $position.nodeBefore?.isText && $position.nodeBefore.text\n\n  if (!text) {\n    return null\n  }\n\n  const textFrom = $position.pos - text.length\n  const match = Array.from(text.matchAll(regexp)).pop()\n\n  if (!match || match.input === undefined || match.index === undefined) {\n    return null\n  }\n\n  // JavaScript doesn't have lookbehinds. This hacks a check that first character\n  // is a space or the start of the line\n  const matchPrefix = match.input.slice(Math.max(0, match.index - 1), match.index)\n  const matchPrefixIsAllowed = new RegExp(`^[${allowedPrefixes?.join('')}\\0]?$`).test(matchPrefix)\n\n  if (allowedPrefixes !== null && !matchPrefixIsAllowed) {\n    return null\n  }\n\n  // The absolute position of the match in the document\n  const from = textFrom + match.index\n  let to = from + match[0].length\n\n  // Edge case handling; if spaces are allowed and we're directly in between\n  // two triggers\n  if (allowSpaces && suffix.test(text.slice(to - 1, to + 1))) {\n    match[0] += ' '\n    to += 1\n  }\n\n  // If the $position is located within the matched substring, return that range\n  if (from < $position.pos && to >= $position.pos) {\n    return {\n      range: {\n        from,\n        to,\n      },\n      query: match[0].slice(char.length),\n      text: match[0],\n    }\n  }\n\n  return null\n}\n"],"mappings":"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","names":["findSuggestionMatch"]}