{"version":3,"file":"index.cjs","names":["escapeForRegEx","DecorationSet","Decoration","floatingUiOffset","floatingUiFlip","autoUpdate","PluginKey","defaultFindSuggestionMatch","clientRectFor","clientRectForHelper","shouldKeepDismissed","shouldKeepDismissedHelper","dispatchExit","dispatchExitHelper","Plugin"],"sources":["../src/findSuggestionMatch.ts","../src/helpers.ts","../src/plugin/props.ts","../src/plugin/state.ts","../src/plugin/async.ts","../src/plugin/floating-ui.ts","../src/plugin/view.ts","../src/suggestion.ts","../src/index.ts"],"sourcesContent":["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","import type { Editor, Range } from '@tiptap/core'\nimport type { EditorState, PluginKey, Transaction } from '@tiptap/pm/state'\nimport type { EditorView } from '@tiptap/pm/view'\n\nimport type { SuggestionMatch } from './findSuggestionMatch.js'\nimport type { SuggestionOptions, SuggestionPluginState } from './types.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 */\nexport function 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\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 */\nexport function getAnchorClientRect(editor: Editor): () => DOMRect | null {\n return () => {\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\n/**\n * Creates a clientRect callback for a given decoration node.\n * Returns the anchor rect when no decoration node is present.\n * Uses the pluginKey's state to resolve the current decoration node on demand.\n */\nexport function clientRectFor(\n editor: Editor,\n view: EditorView,\n decorationNode: Element | null,\n pluginKey: PluginKey,\n): () => DOMRect | null {\n if (!decorationNode) {\n return getAnchorClientRect(editor)\n }\n\n return () => {\n const state: SuggestionPluginState = pluginKey.getState(editor.state) as any\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/**\n * Determines whether a dismissed suggestion should stay dismissed.\n * Returns `true` (keep dismissed) or `false` (allow reactivation).\n */\nexport function shouldKeepDismissed({\n match,\n dismissedRange,\n state,\n transaction,\n editor,\n shouldResetDismissed,\n effectiveAllowSpaces,\n}: {\n match: Exclude\n dismissedRange: Range\n state: EditorState\n transaction: Transaction\n editor: Editor\n shouldResetDismissed?: SuggestionOptions['shouldResetDismissed']\n effectiveAllowSpaces: boolean\n}): boolean {\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/**\n * Dispatch an exit of the suggestion plugin by dispatching a metadata-only\n * transaction to clear the plugin state. The renderer's onExit hook is NOT\n * called here — it fires via the plugin view's stopped transition, which\n * builds SuggestionProps consistently with the normal lifecycle.\n *\n * This prevents a double onExit call (one from dispatchExit, one from the\n * view's update) and keeps exitSuggestion consistent with Escape-triggered\n * exits.\n */\nexport function dispatchExit({\n view,\n pluginKeyRef,\n}: {\n view: EditorView\n pluginKeyRef: PluginKey\n}): void {\n const tr = view.state.tr.setMeta(pluginKeyRef, { exit: true })\n view.dispatch(tr)\n}\n","import type { EditorState, PluginKey } from '@tiptap/pm/state'\nimport type { EditorView } from '@tiptap/pm/view'\nimport { Decoration, DecorationSet } from '@tiptap/pm/view'\n\nimport type { SuggestionKeyDownProps, SuggestionPluginState } from '../types.js'\n\n/**\n * Creates the `props` object for the suggestion ProseMirror plugin.\n * Contains `handleKeyDown` for keyboard handling and `decorations`\n * for rendering the suggestion highlight.\n */\nexport interface CreateSuggestionPropsOptions {\n pluginKey: PluginKey\n decorationTag: string\n decorationClass: string\n decorationContent: string\n decorationEmptyClass: string\n renderer: { onKeyDown?: (props: SuggestionKeyDownProps) => boolean } | undefined\n dispatchExit: (view: EditorView) => void\n}\n\n/**\n * Creates the `props` object for the suggestion ProseMirror plugin.\n * Contains `handleKeyDown` for keyboard handling and `decorations`\n * for rendering the suggestion highlight.\n */\nexport function createSuggestionProps({\n pluginKey,\n decorationTag,\n decorationClass,\n decorationContent,\n decorationEmptyClass,\n renderer,\n dispatchExit,\n}: CreateSuggestionPropsOptions) {\n return {\n /**\n * Call the keydown hook if suggestion is active.\n */\n handleKeyDown(view: EditorView, event: KeyboardEvent) {\n const state: SuggestionPluginState = pluginKey.getState(view.state) as any\n\n if (!state.active) {\n return false\n }\n\n // If Escape is pressed, call onKeyDown 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 // 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)\n\n return true\n }\n\n const handled = renderer?.onKeyDown?.({ view, event, range: state.range }) || false\n return handled\n },\n\n /**\n * Setup decorator on the currently active suggestion.\n */\n decorations(state: EditorState) {\n const pluginState: SuggestionPluginState = pluginKey.getState(state) as any\n const { active, range, decorationId, query } = pluginState\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 || undefined,\n 'data-decoration-content': decorationContent,\n }),\n ])\n },\n }\n}\n","import type { Editor, Range } from '@tiptap/core'\nimport type { EditorState, PluginKey, Transaction } from '@tiptap/pm/state'\n\nimport type {\n findSuggestionMatch as defaultFindSuggestionMatch,\n SuggestionMatch,\n} from '../findSuggestionMatch.js'\nimport type { SuggestionOptions, SuggestionPluginState } from '../types.js'\n\nexport interface CreateSuggestionStateOptions {\n editor: Editor\n char: string\n effectiveAllowSpaces: boolean\n allowToIncludeChar: boolean\n allowedPrefixes: string[] | null\n startOfLine: boolean\n findSuggestionMatch: typeof defaultFindSuggestionMatch\n allow: Exclude\n shouldShow?: SuggestionOptions['shouldShow']\n shouldKeepDismissed: (props: {\n match: Exclude\n dismissedRange: Range\n state: EditorState\n transaction: Transaction\n }) => boolean\n pluginKey: PluginKey\n}\n\n/**\n * Creates the `state` object for the suggestion ProseMirror plugin.\n * Contains `init()` and `apply()` for managing the plugin's internal state\n * across transactions.\n */\nexport function createSuggestionState({\n editor,\n char,\n effectiveAllowSpaces,\n allowToIncludeChar,\n allowedPrefixes,\n startOfLine,\n findSuggestionMatch,\n allow,\n shouldShow,\n shouldKeepDismissed,\n pluginKey,\n}: CreateSuggestionStateOptions) {\n return {\n /**\n * Initialize the plugin's internal state.\n */\n init(): SuggestionPluginState {\n return {\n active: false,\n range: { from: 0, to: 0 },\n query: null,\n text: null,\n composing: false,\n dismissedRange: null,\n }\n },\n\n /**\n * Apply changes to the plugin state from a view transaction.\n */\n apply(\n transaction: Transaction,\n prev: SuggestionPluginState,\n _oldState: EditorState,\n state: EditorState,\n ): SuggestionPluginState {\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: effectiveAllowSpaces,\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 || 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","import type { Editor } from '@tiptap/core'\n\nimport type { SuggestionOptions } from '../types.js'\n\nexport interface CreateSuggestionAsyncRequestManagerOptions {\n editor: Editor\n items: NonNullable['items']>\n}\n\ntype AsyncRequestResult =\n | { status: 'resolved'; items: I[] }\n | { status: 'aborted' }\n | { status: 'error' }\n\nexport function createSuggestionAsyncRequestManager({\n editor,\n items,\n}: CreateSuggestionAsyncRequestManagerOptions) {\n let abortController: AbortController | null = null\n let debounceTimer: ReturnType | null = null\n let debounceResolve: (() => void) | null = null\n\n const clearDebounceTimer = () => {\n if (debounceTimer !== null) {\n clearTimeout(debounceTimer)\n debounceTimer = null\n }\n\n debounceResolve?.()\n debounceResolve = null\n }\n\n const waitForDebounce = (delay: number) => {\n return new Promise(resolve => {\n debounceResolve = resolve\n debounceTimer = setTimeout(() => {\n debounceTimer = null\n const pendingResolve = debounceResolve\n debounceResolve = null\n pendingResolve?.()\n }, delay)\n })\n }\n\n const abort = () => {\n abortController?.abort()\n clearDebounceTimer()\n abortController = null\n }\n\n const fetch = async (query: string, debounce: number): Promise> => {\n abort()\n abortController = new AbortController()\n const controller = abortController\n\n if (debounce > 0) {\n await waitForDebounce(debounce)\n }\n\n if (abortController !== controller || controller.signal.aborted) {\n return { status: 'aborted' }\n }\n\n try {\n const result = await items({\n editor,\n query,\n signal: controller.signal,\n })\n\n if (abortController !== controller || controller.signal.aborted) {\n return { status: 'aborted' }\n }\n\n return { status: 'resolved', items: result }\n } catch {\n if (abortController !== controller || controller.signal.aborted) {\n return { status: 'aborted' }\n }\n\n return { status: 'error' }\n }\n }\n\n return {\n abort,\n fetch,\n }\n}\n","import type { Middleware, VirtualElement } from '@floating-ui/dom'\nimport {\n autoUpdate,\n computePosition,\n flip as floatingUiFlip,\n offset as floatingUiOffset,\n} from '@floating-ui/dom'\n\nimport type {\n SuggestionFloatingUiConfig,\n SuggestionFloatingUiOptions,\n SuggestionMount,\n SuggestionPlacement,\n} from '../types.js'\n\nexport interface CreateSuggestionFloatingUiConfigOptions {\n placement: SuggestionPlacement\n offset: { mainAxis?: number; crossAxis?: number }\n flip: boolean\n floatingUi?: SuggestionFloatingUiOptions\n}\n\nexport function createSuggestionFloatingUiConfig({\n placement,\n offset,\n flip,\n floatingUi,\n}: CreateSuggestionFloatingUiConfigOptions): SuggestionFloatingUiConfig {\n const middleware: Middleware[] = [\n floatingUiOffset({\n mainAxis: offset.mainAxis ?? 4,\n crossAxis: offset.crossAxis ?? 0,\n }),\n ]\n\n if (flip) {\n middleware.push(floatingUiFlip())\n }\n\n if (floatingUi?.middleware?.length) {\n middleware.push(...floatingUi.middleware)\n }\n\n return {\n placement,\n strategy: floatingUi?.strategy ?? 'absolute',\n middleware,\n }\n}\n\nexport interface CreateMountOptions {\n /** Returns the current cursor/anchor rect the popup should track. */\n getReferenceRect: () => DOMRect | null\n /**\n * An element inside the editor's layout/scroll context. Floating UI walks up\n * from here to discover the scroll ancestors (and the window) to observe, so\n * the scroll container does not need to be configured manually.\n */\n contextElement: Element\n /** Resolved Floating UI config (placement, strategy, middleware). */\n config: SuggestionFloatingUiConfig\n /**\n * CSS selector or element the popup should be mounted into. Defaults to\n * `document.body`. Used to portal the popup inside dialogs/modals so it\n * renders on top of (and clips within) the right context.\n */\n container?: string | HTMLElement\n /**\n * When `true`, a pointerdown outside both the popup and the editor dismisses\n * the suggestion. Wired up and torn down alongside the mounted element.\n */\n dismissOnOutsideClick: boolean\n /** Dismisses the active suggestion (used by outside-click handling). */\n dismiss: () => void\n}\n\n/**\n * Resolves a container option (selector or element) to a mount target,\n * falling back to `document.body` when it can't be resolved.\n */\nfunction resolveContainer(container?: string | HTMLElement): HTMLElement {\n if (container instanceof HTMLElement) {\n return container\n }\n\n if (typeof container === 'string') {\n try {\n // `container` is consumer-provided; an invalid selector throws a\n // DOMException, so fall back to document.body instead of crashing.\n const found = document.querySelector(container)\n\n if (found) {\n return found\n }\n } catch {\n return document.body\n }\n }\n\n return document.body\n}\n\n/**\n * Builds the `mount` function handed to the renderer on `SuggestionProps`.\n *\n * Mounts the popup into the container, then wires Floating UI's `autoUpdate`\n * against a virtual reference that re-reads the live cursor rect, so the popup\n * stays anchored across scroll, resize, and layout shifts without the consumer\n * attaching any listeners. The returned `unmount` tears all of that down.\n */\nexport function createMount({\n getReferenceRect,\n contextElement,\n config,\n container,\n dismissOnOutsideClick,\n dismiss,\n}: CreateMountOptions): SuggestionMount {\n return (element, options = {}) => {\n const reference: VirtualElement = {\n getBoundingClientRect: () => getReferenceRect() ?? new DOMRect(),\n contextElement,\n }\n\n let positioned = false\n\n // Mount the popup into the container (default `document.body`) unless the\n // consumer already placed it in the DOM themselves — in which case we leave\n // mounting (and unmounting) to them.\n const mountedByUs = !element.isConnected\n\n if (mountedByUs) {\n resolveContainer(container).appendChild(element)\n }\n\n // Hide the element until the first measurement resolves so it doesn't flash\n // at its initial coordinates. Skipped when the consumer owns applying the\n // position via `onPosition`.\n if (!options.onPosition) {\n element.style.visibility = 'hidden'\n element.style.width = 'max-content'\n }\n\n const update = () => {\n computePosition(reference, element, {\n placement: config.placement,\n strategy: config.strategy,\n middleware: config.middleware,\n }).then(({ x, y, placement, strategy }) => {\n if (options.onPosition) {\n options.onPosition({ x, y, placement: placement as SuggestionPlacement, strategy })\n return\n }\n\n Object.assign(element.style, {\n position: strategy,\n left: `${x}px`,\n top: `${y}px`,\n })\n\n if (!positioned) {\n positioned = true\n element.style.visibility = ''\n }\n })\n }\n\n const cleanupAutoUpdate = autoUpdate(reference, element, update, options.autoUpdate)\n\n // Dismiss when the user interacts outside both the popup and the editor.\n // Capture phase so a parent that stops propagation can't swallow it.\n let onOutsidePointerDown: ((event: PointerEvent) => void) | undefined\n\n if (dismissOnOutsideClick) {\n onOutsidePointerDown = event => {\n const target = event.target\n\n if (\n !(target instanceof Node) ||\n element.contains(target) ||\n contextElement.contains(target)\n ) {\n return\n }\n\n dismiss()\n }\n\n document.addEventListener('pointerdown', onOutsidePointerDown, true)\n }\n\n return () => {\n cleanupAutoUpdate()\n\n if (onOutsidePointerDown) {\n document.removeEventListener('pointerdown', onOutsidePointerDown, true)\n }\n\n if (mountedByUs) {\n element.remove()\n }\n }\n }\n}\n","import type { Editor } from '@tiptap/core'\nimport type { EditorState, PluginKey } from '@tiptap/pm/state'\nimport type { EditorView } from '@tiptap/pm/view'\n\nimport type {\n PluginState,\n SuggestionFloatingUiOptions,\n SuggestionOptions,\n SuggestionPlacement,\n SuggestionProps,\n} from '../types.js'\nimport { createSuggestionAsyncRequestManager } from './async.js'\nimport { createMount, createSuggestionFloatingUiConfig } from './floating-ui.js'\n\nexport interface CreateSuggestionViewOptions {\n editor: Editor\n pluginKey: PluginKey\n items: NonNullable\n renderer: ReturnType> | undefined\n minQueryLength: number\n debounce: number\n initialItems?: any[]\n placement: SuggestionPlacement\n offset: { mainAxis?: number; crossAxis?: number }\n container?: string | HTMLElement\n flip: boolean\n floatingUi?: SuggestionFloatingUiOptions\n dismissOnOutsideClick: boolean\n command: NonNullable\n clientRectFor: (view: EditorView, decorationNode: Element | null) => () => DOMRect | null\n dispatchExit: (view: EditorView) => void\n}\n\n/**\n * Creates the `view` object for the suggestion ProseMirror plugin.\n *\n * Manages the async lifecycle: tracks state transitions, calls renderer hooks,\n * fetches items with debounce and AbortController support.\n *\n * 1. Tracks plugin state transitions (started, updated, stopped) to determine when to call renderer hooks.\n * 2. Calls `onBeforeStart`, `onBeforeUpdate`, `onStart` before fetching to allow the renderer to prepare for first render\n * 3. Manages async fetching of suggestion items with support for debouncing and aborting in-flight requests\n * 4. Calls `onUpdate` after fetching new items to update the renderer with the latest data\n * 5. At the end calls a final `onExit` or `onUpdate` to allow the renderer to clean up or finalize the state\n */\nexport function createSuggestionView({\n editor,\n pluginKey,\n items,\n renderer,\n minQueryLength,\n debounce,\n initialItems,\n placement,\n offset: offsetOption,\n container,\n flip,\n floatingUi,\n dismissOnOutsideClick,\n command,\n clientRectFor,\n dispatchExit,\n}: CreateSuggestionViewOptions) {\n let props: SuggestionProps | undefined\n const asyncRequest = createSuggestionAsyncRequestManager({\n editor,\n items,\n })\n const floatingUiConfig = createSuggestionFloatingUiConfig({\n placement,\n offset: offsetOption,\n flip,\n floatingUi,\n })\n\n function dispatchStateUpdate(\n state: 'started' | 'updated' | 'stopped',\n dispatchProps: SuggestionProps,\n ) {\n switch (state) {\n case 'started':\n renderer?.onStart?.(dispatchProps)\n break\n case 'updated':\n renderer?.onUpdate?.(dispatchProps)\n break\n case 'stopped':\n renderer?.onExit?.(dispatchProps)\n break\n default:\n break\n }\n }\n\n return {\n update: async (view: EditorView, prevState: EditorState) => {\n const prev = pluginKey.getState(prevState)\n const next = pluginKey.getState(view.state)\n\n if (!prev || !next) {\n return\n }\n\n let currentState: 'started' | 'updated' | 'stopped' | null = null\n const queryChanged = prev.query !== next.query\n const textChanged = prev.text !== next.text\n const rangeChanged = prev.range.from !== next.range.from || prev.range.to !== next.range.to\n const effectiveQueryChanged = queryChanged || textChanged || rangeChanged\n\n if (!prev.active && next.active) {\n currentState = 'started'\n } else if (prev.active && !next.active) {\n currentState = 'stopped'\n } else if (next.active && effectiveQueryChanged) {\n currentState = 'updated'\n } else {\n return\n }\n\n const state = currentState === 'stopped' ? prev : next\n const decorationNode = view.dom.querySelector(`[data-decoration-id=\"${state.decorationId}\"]`)\n const clientRect = clientRectFor(view, decorationNode)\n\n const exceedsMinQueryLength =\n minQueryLength === 0 || (state.query ? state.query.length >= minQueryLength : false)\n const willFetch =\n (currentState === 'started' || currentState === 'updated') && exceedsMinQueryLength\n\n props = {\n editor,\n range: state.range,\n query: state.query || '',\n text: state.text || '',\n items: initialItems ?? [],\n command: commandProps => {\n return command({\n editor,\n range: state.range,\n props: commandProps,\n })\n },\n decorationNode,\n clientRect,\n loading: willFetch,\n placement,\n offset: { mainAxis: offsetOption.mainAxis ?? 4, crossAxis: offsetOption.crossAxis ?? 0 },\n container,\n flip,\n floatingUi: floatingUiConfig,\n mount: createMount({\n getReferenceRect: clientRect,\n contextElement: view.dom,\n config: floatingUiConfig,\n container,\n dismissOnOutsideClick,\n dismiss: () => dispatchExit(editor.view),\n }),\n }\n\n if (currentState === 'started') {\n renderer?.onBeforeStart?.(props)\n }\n\n if (currentState === 'updated') {\n renderer?.onBeforeUpdate?.(props)\n }\n\n // we run the start before we fetch\n // to allow for the component to render immediately\n if (currentState === 'started') {\n dispatchStateUpdate(currentState, props)\n }\n\n if (currentState === 'started' || currentState === 'updated') {\n if (!willFetch) {\n // Abort any in-flight request so stale results don't overwrite\n asyncRequest.abort()\n props = { ...props, items: initialItems ?? [], loading: false }\n } else {\n // update the renderer with loading state before we start the async fetch\n props = { ...props, items: initialItems ?? [], loading: true }\n currentState = 'updated'\n dispatchStateUpdate(currentState, props)\n\n const result = await asyncRequest.fetch(state.query || '', debounce)\n\n if (result.status === 'aborted') {\n return\n }\n\n // Re-check plugin state because the suggestion may have been dismissed\n const currentPluginState = pluginKey.getState(view.state)\n if (!currentPluginState?.active) {\n asyncRequest.abort()\n\n return\n }\n\n props =\n result.status === 'resolved'\n ? {\n ...props,\n items: result.items,\n loading: false,\n }\n : {\n ...props,\n loading: false,\n }\n }\n }\n\n if (currentState === 'stopped') {\n // stop running updates immediately and call onExit to allow the renderer to clean up\n asyncRequest.abort()\n dispatchStateUpdate(currentState, props)\n props = undefined\n return\n }\n\n if (currentState === 'updated') {\n dispatchStateUpdate(currentState, props)\n }\n },\n\n destroy: () => {\n asyncRequest.abort()\n\n if (!props) {\n return\n }\n\n renderer?.onExit?.(props)\n },\n }\n}\n","import type { 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'\n\nimport type { SuggestionMatch } from './findSuggestionMatch.js'\nimport { findSuggestionMatch as defaultFindSuggestionMatch } from './findSuggestionMatch.js'\nimport {\n clientRectFor as clientRectForHelper,\n dispatchExit as dispatchExitHelper,\n shouldKeepDismissed as shouldKeepDismissedHelper,\n} from './helpers.js'\nimport { createSuggestionProps } from './plugin/props.js'\nimport { createSuggestionState } from './plugin/state.js'\nimport { createSuggestionView } from './plugin/view.js'\nimport type { SuggestionOptions } from './types.js'\n\nexport type {\n SuggestionFloatingUiConfig,\n SuggestionFloatingUiOptions,\n SuggestionKeyDownProps,\n SuggestionMount,\n SuggestionMountOptions,\n SuggestionOptions,\n SuggestionPlacement,\n SuggestionPositionData,\n SuggestionProps,\n} from './types.js'\n\nexport const SuggestionPluginKey = new PluginKey('suggestion')\n\ntype ShouldKeepDismissedProps = {\n match: Exclude\n dismissedRange: Range\n state: EditorState\n transaction: Transaction\n}\n\n/**\n * This utility allows you to create suggestions.\n * @see https://tiptap.dev/api/utilities/suggestion\n */\nexport function Suggestion({\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 minQueryLength = 0,\n debounce = 0,\n initialItems,\n placement = 'bottom-start',\n offset: offsetOption = {},\n container,\n flip = true,\n floatingUi,\n dismissOnOutsideClick = true,\n render = () => ({}),\n allow = () => true,\n findSuggestionMatch = defaultFindSuggestionMatch,\n shouldShow,\n shouldResetDismissed,\n}: SuggestionOptions) {\n const renderer = render?.()\n const effectiveAllowSpaces = allowSpaces && !allowToIncludeChar\n\n const clientRectFor = (view: EditorView, decorationNode: Element | null) =>\n clientRectForHelper(editor, view, decorationNode, pluginKey)\n\n // helper to check if the dismissed suggestion should stay dismissed, with access to editor and options\n function shouldKeepDismissed(props: ShouldKeepDismissedProps) {\n return shouldKeepDismissedHelper({\n ...props,\n editor,\n shouldResetDismissed,\n effectiveAllowSpaces,\n })\n }\n\n const dispatchExit = (view: EditorView) =>\n dispatchExitHelper({\n view,\n pluginKeyRef: pluginKey,\n })\n\n return new Plugin({\n key: pluginKey,\n\n view: () =>\n createSuggestionView({\n editor,\n pluginKey,\n items,\n renderer,\n minQueryLength,\n debounce,\n initialItems,\n placement,\n offset: offsetOption,\n container,\n flip,\n floatingUi,\n dismissOnOutsideClick,\n command,\n clientRectFor,\n dispatchExit,\n }),\n\n state: createSuggestionState({\n editor,\n char,\n effectiveAllowSpaces,\n allowToIncludeChar,\n allowedPrefixes,\n startOfLine,\n findSuggestionMatch,\n allow,\n shouldShow,\n shouldKeepDismissed,\n pluginKey,\n }),\n\n props: createSuggestionProps({\n pluginKey,\n decorationTag,\n decorationClass,\n decorationContent,\n decorationEmptyClass,\n renderer,\n dispatchExit,\n }),\n })\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 { exitSuggestion, Suggestion } from './suggestion.js'\n\nexport * from './findSuggestionMatch.js'\nexport * from './suggestion.js'\n\nexport { exitSuggestion }\n\nexport default Suggestion\n"],"mappings":"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"}