261 lines
9.7 KiB
JavaScript
261 lines
9.7 KiB
JavaScript
'use strict';
|
|
|
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
|
var core = require('@tiptap/core');
|
|
var model = require('@tiptap/pm/model');
|
|
var Suggestion = require('@tiptap/suggestion');
|
|
var state = require('@tiptap/pm/state');
|
|
|
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
|
|
var Suggestion__default = /*#__PURE__*/_interopDefaultCompat(Suggestion);
|
|
|
|
/**
|
|
* Returns the suggestion options for a trigger of the Mention extension. These
|
|
* options are used to create a `Suggestion` ProseMirror plugin. Each plugin lets
|
|
* you define a different trigger that opens the Mention menu. For example,
|
|
* you can define a `@` trigger to mention users and a `#` trigger to mention
|
|
* tags.
|
|
*
|
|
* @param param0 The configured options for the suggestion
|
|
* @returns
|
|
*/
|
|
function getSuggestionOptions({ editor: tiptapEditor, overrideSuggestionOptions, extensionName, char = '@', }) {
|
|
const pluginKey = new state.PluginKey();
|
|
return {
|
|
editor: tiptapEditor,
|
|
char,
|
|
pluginKey,
|
|
command: ({ editor, range, props }) => {
|
|
var _a, _b, _c;
|
|
// increase range.to by one when the next node is of type "text"
|
|
// and starts with a space character
|
|
const nodeAfter = editor.view.state.selection.$to.nodeAfter;
|
|
const overrideSpace = (_a = nodeAfter === null || nodeAfter === void 0 ? void 0 : nodeAfter.text) === null || _a === void 0 ? void 0 : _a.startsWith(' ');
|
|
if (overrideSpace) {
|
|
range.to += 1;
|
|
}
|
|
editor
|
|
.chain()
|
|
.focus()
|
|
.insertContentAt(range, [
|
|
{
|
|
type: extensionName,
|
|
attrs: { ...props, mentionSuggestionChar: char },
|
|
},
|
|
{
|
|
type: 'text',
|
|
text: ' ',
|
|
},
|
|
])
|
|
.run();
|
|
// get reference to `window` object from editor element, to support cross-frame JS usage
|
|
(_c = (_b = editor.view.dom.ownerDocument.defaultView) === null || _b === void 0 ? void 0 : _b.getSelection()) === null || _c === void 0 ? void 0 : _c.collapseToEnd();
|
|
},
|
|
allow: ({ state, range }) => {
|
|
const $from = state.doc.resolve(range.from);
|
|
const type = state.schema.nodes[extensionName];
|
|
const allow = !!$from.parent.type.contentMatch.matchType(type);
|
|
return allow;
|
|
},
|
|
...overrideSuggestionOptions,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Returns the suggestions for the mention extension.
|
|
*
|
|
* @param options The extension options
|
|
* @returns the suggestions
|
|
*/
|
|
function getSuggestions(options) {
|
|
return (options.options.suggestions.length ? options.options.suggestions : [options.options.suggestion]).map(suggestion => getSuggestionOptions({
|
|
// @ts-ignore `editor` can be `undefined` when converting the document to HTML with the HTML utility
|
|
editor: options.editor,
|
|
overrideSuggestionOptions: suggestion,
|
|
extensionName: options.name,
|
|
char: suggestion.char,
|
|
}));
|
|
}
|
|
/**
|
|
* Returns the suggestion options of the mention that has a given character trigger. If not
|
|
* found, it returns the first suggestion.
|
|
*
|
|
* @param options The extension options
|
|
* @param char The character that triggers the mention
|
|
* @returns The suggestion options
|
|
*/
|
|
function getSuggestionFromChar(options, char) {
|
|
const suggestions = getSuggestions(options);
|
|
const suggestion = suggestions.find(s => s.char === char);
|
|
if (suggestion) {
|
|
return suggestion;
|
|
}
|
|
if (suggestions.length) {
|
|
return suggestions[0];
|
|
}
|
|
return null;
|
|
}
|
|
/**
|
|
* This extension allows you to insert mentions into the editor.
|
|
* @see https://www.tiptap.dev/api/extensions/mention
|
|
*/
|
|
const Mention = core.Node.create({
|
|
name: 'mention',
|
|
priority: 101,
|
|
addOptions() {
|
|
return {
|
|
HTMLAttributes: {},
|
|
renderText({ node, suggestion }) {
|
|
var _a, _b;
|
|
return `${(_a = suggestion === null || suggestion === void 0 ? void 0 : suggestion.char) !== null && _a !== void 0 ? _a : '@'}${(_b = node.attrs.label) !== null && _b !== void 0 ? _b : node.attrs.id}`;
|
|
},
|
|
deleteTriggerWithBackspace: false,
|
|
renderHTML({ options, node, suggestion }) {
|
|
var _a, _b;
|
|
return [
|
|
'span',
|
|
core.mergeAttributes(this.HTMLAttributes, options.HTMLAttributes),
|
|
`${(_a = suggestion === null || suggestion === void 0 ? void 0 : suggestion.char) !== null && _a !== void 0 ? _a : '@'}${(_b = node.attrs.label) !== null && _b !== void 0 ? _b : node.attrs.id}`,
|
|
];
|
|
},
|
|
suggestions: [],
|
|
suggestion: {},
|
|
};
|
|
},
|
|
group: 'inline',
|
|
inline: true,
|
|
selectable: false,
|
|
atom: true,
|
|
addAttributes() {
|
|
return {
|
|
id: {
|
|
default: null,
|
|
parseHTML: element => element.getAttribute('data-id'),
|
|
renderHTML: attributes => {
|
|
if (!attributes.id) {
|
|
return {};
|
|
}
|
|
return {
|
|
'data-id': attributes.id,
|
|
};
|
|
},
|
|
},
|
|
label: {
|
|
default: null,
|
|
parseHTML: element => element.getAttribute('data-label'),
|
|
renderHTML: attributes => {
|
|
if (!attributes.label) {
|
|
return {};
|
|
}
|
|
return {
|
|
'data-label': attributes.label,
|
|
};
|
|
},
|
|
},
|
|
// When there are multiple types of mentions, this attribute helps distinguish them
|
|
mentionSuggestionChar: {
|
|
default: '@',
|
|
parseHTML: element => element.getAttribute('data-mention-suggestion-char'),
|
|
renderHTML: attributes => {
|
|
return {
|
|
'data-mention-suggestion-char': attributes.mentionSuggestionChar,
|
|
};
|
|
},
|
|
},
|
|
};
|
|
},
|
|
parseHTML() {
|
|
return [
|
|
{
|
|
tag: `span[data-type="${this.name}"]`,
|
|
},
|
|
];
|
|
},
|
|
renderHTML({ node, HTMLAttributes }) {
|
|
const suggestion = getSuggestionFromChar(this, node.attrs.mentionSuggestionChar);
|
|
if (this.options.renderLabel !== undefined) {
|
|
console.warn('renderLabel is deprecated use renderText and renderHTML instead');
|
|
return [
|
|
'span',
|
|
core.mergeAttributes({ 'data-type': this.name }, this.options.HTMLAttributes, HTMLAttributes),
|
|
this.options.renderLabel({
|
|
options: this.options,
|
|
node,
|
|
suggestion,
|
|
}),
|
|
];
|
|
}
|
|
const mergedOptions = { ...this.options };
|
|
mergedOptions.HTMLAttributes = core.mergeAttributes({ 'data-type': this.name }, this.options.HTMLAttributes, HTMLAttributes);
|
|
const html = this.options.renderHTML({
|
|
options: mergedOptions,
|
|
node,
|
|
suggestion,
|
|
});
|
|
if (typeof html === 'string') {
|
|
return [
|
|
'span',
|
|
core.mergeAttributes({ 'data-type': this.name }, this.options.HTMLAttributes, HTMLAttributes),
|
|
html,
|
|
];
|
|
}
|
|
return html;
|
|
},
|
|
renderText({ node }) {
|
|
const args = {
|
|
options: this.options,
|
|
node,
|
|
suggestion: getSuggestionFromChar(this, node.attrs.mentionSuggestionChar),
|
|
};
|
|
if (this.options.renderLabel !== undefined) {
|
|
console.warn('renderLabel is deprecated use renderText and renderHTML instead');
|
|
return this.options.renderLabel(args);
|
|
}
|
|
return this.options.renderText(args);
|
|
},
|
|
addKeyboardShortcuts() {
|
|
return {
|
|
Backspace: () => this.editor.commands.command(({ tr, state }) => {
|
|
let isMention = false;
|
|
const { selection } = state;
|
|
const { empty, anchor } = selection;
|
|
if (!empty) {
|
|
return false;
|
|
}
|
|
state.doc.nodesBetween(anchor - 1, anchor, (node, pos) => {
|
|
if (node.type.name === this.name) {
|
|
isMention = true;
|
|
tr.insertText(this.options.deleteTriggerWithBackspace ? '' : this.options.suggestion.char || '', pos, pos + node.nodeSize);
|
|
return false;
|
|
}
|
|
});
|
|
// Store node and position for later use
|
|
let mentionNode = new model.Node();
|
|
let mentionPos = 0;
|
|
state.doc.nodesBetween(anchor - 1, anchor, (node, pos) => {
|
|
if (node.type.name === this.name) {
|
|
isMention = true;
|
|
mentionNode = node;
|
|
mentionPos = pos;
|
|
return false;
|
|
}
|
|
});
|
|
if (isMention) {
|
|
tr.insertText(this.options.deleteTriggerWithBackspace ? '' : mentionNode.attrs.mentionSuggestionChar, mentionPos, mentionPos + mentionNode.nodeSize);
|
|
}
|
|
return isMention;
|
|
}),
|
|
};
|
|
},
|
|
addProseMirrorPlugins() {
|
|
// Create a plugin for each suggestion configuration
|
|
return getSuggestions(this).map(Suggestion__default.default);
|
|
},
|
|
});
|
|
|
|
exports.Mention = Mention;
|
|
exports.default = Mention;
|
|
//# sourceMappingURL=index.cjs.map
|