{"version":3,"file":"index.js","names":["ProseMirrorNode"],"sources":["../src/utils/get-default-suggestion-attributes.ts","../src/mention.ts","../src/index.ts"],"sourcesContent":["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","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 = /(?:^|\\s)(\\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 { Mention } from './mention.js'\n\nexport * from './mention.js'\n\nexport default Mention\n"],"mappings":"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"}