{"version":3,"sources":["../src/index.ts","../src/mention.ts","../src/utils/get-default-suggestion-attributes.ts"],"sourcesContent":["import { Mention } from './mention.js'\n\nexport * from './mention.js'\n\nexport default Mention\n","import type { Editor } from '@tiptap/core'\nimport { createInlineMarkdownSpec, mergeAttributes, Node } from '@tiptap/core'\nimport type { DOMOutputSpec } from '@tiptap/pm/model'\nimport { Node as ProseMirrorNode } from '@tiptap/pm/model'\nimport type { SuggestionOptions } from '@tiptap/suggestion'\nimport { Suggestion } from '@tiptap/suggestion'\n\nimport { getSuggestionOptions } from './utils/get-default-suggestion-attributes.js'\n\n// See `addAttributes` below\nexport interface MentionNodeAttrs {\n /**\n * The identifier for the selected item that was mentioned, stored as a `data-id`\n * attribute.\n */\n id: string | null\n /**\n * The label to be rendered by the editor as the displayed text for this mentioned\n * item, if provided. Stored as a `data-label` attribute. See `renderLabel`.\n */\n label?: string | null\n /**\n * The character that triggers the suggestion, stored as\n * `data-mention-suggestion-char` attribute.\n */\n mentionSuggestionChar?: string\n}\n\nexport interface MentionOptions<\n SuggestionItem = any,\n Attrs extends Record = MentionNodeAttrs,\n> {\n /**\n * The HTML attributes for a mention node.\n * @default {}\n * @example { class: 'foo' }\n */\n HTMLAttributes: Record\n\n /**\n * A function to render the label of a mention.\n * @deprecated use renderText and renderHTML instead\n * @param props The render props\n * @returns The label\n * @example ({ options, node }) => `${options.suggestion.char}${node.attrs.label ?? node.attrs.id}`\n */\n renderLabel?: (props: {\n options: MentionOptions\n node: ProseMirrorNode\n suggestion: SuggestionOptions | null\n }) => string\n\n /**\n * A function to render the text of a mention.\n * @param props The render props\n * @returns The text\n * @example ({ options, node }) => `${options.suggestion.char}${node.attrs.label ?? node.attrs.id}`\n */\n renderText: (props: {\n options: MentionOptions\n node: ProseMirrorNode\n suggestion: SuggestionOptions | null\n }) => string\n\n /**\n * A function to render the HTML of a mention.\n * @param props The render props\n * @returns The HTML as a ProseMirror DOM Output Spec\n * @example ({ options, node }) => ['span', { 'data-type': 'mention' }, `${options.suggestion.char}${node.attrs.label ?? node.attrs.id}`]\n */\n renderHTML: (props: {\n options: MentionOptions\n node: ProseMirrorNode\n suggestion: SuggestionOptions | null\n }) => DOMOutputSpec\n\n /**\n * Whether to delete the trigger character with backspace.\n * @default false\n */\n deleteTriggerWithBackspace: boolean\n\n /**\n * The suggestion options, when you want to support multiple triggers.\n *\n * With this parameter, you can define multiple types of mention. For example, you can use the `@` character\n * to mention users and the `#` character to mention tags.\n *\n * @default [{ char: '@', pluginKey: MentionPluginKey }]\n * @example [{ char: '@', pluginKey: MentionPluginKey }, { char: '#', pluginKey: new PluginKey('hashtag') }]\n */\n suggestions: Array, 'editor'>>\n\n /**\n * The suggestion options, when you want to support only one trigger. To support multiple triggers, use the\n * `suggestions` parameter instead.\n *\n * @default {}\n * @example { char: '@', pluginKey: MentionPluginKey, command: ({ editor, range, props }) => { ... } }\n */\n suggestion: Omit, 'editor'>\n}\n\ninterface GetSuggestionsOptions {\n editor?: Editor\n options: MentionOptions\n name: string\n}\n\n/**\n * Returns the suggestions for the mention extension.\n *\n * @param options The extension options\n * @returns the suggestions\n */\nfunction getSuggestions(options: GetSuggestionsOptions) {\n return (\n options.options.suggestions.length ? options.options.suggestions : [options.options.suggestion]\n ).map(suggestion =>\n getSuggestionOptions({\n // @ts-ignore `editor` can be `undefined` when converting the document to HTML with the HTML utility\n editor: options.editor,\n overrideSuggestionOptions: suggestion,\n extensionName: options.name,\n char: suggestion.char,\n }),\n )\n}\n\n/**\n * Returns the suggestion options of the mention that has a given character trigger. If not\n * found, it returns the first suggestion.\n *\n * @param options The extension options\n * @param char The character that triggers the mention\n * @returns The suggestion options\n */\nfunction getSuggestionFromChar(options: GetSuggestionsOptions, char: string) {\n const suggestions = getSuggestions(options)\n\n const suggestion = suggestions.find(s => s.char === char)\n if (suggestion) {\n return suggestion\n }\n\n if (suggestions.length) {\n return suggestions[0]\n }\n\n return null\n}\n\n/**\n * This extension allows you to insert mentions into the editor.\n * @see https://www.tiptap.dev/api/extensions/mention\n */\nexport const Mention = Node.create({\n name: 'mention',\n\n priority: 101,\n\n addOptions() {\n return {\n HTMLAttributes: {},\n renderText({ node, suggestion }) {\n return `${suggestion?.char ?? '@'}${node.attrs.label ?? node.attrs.id}`\n },\n deleteTriggerWithBackspace: false,\n renderHTML({ options, node, suggestion }) {\n return [\n 'span',\n mergeAttributes(this.HTMLAttributes, options.HTMLAttributes),\n `${suggestion?.char ?? '@'}${node.attrs.label ?? node.attrs.id}`,\n ]\n },\n suggestions: [],\n suggestion: {},\n }\n },\n\n group: 'inline',\n\n inline: true,\n\n selectable: false,\n\n atom: true,\n\n addAttributes() {\n return {\n id: {\n default: null,\n parseHTML: element => element.getAttribute('data-id'),\n renderHTML: attributes => {\n if (!attributes.id) {\n return {}\n }\n\n return {\n 'data-id': attributes.id,\n }\n },\n },\n\n label: {\n default: null,\n parseHTML: element => element.getAttribute('data-label'),\n renderHTML: attributes => {\n if (!attributes.label) {\n return {}\n }\n\n return {\n 'data-label': attributes.label,\n }\n },\n },\n\n // When there are multiple types of mentions, this attribute helps distinguish them\n mentionSuggestionChar: {\n default: '@',\n parseHTML: element => element.getAttribute('data-mention-suggestion-char'),\n renderHTML: attributes => {\n return {\n 'data-mention-suggestion-char': attributes.mentionSuggestionChar,\n }\n },\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: `span[data-type=\"${this.name}\"]`,\n },\n ]\n },\n\n renderHTML({ node, HTMLAttributes }) {\n const suggestion = getSuggestionFromChar(this, node.attrs.mentionSuggestionChar)\n\n if (this.options.renderLabel !== undefined) {\n console.warn('renderLabel is deprecated use renderText and renderHTML instead')\n return [\n 'span',\n mergeAttributes({ 'data-type': this.name }, this.options.HTMLAttributes, HTMLAttributes),\n this.options.renderLabel({\n options: this.options,\n node,\n suggestion,\n }),\n ]\n }\n const mergedOptions = { ...this.options }\n\n mergedOptions.HTMLAttributes = mergeAttributes(\n { 'data-type': this.name },\n this.options.HTMLAttributes,\n HTMLAttributes,\n )\n\n const html = this.options.renderHTML({\n options: mergedOptions,\n node,\n suggestion,\n })\n\n if (typeof html === 'string') {\n return [\n 'span',\n mergeAttributes({ 'data-type': this.name }, this.options.HTMLAttributes, HTMLAttributes),\n html,\n ]\n }\n return html\n },\n\n ...createInlineMarkdownSpec({\n nodeName: 'mention',\n name: '@',\n selfClosing: true,\n allowedAttributes: ['id', 'label', { name: 'mentionSuggestionChar', skipIfDefault: '@' }],\n parseAttributes: (attrString: string) => {\n const attrs: Record = {}\n const regex = /(\\w+)=(?:\"([^\"]*)\"|'([^']*)')/g\n let match = regex.exec(attrString)\n\n while (match !== null) {\n const [, key, doubleQuoted, singleQuoted] = match\n const value = doubleQuoted ?? singleQuoted\n attrs[key === 'char' ? 'mentionSuggestionChar' : key] = value\n match = regex.exec(attrString)\n }\n\n return attrs\n },\n serializeAttributes: (attrs: Record) => {\n return Object.entries(attrs)\n .filter(([, value]) => value !== undefined && value !== null)\n .map(([key, value]) => {\n const serializedKey = key === 'mentionSuggestionChar' ? 'char' : key\n return `${serializedKey}=\"${value}\"`\n })\n .join(' ')\n },\n }),\n\n renderText({ node }) {\n const args = {\n options: this.options,\n node,\n suggestion: getSuggestionFromChar(this, node.attrs.mentionSuggestionChar),\n }\n if (this.options.renderLabel !== undefined) {\n console.warn('renderLabel is deprecated use renderText and renderHTML instead')\n return this.options.renderLabel(args)\n }\n\n return this.options.renderText(args)\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) {\n return false\n }\n\n // Store node and position for later use\n let mentionNode = new ProseMirrorNode()\n let mentionPos = 0\n\n state.doc.nodesBetween(anchor - 1, anchor, (node, pos) => {\n if (node.type.name === this.name) {\n isMention = true\n mentionNode = node\n mentionPos = pos\n return false\n }\n })\n\n if (isMention) {\n tr.insertText(\n this.options.deleteTriggerWithBackspace\n ? ''\n : mentionNode.attrs.mentionSuggestionChar,\n mentionPos,\n mentionPos + mentionNode.nodeSize,\n )\n }\n\n return isMention\n }),\n }\n },\n\n addProseMirrorPlugins() {\n // Create a plugin for each suggestion configuration\n return getSuggestions(this).map(Suggestion)\n },\n})\n","import type { Editor } from '@tiptap/core'\nimport { PluginKey } from '@tiptap/pm/state'\nimport type { SuggestionOptions } from '@tiptap/suggestion'\n\n/**\n * Arguments for the `getSuggestionOptions` function\n * @see getSuggestionOptions\n */\nexport interface GetSuggestionOptionsOptions {\n /**\n * The Tiptap editor instance.\n */\n editor: Editor\n /**\n * The suggestion options configuration provided to the\n * `Mention` extension.\n */\n overrideSuggestionOptions: Omit\n /**\n * The name of the Mention extension\n */\n extensionName: string\n /**\n * The character that triggers the suggestion.\n * @default '@'\n */\n char?: string\n}\n\n/**\n * Returns the suggestion options for a trigger of the Mention extension. These\n * options are used to create a `Suggestion` ProseMirror plugin. Each plugin lets\n * you define a different trigger that opens the Mention menu. For example,\n * you can define a `@` trigger to mention users and a `#` trigger to mention\n * tags.\n *\n * @param param0 The configured options for the suggestion\n * @returns\n */\nexport function getSuggestionOptions({\n editor: tiptapEditor,\n overrideSuggestionOptions,\n extensionName,\n char = '@',\n}: GetSuggestionOptionsOptions): SuggestionOptions {\n const pluginKey = new PluginKey()\n\n return {\n editor: tiptapEditor,\n char,\n pluginKey,\n command: ({ editor, range, props }: { editor: any; range: any; props: any }) => {\n // increase range.to by one when the next node is of type \"text\"\n // and starts with a space character\n const nodeAfter = editor.view.state.selection.$to.nodeAfter\n const overrideSpace = nodeAfter?.text?.startsWith(' ')\n\n if (overrideSpace) {\n range.to += 1\n }\n\n editor\n .chain()\n .focus()\n .insertContentAt(range, [\n {\n type: extensionName,\n attrs: { ...props, mentionSuggestionChar: char },\n },\n {\n type: 'text',\n text: ' ',\n },\n ])\n .run()\n\n // get reference to `window` object from editor element, to support cross-frame JS usage\n editor.view.dom.ownerDocument.defaultView?.getSelection()?.collapseToEnd()\n },\n allow: ({ state, range }: { state: any; range: any }) => {\n const $from = state.doc.resolve(range.from)\n const type = state.schema.nodes[extensionName]\n const allow = !!$from.parent.type.contentMatch.matchType(type)\n\n return allow\n },\n ...overrideSuggestionOptions,\n }\n}\n"],"mappings":"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","names":["ProseMirrorNode"]}