@remirror/extension-mention
Advanced tools
Comparing version
# @remirror/extension-mention | ||
## 0.7.6 | ||
### Patch Changes | ||
- Updated dependencies [0300d01c] | ||
- @remirror/core@0.9.0 | ||
- prosemirror-suggest@0.7.6 | ||
## 0.7.5 | ||
@@ -4,0 +12,0 @@ |
@@ -8,2 +8,8 @@ 'use strict'; | ||
var _objectWithoutProperties = _interopDefault(require('@babel/runtime/helpers/objectWithoutProperties')); | ||
var _classCallCheck = _interopDefault(require('@babel/runtime/helpers/classCallCheck')); | ||
var _createClass = _interopDefault(require('@babel/runtime/helpers/createClass')); | ||
var _possibleConstructorReturn = _interopDefault(require('@babel/runtime/helpers/possibleConstructorReturn')); | ||
var _getPrototypeOf = _interopDefault(require('@babel/runtime/helpers/getPrototypeOf')); | ||
var _assertThisInitialized = _interopDefault(require('@babel/runtime/helpers/assertThisInitialized')); | ||
var _inherits = _interopDefault(require('@babel/runtime/helpers/inherits')); | ||
var _defineProperty = _interopDefault(require('@babel/runtime/helpers/defineProperty')); | ||
@@ -20,3 +26,3 @@ var core = require('@remirror/core'); | ||
*/ | ||
const DEFAULT_MATCHER = _objectSpread({}, core.pick(prosemirrorSuggest.DEFAULT_SUGGESTER, ['startOfLine', 'supportedCharacters', 'validPrefixCharacters', 'invalidPrefixCharacters', 'appendText', 'suggestClassName']), { | ||
var DEFAULT_MATCHER = _objectSpread({}, core.pick(prosemirrorSuggest.DEFAULT_SUGGESTER, ['startOfLine', 'supportedCharacters', 'validPrefixCharacters', 'invalidPrefixCharacters', 'appendText', 'suggestClassName']), { | ||
appendText: ' ', | ||
@@ -31,3 +37,5 @@ matchOffset: 1, | ||
const isValidMentionAttrs = attrs => core.bool(attrs && core.isPlainObject(attrs) && attrs.id && attrs.label); | ||
var isValidMentionAttrs = function isValidMentionAttrs(attrs) { | ||
return core.bool(attrs && core.isPlainObject(attrs) && attrs.id && attrs.label); | ||
}; | ||
/** | ||
@@ -40,4 +48,6 @@ * Gets the matcher from the list of matchers if it exists. | ||
const getMatcher = (name, matchers) => { | ||
const matcher = matchers.find(matcher => matcher.name === name); | ||
var getMatcher = function getMatcher(name, matchers) { | ||
var matcher = matchers.find(function (matcher) { | ||
return matcher.name === name; | ||
}); | ||
return matcher ? _objectSpread({}, DEFAULT_MATCHER, {}, matcher) : undefined; | ||
@@ -50,3 +60,3 @@ }; | ||
const getAppendText = (preferred, fallback) => { | ||
var getAppendText = function getAppendText(preferred, fallback) { | ||
if (core.isString(preferred)) { | ||
@@ -67,3 +77,5 @@ return preferred; | ||
const defaultHandler = () => false; | ||
var defaultHandler = function defaultHandler() { | ||
return false; | ||
}; | ||
/** | ||
@@ -76,311 +88,334 @@ * The mention extension manages suggestions through onChange, onKeyDown, onExit and onEnter callbacks. | ||
class MentionExtension extends core.MarkExtension { | ||
constructor(...args) { | ||
super(...args); | ||
var MentionExtension = | ||
/*#__PURE__*/ | ||
function (_MarkExtension) { | ||
_inherits(MentionExtension, _MarkExtension); | ||
_defineProperty(this, "createMention", (type, getState, shouldUpdate = false) => config => { | ||
if (!isValidMentionAttrs(config)) { | ||
throw new Error('Invalid configuration attributes passed to the MentionExtension command.'); | ||
} | ||
function MentionExtension() { | ||
var _getPrototypeOf2; | ||
const { | ||
range, | ||
appendText, | ||
replacementType | ||
} = config, | ||
var _this; | ||
_classCallCheck(this, MentionExtension); | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(MentionExtension)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
_defineProperty(_assertThisInitialized(_this), "createMention", function (type, getState) { | ||
var shouldUpdate = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; | ||
return function (config) { | ||
if (!isValidMentionAttrs(config)) { | ||
throw new Error('Invalid configuration attributes passed to the MentionExtension command.'); | ||
} | ||
var range = config.range, | ||
appendText = config.appendText, | ||
replacementType = config.replacementType, | ||
attrs = _objectWithoutProperties(config, ["range", "appendText", "replacementType"]); | ||
let name = attrs.name; | ||
var name = attrs.name; | ||
if (!name) { | ||
if (this.options.matchers.length >= 2) { | ||
throw new Error('The MentionExtension command must specify a name since there are multiple matchers configured'); | ||
if (!name) { | ||
if (_this.options.matchers.length >= 2) { | ||
throw new Error('The MentionExtension command must specify a name since there are multiple matchers configured'); | ||
} | ||
name = _this.options.matchers[0].name; | ||
} | ||
name = this.options.matchers[0].name; | ||
} | ||
var allowedNames = _this.options.matchers.map(function (_ref) { | ||
var name = _ref.name; | ||
return name; | ||
}); | ||
const allowedNames = this.options.matchers.map(({ | ||
name | ||
}) => name); | ||
if (!allowedNames.includes(name)) { | ||
throw new Error("The name '".concat(name, "' specified for this command is invalid. Please choose from: ").concat(JSON.stringify(allowedNames), ".")); | ||
} | ||
if (!allowedNames.includes(name)) { | ||
throw new Error("The name '".concat(name, "' specified for this command is invalid. Please choose from: ").concat(JSON.stringify(allowedNames), ".")); | ||
} | ||
var matcher = getMatcher(name, _this.options.matchers); | ||
const matcher = getMatcher(name, this.options.matchers); | ||
if (!matcher) { | ||
throw new Error("Mentions matcher not found for name ".concat(name, ".")); | ||
} | ||
if (!matcher) { | ||
throw new Error("Mentions matcher not found for name ".concat(name, ".")); | ||
} | ||
var _ref2 = range !== null && range !== void 0 ? range : getState().selection, | ||
from = _ref2.from, | ||
to = _ref2.to; | ||
const { | ||
from, | ||
to | ||
} = range !== null && range !== void 0 ? range : getState().selection; | ||
let startTransaction; | ||
var startTransaction; | ||
if (shouldUpdate) { | ||
// Remove all currently active marks before proceeding. | ||
startTransaction = (tr, state) => { | ||
// Remove mark at previous position | ||
let { | ||
oldFrom, | ||
oldTo | ||
} = { | ||
oldFrom: from, | ||
oldTo: range ? range.end : to | ||
}; | ||
const $oldTo = state.doc.resolve(oldTo); | ||
({ | ||
from: oldFrom, | ||
to: oldTo | ||
} = core.getMarkRange($oldTo, type) || { | ||
from: oldFrom, | ||
to: oldTo | ||
}); | ||
tr.removeMark(oldFrom, oldTo, type); | ||
tr.setMeta('addToHistory', false); // Remove mark at current position | ||
if (shouldUpdate) { | ||
// Remove all currently active marks before proceeding. | ||
startTransaction = function startTransaction(tr, state) { | ||
// Remove mark at previous position | ||
var _oldFrom$oldTo = { | ||
oldFrom: from, | ||
oldTo: range ? range.end : to | ||
}, | ||
oldFrom = _oldFrom$oldTo.oldFrom, | ||
oldTo = _oldFrom$oldTo.oldTo; | ||
var $oldTo = state.doc.resolve(oldTo); | ||
const $newTo = tr.selection.$from; | ||
const { | ||
from: newFrom, | ||
to: newTo | ||
} = core.getMarkRange($newTo, type) || { | ||
from: $newTo.pos, | ||
to: $newTo.pos | ||
var _ref3 = core.getMarkRange($oldTo, type) || { | ||
from: oldFrom, | ||
to: oldTo | ||
}; | ||
oldFrom = _ref3.from; | ||
oldTo = _ref3.to; | ||
tr.removeMark(oldFrom, oldTo, type); | ||
tr.setMeta('addToHistory', false); // Remove mark at current position | ||
var $newTo = tr.selection.$from; | ||
var _ref4 = core.getMarkRange($newTo, type) || { | ||
from: $newTo.pos, | ||
to: $newTo.pos | ||
}, | ||
newFrom = _ref4.from, | ||
newTo = _ref4.to; | ||
tr.removeMark(newFrom, newTo, type); | ||
return tr.setMeta('addToHistory', false); | ||
}; | ||
tr.removeMark(newFrom, newTo, type); | ||
return tr.setMeta('addToHistory', false); | ||
}; | ||
} | ||
} | ||
return core.replaceText({ | ||
type, | ||
attrs: _objectSpread$1({}, attrs, { | ||
name | ||
}), | ||
appendText: getAppendText(appendText, matcher.appendText), | ||
range: range ? { | ||
from, | ||
to: replacementType === 'full' ? range.end || to : to | ||
} : undefined, | ||
content: attrs.label, | ||
startTransaction | ||
}); | ||
return core.replaceText({ | ||
type: type, | ||
attrs: _objectSpread$1({}, attrs, { | ||
name: name | ||
}), | ||
appendText: getAppendText(appendText, matcher.appendText), | ||
range: range ? { | ||
from: from, | ||
to: replacementType === 'full' ? range.end || to : to | ||
} : undefined, | ||
content: attrs.label, | ||
startTransaction: startTransaction | ||
}); | ||
}; | ||
}); | ||
} | ||
get name() { | ||
return 'mention'; | ||
return _this; | ||
} | ||
/** | ||
* Provide the default options for this extension | ||
*/ | ||
_createClass(MentionExtension, [{ | ||
key: "commands", | ||
value: function commands(_ref5) { | ||
var type = _ref5.type, | ||
getState = _ref5.getState; | ||
return { | ||
createMention: this.createMention(type, getState), | ||
updateMention: this.createMention(type, getState, true), | ||
removeMention: function removeMention() { | ||
var _ref6 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Object.create(null), | ||
range = _ref6.range; | ||
get defaultOptions() { | ||
return { | ||
matchers: [], | ||
appendText: ' ', | ||
mentionClassName: 'mention', | ||
extraAttrs: [], | ||
mentionTag: 'a', | ||
suggestTag: 'a', | ||
onChange: defaultHandler, | ||
onExit: defaultHandler, | ||
onCharacterEntry: defaultHandler, | ||
keyBindings: {} | ||
}; | ||
} | ||
return core.removeMark({ | ||
type: type, | ||
expand: true, | ||
range: range | ||
}); | ||
} | ||
}; | ||
} | ||
}, { | ||
key: "pasteRules", | ||
value: function pasteRules(_ref7) { | ||
var type = _ref7.type; | ||
return this.options.matchers.map(function (matcher) { | ||
var _DEFAULT_MATCHER$matc = _objectSpread$1({}, DEFAULT_MATCHER, {}, matcher), | ||
startOfLine = _DEFAULT_MATCHER$matc.startOfLine, | ||
_char = _DEFAULT_MATCHER$matc["char"], | ||
supportedCharacters = _DEFAULT_MATCHER$matc.supportedCharacters, | ||
name = _DEFAULT_MATCHER$matc.name; | ||
get schema() { | ||
const dataAttributeId = 'data-mention-id'; | ||
const dataAttributeName = 'data-mention-name'; | ||
return { | ||
attrs: _objectSpread$1({ | ||
id: {}, | ||
label: {}, | ||
name: {} | ||
}, this.extraAttrs()), | ||
group: core.MarkGroup.Behavior, | ||
excludes: '_', | ||
inclusive: false, | ||
parseDOM: [{ | ||
tag: "".concat(this.options.mentionTag, "[").concat(dataAttributeId, "]"), | ||
getAttrs: node => { | ||
if (!core.isElementDOMNode(node)) { | ||
return false; | ||
var regexp = new RegExp("(".concat(prosemirrorSuggest.getRegexPrefix(startOfLine)).concat(prosemirrorSuggest.escapeChar(_char)).concat(prosemirrorSuggest.regexToString(supportedCharacters), ")"), 'g'); | ||
return core.markPasteRule({ | ||
regexp: regexp, | ||
type: type, | ||
getAttrs: function getAttrs(str) { | ||
return { | ||
id: core.getMatchString(str.slice(_char.length, str.length)), | ||
label: core.getMatchString(str), | ||
name: name | ||
}; | ||
} | ||
}); | ||
}); | ||
} | ||
}, { | ||
key: "suggestions", | ||
value: function suggestions(_ref8) { | ||
var getActions = _ref8.getActions, | ||
type = _ref8.type, | ||
getState = _ref8.getState; | ||
var _this$options = this.options, | ||
matchers = _this$options.matchers, | ||
onChange = _this$options.onChange, | ||
onExit = _this$options.onExit, | ||
noDecorations = _this$options.noDecorations, | ||
keyBindings = _this$options.keyBindings, | ||
onCharacterEntry = _this$options.onCharacterEntry, | ||
suggestTag = _this$options.suggestTag; | ||
return matchers.map(function (matcher) { | ||
return _objectSpread$1({}, DEFAULT_MATCHER, {}, matcher, { | ||
noDecorations: noDecorations, | ||
suggestTag: suggestTag, | ||
onChange: onChange, | ||
onExit: onExit, | ||
keyBindings: keyBindings, | ||
onCharacterEntry: onCharacterEntry, | ||
createCommand: function createCommand(_ref9) { | ||
var match = _ref9.match, | ||
reason = _ref9.reason, | ||
setMarkRemoved = _ref9.setMarkRemoved; | ||
var name = match.suggester.name, | ||
range = match.range; | ||
var create = getActions('createMention'); | ||
var update = getActions('updateMention'); | ||
var remove = getActions('removeMention'); | ||
var isActive = core.isMarkActive({ | ||
from: match.range.from, | ||
to: match.range.end, | ||
type: type, | ||
state: getState() | ||
}); | ||
var fn = isActive ? update : create; | ||
var isSplit = prosemirrorSuggest.isSplitReason(reason); | ||
var isInvalid = prosemirrorSuggest.isInvalidSplitReason(reason); | ||
var isRemoved = prosemirrorSuggest.isRemovedReason(reason); | ||
const id = node.getAttribute(dataAttributeId); | ||
const name = node.getAttribute(dataAttributeName); | ||
const label = node.innerText; | ||
return { | ||
id, | ||
label, | ||
name | ||
}; | ||
} | ||
}], | ||
toDOM: node => { | ||
var _matcher$mentionClass; | ||
var removeCommand = function removeCommand() { | ||
setMarkRemoved(); | ||
const _ref = node.attrs, | ||
{ | ||
label: _, | ||
id, | ||
name, | ||
replacementType, | ||
range | ||
} = _ref, | ||
attrs = _objectWithoutProperties(_ref, ["label", "id", "name", "replacementType", "range"]); | ||
try { | ||
// This might fail when a deletion has taken place. | ||
isInvalid ? remove({ | ||
range: match.range | ||
}) : core.noop(); | ||
} catch (_unused) {// This sometimes fails and it's best to ignore until more is | ||
// known about the impact. | ||
} | ||
}; | ||
const matcher = this.options.matchers.find(matcher => matcher.name === name); | ||
const mentionClassName = matcher ? (_matcher$mentionClass = matcher.mentionClassName) !== null && _matcher$mentionClass !== void 0 ? _matcher$mentionClass : DEFAULT_MATCHER.mentionClassName : DEFAULT_MATCHER.mentionClassName; | ||
return [this.options.mentionTag, _objectSpread$1({}, attrs, { | ||
class: name ? "".concat(mentionClassName, " ").concat(mentionClassName, "-").concat(name) : mentionClassName, | ||
[dataAttributeId]: id, | ||
[dataAttributeName]: name | ||
}), 0]; | ||
} | ||
}; | ||
} | ||
/** | ||
* A function for creating the mention for the first time. | ||
*/ | ||
var createCommand = function createCommand(_ref10) { | ||
var _ref10$replacementTyp = _ref10.replacementType, | ||
replacementType = _ref10$replacementTyp === void 0 ? isSplit ? 'partial' : 'full' : _ref10$replacementTyp, | ||
_ref10$id = _ref10.id, | ||
id = _ref10$id === void 0 ? match.queryText[replacementType] : _ref10$id, | ||
_ref10$label = _ref10.label, | ||
label = _ref10$label === void 0 ? match.matchText[replacementType] : _ref10$label, | ||
appendText = _ref10.appendText, | ||
attrs = _objectWithoutProperties(_ref10, ["replacementType", "id", "label", "appendText"]); | ||
fn(_objectSpread$1({ | ||
id: id, | ||
label: label, | ||
appendText: appendText, | ||
replacementType: replacementType, | ||
name: name, | ||
range: range | ||
}, attrs)); | ||
}; | ||
commands({ | ||
type, | ||
getState | ||
}) { | ||
return { | ||
createMention: this.createMention(type, getState), | ||
updateMention: this.createMention(type, getState, true), | ||
removeMention: ({ | ||
range | ||
} = Object.create(null)) => { | ||
return core.removeMark({ | ||
type, | ||
expand: true, | ||
range | ||
var command = isInvalid || isRemoved ? removeCommand : createCommand; | ||
return command; | ||
} | ||
}); | ||
} | ||
}; | ||
} | ||
pasteRules({ | ||
type | ||
}) { | ||
return this.options.matchers.map(matcher => { | ||
const { | ||
startOfLine, | ||
char, | ||
supportedCharacters, | ||
name | ||
} = _objectSpread$1({}, DEFAULT_MATCHER, {}, matcher); | ||
const regexp = new RegExp("(".concat(prosemirrorSuggest.getRegexPrefix(startOfLine)).concat(prosemirrorSuggest.escapeChar(char)).concat(prosemirrorSuggest.regexToString(supportedCharacters), ")"), 'g'); | ||
return core.markPasteRule({ | ||
regexp, | ||
type, | ||
getAttrs: str => ({ | ||
id: core.getMatchString(str.slice(char.length, str.length)), | ||
label: core.getMatchString(str), | ||
name | ||
}) | ||
}); | ||
}); | ||
} | ||
} | ||
}, { | ||
key: "name", | ||
get: function get() { | ||
return 'mention'; | ||
} | ||
/** | ||
* Provide the default options for this extension | ||
*/ | ||
suggestions({ | ||
getActions, | ||
type, | ||
getState | ||
}) { | ||
const { | ||
matchers, | ||
onChange, | ||
onExit, | ||
noDecorations, | ||
keyBindings, | ||
onCharacterEntry, | ||
suggestTag | ||
} = this.options; | ||
return matchers.map(matcher => { | ||
return _objectSpread$1({}, DEFAULT_MATCHER, {}, matcher, { | ||
noDecorations, | ||
suggestTag, | ||
onChange, | ||
onExit, | ||
keyBindings, | ||
onCharacterEntry, | ||
createCommand: ({ | ||
match, | ||
reason, | ||
setMarkRemoved | ||
}) => { | ||
const { | ||
suggester: { | ||
name | ||
}, | ||
range | ||
} = match; | ||
const create = getActions('createMention'); | ||
const update = getActions('updateMention'); | ||
const remove = getActions('removeMention'); | ||
const isActive = core.isMarkActive({ | ||
from: match.range.from, | ||
to: match.range.end, | ||
type: type, | ||
state: getState() | ||
}); | ||
const fn = isActive ? update : create; | ||
const isSplit = prosemirrorSuggest.isSplitReason(reason); | ||
const isInvalid = prosemirrorSuggest.isInvalidSplitReason(reason); | ||
const isRemoved = prosemirrorSuggest.isRemovedReason(reason); | ||
}, { | ||
key: "defaultOptions", | ||
get: function get() { | ||
return { | ||
matchers: [], | ||
appendText: ' ', | ||
mentionClassName: 'mention', | ||
extraAttrs: [], | ||
mentionTag: 'a', | ||
suggestTag: 'a', | ||
onChange: defaultHandler, | ||
onExit: defaultHandler, | ||
onCharacterEntry: defaultHandler, | ||
keyBindings: {} | ||
}; | ||
} | ||
}, { | ||
key: "schema", | ||
get: function get() { | ||
var _this2 = this; | ||
const removeCommand = () => { | ||
setMarkRemoved(); | ||
try { | ||
// This might fail when a deletion has taken place. | ||
isInvalid ? remove({ | ||
range: match.range | ||
}) : core.noop(); | ||
} catch (_unused) {// This sometimes fails and it's best to ignore until more is | ||
// known about the impact. | ||
var dataAttributeId = 'data-mention-id'; | ||
var dataAttributeName = 'data-mention-name'; | ||
return { | ||
attrs: _objectSpread$1({ | ||
id: {}, | ||
label: {}, | ||
name: {} | ||
}, this.extraAttrs()), | ||
group: core.MarkGroup.Behavior, | ||
excludes: '_', | ||
inclusive: false, | ||
parseDOM: [{ | ||
tag: "".concat(this.options.mentionTag, "[").concat(dataAttributeId, "]"), | ||
getAttrs: function getAttrs(node) { | ||
if (!core.isElementDOMNode(node)) { | ||
return false; | ||
} | ||
}; | ||
const createCommand = (_ref2) => { | ||
let { | ||
replacementType = isSplit ? 'partial' : 'full', | ||
id = match.queryText[replacementType], | ||
label = match.matchText[replacementType], | ||
appendText | ||
} = _ref2, | ||
attrs = _objectWithoutProperties(_ref2, ["replacementType", "id", "label", "appendText"]); | ||
var id = node.getAttribute(dataAttributeId); | ||
var name = node.getAttribute(dataAttributeName); | ||
var label = node.innerText; | ||
return { | ||
id: id, | ||
label: label, | ||
name: name | ||
}; | ||
} | ||
}], | ||
toDOM: function toDOM(node) { | ||
var _matcher$mentionClass, _objectSpread2; | ||
fn(_objectSpread$1({ | ||
id, | ||
label, | ||
appendText, | ||
replacementType, | ||
name, | ||
range | ||
}, attrs)); | ||
}; | ||
var _ref11 = node.attrs, | ||
_ = _ref11.label, | ||
id = _ref11.id, | ||
name = _ref11.name, | ||
replacementType = _ref11.replacementType, | ||
range = _ref11.range, | ||
attrs = _objectWithoutProperties(_ref11, ["label", "id", "name", "replacementType", "range"]); | ||
const command = isInvalid || isRemoved ? removeCommand : createCommand; | ||
return command; | ||
var matcher = _this2.options.matchers.find(function (matcher) { | ||
return matcher.name === name; | ||
}); | ||
var mentionClassName = matcher ? (_matcher$mentionClass = matcher.mentionClassName) !== null && _matcher$mentionClass !== void 0 ? _matcher$mentionClass : DEFAULT_MATCHER.mentionClassName : DEFAULT_MATCHER.mentionClassName; | ||
return [_this2.options.mentionTag, _objectSpread$1({}, attrs, (_objectSpread2 = { | ||
"class": name ? "".concat(mentionClassName, " ").concat(mentionClassName, "-").concat(name) : mentionClassName | ||
}, _defineProperty(_objectSpread2, dataAttributeId, id), _defineProperty(_objectSpread2, dataAttributeName, name), _objectSpread2)), 0]; | ||
} | ||
}); | ||
}); | ||
} | ||
}; | ||
} | ||
/** | ||
* A function for creating the mention for the first time. | ||
*/ | ||
} | ||
}]); | ||
return MentionExtension; | ||
}(core.MarkExtension); | ||
exports.MentionExtension = MentionExtension; | ||
//# sourceMappingURL=extension-mention.cjs.js.map |
import _objectWithoutProperties from '@babel/runtime/helpers/objectWithoutProperties'; | ||
import _classCallCheck from '@babel/runtime/helpers/classCallCheck'; | ||
import _createClass from '@babel/runtime/helpers/createClass'; | ||
import _possibleConstructorReturn from '@babel/runtime/helpers/possibleConstructorReturn'; | ||
import _getPrototypeOf from '@babel/runtime/helpers/getPrototypeOf'; | ||
import _assertThisInitialized from '@babel/runtime/helpers/assertThisInitialized'; | ||
import _inherits from '@babel/runtime/helpers/inherits'; | ||
import _defineProperty from '@babel/runtime/helpers/defineProperty'; | ||
import { bool, isPlainObject, pick, isString, MarkExtension, replaceText, MarkGroup, isElementDOMNode, removeMark, markPasteRule, getMatchString, getMarkRange, isMarkActive, noop } from '@remirror/core'; | ||
import { bool, isPlainObject, pick, isString, replaceText, removeMark, markPasteRule, getMatchString, MarkGroup, isElementDOMNode, MarkExtension, getMarkRange, isMarkActive, noop } from '@remirror/core'; | ||
import { DEFAULT_SUGGESTER, getRegexPrefix, escapeChar, regexToString, isSplitReason, isInvalidSplitReason, isRemovedReason } from 'prosemirror-suggest'; | ||
@@ -13,3 +19,3 @@ | ||
*/ | ||
const DEFAULT_MATCHER = _objectSpread({}, pick(DEFAULT_SUGGESTER, ['startOfLine', 'supportedCharacters', 'validPrefixCharacters', 'invalidPrefixCharacters', 'appendText', 'suggestClassName']), { | ||
var DEFAULT_MATCHER = _objectSpread({}, pick(DEFAULT_SUGGESTER, ['startOfLine', 'supportedCharacters', 'validPrefixCharacters', 'invalidPrefixCharacters', 'appendText', 'suggestClassName']), { | ||
appendText: ' ', | ||
@@ -24,3 +30,5 @@ matchOffset: 1, | ||
const isValidMentionAttrs = attrs => bool(attrs && isPlainObject(attrs) && attrs.id && attrs.label); | ||
var isValidMentionAttrs = function isValidMentionAttrs(attrs) { | ||
return bool(attrs && isPlainObject(attrs) && attrs.id && attrs.label); | ||
}; | ||
/** | ||
@@ -33,4 +41,6 @@ * Gets the matcher from the list of matchers if it exists. | ||
const getMatcher = (name, matchers) => { | ||
const matcher = matchers.find(matcher => matcher.name === name); | ||
var getMatcher = function getMatcher(name, matchers) { | ||
var matcher = matchers.find(function (matcher) { | ||
return matcher.name === name; | ||
}); | ||
return matcher ? _objectSpread({}, DEFAULT_MATCHER, {}, matcher) : undefined; | ||
@@ -43,3 +53,3 @@ }; | ||
const getAppendText = (preferred, fallback) => { | ||
var getAppendText = function getAppendText(preferred, fallback) { | ||
if (isString(preferred)) { | ||
@@ -60,3 +70,5 @@ return preferred; | ||
const defaultHandler = () => false; | ||
var defaultHandler = function defaultHandler() { | ||
return false; | ||
}; | ||
/** | ||
@@ -69,311 +81,334 @@ * The mention extension manages suggestions through onChange, onKeyDown, onExit and onEnter callbacks. | ||
class MentionExtension extends MarkExtension { | ||
constructor(...args) { | ||
super(...args); | ||
var MentionExtension = | ||
/*#__PURE__*/ | ||
function (_MarkExtension) { | ||
_inherits(MentionExtension, _MarkExtension); | ||
_defineProperty(this, "createMention", (type, getState, shouldUpdate = false) => config => { | ||
if (!isValidMentionAttrs(config)) { | ||
throw new Error('Invalid configuration attributes passed to the MentionExtension command.'); | ||
} | ||
function MentionExtension() { | ||
var _getPrototypeOf2; | ||
const { | ||
range, | ||
appendText, | ||
replacementType | ||
} = config, | ||
var _this; | ||
_classCallCheck(this, MentionExtension); | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(MentionExtension)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
_defineProperty(_assertThisInitialized(_this), "createMention", function (type, getState) { | ||
var shouldUpdate = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; | ||
return function (config) { | ||
if (!isValidMentionAttrs(config)) { | ||
throw new Error('Invalid configuration attributes passed to the MentionExtension command.'); | ||
} | ||
var range = config.range, | ||
appendText = config.appendText, | ||
replacementType = config.replacementType, | ||
attrs = _objectWithoutProperties(config, ["range", "appendText", "replacementType"]); | ||
let name = attrs.name; | ||
var name = attrs.name; | ||
if (!name) { | ||
if (this.options.matchers.length >= 2) { | ||
throw new Error('The MentionExtension command must specify a name since there are multiple matchers configured'); | ||
if (!name) { | ||
if (_this.options.matchers.length >= 2) { | ||
throw new Error('The MentionExtension command must specify a name since there are multiple matchers configured'); | ||
} | ||
name = _this.options.matchers[0].name; | ||
} | ||
name = this.options.matchers[0].name; | ||
} | ||
var allowedNames = _this.options.matchers.map(function (_ref) { | ||
var name = _ref.name; | ||
return name; | ||
}); | ||
const allowedNames = this.options.matchers.map(({ | ||
name | ||
}) => name); | ||
if (!allowedNames.includes(name)) { | ||
throw new Error("The name '".concat(name, "' specified for this command is invalid. Please choose from: ").concat(JSON.stringify(allowedNames), ".")); | ||
} | ||
if (!allowedNames.includes(name)) { | ||
throw new Error("The name '".concat(name, "' specified for this command is invalid. Please choose from: ").concat(JSON.stringify(allowedNames), ".")); | ||
} | ||
var matcher = getMatcher(name, _this.options.matchers); | ||
const matcher = getMatcher(name, this.options.matchers); | ||
if (!matcher) { | ||
throw new Error("Mentions matcher not found for name ".concat(name, ".")); | ||
} | ||
if (!matcher) { | ||
throw new Error("Mentions matcher not found for name ".concat(name, ".")); | ||
} | ||
var _ref2 = range !== null && range !== void 0 ? range : getState().selection, | ||
from = _ref2.from, | ||
to = _ref2.to; | ||
const { | ||
from, | ||
to | ||
} = range !== null && range !== void 0 ? range : getState().selection; | ||
let startTransaction; | ||
var startTransaction; | ||
if (shouldUpdate) { | ||
// Remove all currently active marks before proceeding. | ||
startTransaction = (tr, state) => { | ||
// Remove mark at previous position | ||
let { | ||
oldFrom, | ||
oldTo | ||
} = { | ||
oldFrom: from, | ||
oldTo: range ? range.end : to | ||
}; | ||
const $oldTo = state.doc.resolve(oldTo); | ||
({ | ||
from: oldFrom, | ||
to: oldTo | ||
} = getMarkRange($oldTo, type) || { | ||
from: oldFrom, | ||
to: oldTo | ||
}); | ||
tr.removeMark(oldFrom, oldTo, type); | ||
tr.setMeta('addToHistory', false); // Remove mark at current position | ||
if (shouldUpdate) { | ||
// Remove all currently active marks before proceeding. | ||
startTransaction = function startTransaction(tr, state) { | ||
// Remove mark at previous position | ||
var _oldFrom$oldTo = { | ||
oldFrom: from, | ||
oldTo: range ? range.end : to | ||
}, | ||
oldFrom = _oldFrom$oldTo.oldFrom, | ||
oldTo = _oldFrom$oldTo.oldTo; | ||
var $oldTo = state.doc.resolve(oldTo); | ||
const $newTo = tr.selection.$from; | ||
const { | ||
from: newFrom, | ||
to: newTo | ||
} = getMarkRange($newTo, type) || { | ||
from: $newTo.pos, | ||
to: $newTo.pos | ||
var _ref3 = getMarkRange($oldTo, type) || { | ||
from: oldFrom, | ||
to: oldTo | ||
}; | ||
oldFrom = _ref3.from; | ||
oldTo = _ref3.to; | ||
tr.removeMark(oldFrom, oldTo, type); | ||
tr.setMeta('addToHistory', false); // Remove mark at current position | ||
var $newTo = tr.selection.$from; | ||
var _ref4 = getMarkRange($newTo, type) || { | ||
from: $newTo.pos, | ||
to: $newTo.pos | ||
}, | ||
newFrom = _ref4.from, | ||
newTo = _ref4.to; | ||
tr.removeMark(newFrom, newTo, type); | ||
return tr.setMeta('addToHistory', false); | ||
}; | ||
tr.removeMark(newFrom, newTo, type); | ||
return tr.setMeta('addToHistory', false); | ||
}; | ||
} | ||
} | ||
return replaceText({ | ||
type, | ||
attrs: _objectSpread$1({}, attrs, { | ||
name | ||
}), | ||
appendText: getAppendText(appendText, matcher.appendText), | ||
range: range ? { | ||
from, | ||
to: replacementType === 'full' ? range.end || to : to | ||
} : undefined, | ||
content: attrs.label, | ||
startTransaction | ||
}); | ||
return replaceText({ | ||
type: type, | ||
attrs: _objectSpread$1({}, attrs, { | ||
name: name | ||
}), | ||
appendText: getAppendText(appendText, matcher.appendText), | ||
range: range ? { | ||
from: from, | ||
to: replacementType === 'full' ? range.end || to : to | ||
} : undefined, | ||
content: attrs.label, | ||
startTransaction: startTransaction | ||
}); | ||
}; | ||
}); | ||
} | ||
get name() { | ||
return 'mention'; | ||
return _this; | ||
} | ||
/** | ||
* Provide the default options for this extension | ||
*/ | ||
_createClass(MentionExtension, [{ | ||
key: "commands", | ||
value: function commands(_ref5) { | ||
var type = _ref5.type, | ||
getState = _ref5.getState; | ||
return { | ||
createMention: this.createMention(type, getState), | ||
updateMention: this.createMention(type, getState, true), | ||
removeMention: function removeMention() { | ||
var _ref6 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Object.create(null), | ||
range = _ref6.range; | ||
get defaultOptions() { | ||
return { | ||
matchers: [], | ||
appendText: ' ', | ||
mentionClassName: 'mention', | ||
extraAttrs: [], | ||
mentionTag: 'a', | ||
suggestTag: 'a', | ||
onChange: defaultHandler, | ||
onExit: defaultHandler, | ||
onCharacterEntry: defaultHandler, | ||
keyBindings: {} | ||
}; | ||
} | ||
return removeMark({ | ||
type: type, | ||
expand: true, | ||
range: range | ||
}); | ||
} | ||
}; | ||
} | ||
}, { | ||
key: "pasteRules", | ||
value: function pasteRules(_ref7) { | ||
var type = _ref7.type; | ||
return this.options.matchers.map(function (matcher) { | ||
var _DEFAULT_MATCHER$matc = _objectSpread$1({}, DEFAULT_MATCHER, {}, matcher), | ||
startOfLine = _DEFAULT_MATCHER$matc.startOfLine, | ||
_char = _DEFAULT_MATCHER$matc["char"], | ||
supportedCharacters = _DEFAULT_MATCHER$matc.supportedCharacters, | ||
name = _DEFAULT_MATCHER$matc.name; | ||
get schema() { | ||
const dataAttributeId = 'data-mention-id'; | ||
const dataAttributeName = 'data-mention-name'; | ||
return { | ||
attrs: _objectSpread$1({ | ||
id: {}, | ||
label: {}, | ||
name: {} | ||
}, this.extraAttrs()), | ||
group: MarkGroup.Behavior, | ||
excludes: '_', | ||
inclusive: false, | ||
parseDOM: [{ | ||
tag: "".concat(this.options.mentionTag, "[").concat(dataAttributeId, "]"), | ||
getAttrs: node => { | ||
if (!isElementDOMNode(node)) { | ||
return false; | ||
var regexp = new RegExp("(".concat(getRegexPrefix(startOfLine)).concat(escapeChar(_char)).concat(regexToString(supportedCharacters), ")"), 'g'); | ||
return markPasteRule({ | ||
regexp: regexp, | ||
type: type, | ||
getAttrs: function getAttrs(str) { | ||
return { | ||
id: getMatchString(str.slice(_char.length, str.length)), | ||
label: getMatchString(str), | ||
name: name | ||
}; | ||
} | ||
}); | ||
}); | ||
} | ||
}, { | ||
key: "suggestions", | ||
value: function suggestions(_ref8) { | ||
var getActions = _ref8.getActions, | ||
type = _ref8.type, | ||
getState = _ref8.getState; | ||
var _this$options = this.options, | ||
matchers = _this$options.matchers, | ||
onChange = _this$options.onChange, | ||
onExit = _this$options.onExit, | ||
noDecorations = _this$options.noDecorations, | ||
keyBindings = _this$options.keyBindings, | ||
onCharacterEntry = _this$options.onCharacterEntry, | ||
suggestTag = _this$options.suggestTag; | ||
return matchers.map(function (matcher) { | ||
return _objectSpread$1({}, DEFAULT_MATCHER, {}, matcher, { | ||
noDecorations: noDecorations, | ||
suggestTag: suggestTag, | ||
onChange: onChange, | ||
onExit: onExit, | ||
keyBindings: keyBindings, | ||
onCharacterEntry: onCharacterEntry, | ||
createCommand: function createCommand(_ref9) { | ||
var match = _ref9.match, | ||
reason = _ref9.reason, | ||
setMarkRemoved = _ref9.setMarkRemoved; | ||
var name = match.suggester.name, | ||
range = match.range; | ||
var create = getActions('createMention'); | ||
var update = getActions('updateMention'); | ||
var remove = getActions('removeMention'); | ||
var isActive = isMarkActive({ | ||
from: match.range.from, | ||
to: match.range.end, | ||
type: type, | ||
state: getState() | ||
}); | ||
var fn = isActive ? update : create; | ||
var isSplit = isSplitReason(reason); | ||
var isInvalid = isInvalidSplitReason(reason); | ||
var isRemoved = isRemovedReason(reason); | ||
const id = node.getAttribute(dataAttributeId); | ||
const name = node.getAttribute(dataAttributeName); | ||
const label = node.innerText; | ||
return { | ||
id, | ||
label, | ||
name | ||
}; | ||
} | ||
}], | ||
toDOM: node => { | ||
var _matcher$mentionClass; | ||
var removeCommand = function removeCommand() { | ||
setMarkRemoved(); | ||
const _ref = node.attrs, | ||
{ | ||
label: _, | ||
id, | ||
name, | ||
replacementType, | ||
range | ||
} = _ref, | ||
attrs = _objectWithoutProperties(_ref, ["label", "id", "name", "replacementType", "range"]); | ||
try { | ||
// This might fail when a deletion has taken place. | ||
isInvalid ? remove({ | ||
range: match.range | ||
}) : noop(); | ||
} catch (_unused) {// This sometimes fails and it's best to ignore until more is | ||
// known about the impact. | ||
} | ||
}; | ||
const matcher = this.options.matchers.find(matcher => matcher.name === name); | ||
const mentionClassName = matcher ? (_matcher$mentionClass = matcher.mentionClassName) !== null && _matcher$mentionClass !== void 0 ? _matcher$mentionClass : DEFAULT_MATCHER.mentionClassName : DEFAULT_MATCHER.mentionClassName; | ||
return [this.options.mentionTag, _objectSpread$1({}, attrs, { | ||
class: name ? "".concat(mentionClassName, " ").concat(mentionClassName, "-").concat(name) : mentionClassName, | ||
[dataAttributeId]: id, | ||
[dataAttributeName]: name | ||
}), 0]; | ||
} | ||
}; | ||
} | ||
/** | ||
* A function for creating the mention for the first time. | ||
*/ | ||
var createCommand = function createCommand(_ref10) { | ||
var _ref10$replacementTyp = _ref10.replacementType, | ||
replacementType = _ref10$replacementTyp === void 0 ? isSplit ? 'partial' : 'full' : _ref10$replacementTyp, | ||
_ref10$id = _ref10.id, | ||
id = _ref10$id === void 0 ? match.queryText[replacementType] : _ref10$id, | ||
_ref10$label = _ref10.label, | ||
label = _ref10$label === void 0 ? match.matchText[replacementType] : _ref10$label, | ||
appendText = _ref10.appendText, | ||
attrs = _objectWithoutProperties(_ref10, ["replacementType", "id", "label", "appendText"]); | ||
fn(_objectSpread$1({ | ||
id: id, | ||
label: label, | ||
appendText: appendText, | ||
replacementType: replacementType, | ||
name: name, | ||
range: range | ||
}, attrs)); | ||
}; | ||
commands({ | ||
type, | ||
getState | ||
}) { | ||
return { | ||
createMention: this.createMention(type, getState), | ||
updateMention: this.createMention(type, getState, true), | ||
removeMention: ({ | ||
range | ||
} = Object.create(null)) => { | ||
return removeMark({ | ||
type, | ||
expand: true, | ||
range | ||
var command = isInvalid || isRemoved ? removeCommand : createCommand; | ||
return command; | ||
} | ||
}); | ||
} | ||
}; | ||
} | ||
pasteRules({ | ||
type | ||
}) { | ||
return this.options.matchers.map(matcher => { | ||
const { | ||
startOfLine, | ||
char, | ||
supportedCharacters, | ||
name | ||
} = _objectSpread$1({}, DEFAULT_MATCHER, {}, matcher); | ||
const regexp = new RegExp("(".concat(getRegexPrefix(startOfLine)).concat(escapeChar(char)).concat(regexToString(supportedCharacters), ")"), 'g'); | ||
return markPasteRule({ | ||
regexp, | ||
type, | ||
getAttrs: str => ({ | ||
id: getMatchString(str.slice(char.length, str.length)), | ||
label: getMatchString(str), | ||
name | ||
}) | ||
}); | ||
}); | ||
} | ||
} | ||
}, { | ||
key: "name", | ||
get: function get() { | ||
return 'mention'; | ||
} | ||
/** | ||
* Provide the default options for this extension | ||
*/ | ||
suggestions({ | ||
getActions, | ||
type, | ||
getState | ||
}) { | ||
const { | ||
matchers, | ||
onChange, | ||
onExit, | ||
noDecorations, | ||
keyBindings, | ||
onCharacterEntry, | ||
suggestTag | ||
} = this.options; | ||
return matchers.map(matcher => { | ||
return _objectSpread$1({}, DEFAULT_MATCHER, {}, matcher, { | ||
noDecorations, | ||
suggestTag, | ||
onChange, | ||
onExit, | ||
keyBindings, | ||
onCharacterEntry, | ||
createCommand: ({ | ||
match, | ||
reason, | ||
setMarkRemoved | ||
}) => { | ||
const { | ||
suggester: { | ||
name | ||
}, | ||
range | ||
} = match; | ||
const create = getActions('createMention'); | ||
const update = getActions('updateMention'); | ||
const remove = getActions('removeMention'); | ||
const isActive = isMarkActive({ | ||
from: match.range.from, | ||
to: match.range.end, | ||
type: type, | ||
state: getState() | ||
}); | ||
const fn = isActive ? update : create; | ||
const isSplit = isSplitReason(reason); | ||
const isInvalid = isInvalidSplitReason(reason); | ||
const isRemoved = isRemovedReason(reason); | ||
}, { | ||
key: "defaultOptions", | ||
get: function get() { | ||
return { | ||
matchers: [], | ||
appendText: ' ', | ||
mentionClassName: 'mention', | ||
extraAttrs: [], | ||
mentionTag: 'a', | ||
suggestTag: 'a', | ||
onChange: defaultHandler, | ||
onExit: defaultHandler, | ||
onCharacterEntry: defaultHandler, | ||
keyBindings: {} | ||
}; | ||
} | ||
}, { | ||
key: "schema", | ||
get: function get() { | ||
var _this2 = this; | ||
const removeCommand = () => { | ||
setMarkRemoved(); | ||
try { | ||
// This might fail when a deletion has taken place. | ||
isInvalid ? remove({ | ||
range: match.range | ||
}) : noop(); | ||
} catch (_unused) {// This sometimes fails and it's best to ignore until more is | ||
// known about the impact. | ||
var dataAttributeId = 'data-mention-id'; | ||
var dataAttributeName = 'data-mention-name'; | ||
return { | ||
attrs: _objectSpread$1({ | ||
id: {}, | ||
label: {}, | ||
name: {} | ||
}, this.extraAttrs()), | ||
group: MarkGroup.Behavior, | ||
excludes: '_', | ||
inclusive: false, | ||
parseDOM: [{ | ||
tag: "".concat(this.options.mentionTag, "[").concat(dataAttributeId, "]"), | ||
getAttrs: function getAttrs(node) { | ||
if (!isElementDOMNode(node)) { | ||
return false; | ||
} | ||
}; | ||
const createCommand = (_ref2) => { | ||
let { | ||
replacementType = isSplit ? 'partial' : 'full', | ||
id = match.queryText[replacementType], | ||
label = match.matchText[replacementType], | ||
appendText | ||
} = _ref2, | ||
attrs = _objectWithoutProperties(_ref2, ["replacementType", "id", "label", "appendText"]); | ||
var id = node.getAttribute(dataAttributeId); | ||
var name = node.getAttribute(dataAttributeName); | ||
var label = node.innerText; | ||
return { | ||
id: id, | ||
label: label, | ||
name: name | ||
}; | ||
} | ||
}], | ||
toDOM: function toDOM(node) { | ||
var _matcher$mentionClass, _objectSpread2; | ||
fn(_objectSpread$1({ | ||
id, | ||
label, | ||
appendText, | ||
replacementType, | ||
name, | ||
range | ||
}, attrs)); | ||
}; | ||
var _ref11 = node.attrs, | ||
_ = _ref11.label, | ||
id = _ref11.id, | ||
name = _ref11.name, | ||
replacementType = _ref11.replacementType, | ||
range = _ref11.range, | ||
attrs = _objectWithoutProperties(_ref11, ["label", "id", "name", "replacementType", "range"]); | ||
const command = isInvalid || isRemoved ? removeCommand : createCommand; | ||
return command; | ||
var matcher = _this2.options.matchers.find(function (matcher) { | ||
return matcher.name === name; | ||
}); | ||
var mentionClassName = matcher ? (_matcher$mentionClass = matcher.mentionClassName) !== null && _matcher$mentionClass !== void 0 ? _matcher$mentionClass : DEFAULT_MATCHER.mentionClassName : DEFAULT_MATCHER.mentionClassName; | ||
return [_this2.options.mentionTag, _objectSpread$1({}, attrs, (_objectSpread2 = { | ||
"class": name ? "".concat(mentionClassName, " ").concat(mentionClassName, "-").concat(name) : mentionClassName | ||
}, _defineProperty(_objectSpread2, dataAttributeId, id), _defineProperty(_objectSpread2, dataAttributeName, name), _objectSpread2)), 0]; | ||
} | ||
}); | ||
}); | ||
} | ||
}; | ||
} | ||
/** | ||
* A function for creating the mention for the first time. | ||
*/ | ||
} | ||
}]); | ||
return MentionExtension; | ||
}(MarkExtension); | ||
export { MentionExtension }; | ||
//# sourceMappingURL=extension-mention.esm.js.map |
@@ -8,2 +8,8 @@ 'use strict'; | ||
var _objectWithoutProperties = _interopDefault(require('@babel/runtime/helpers/objectWithoutProperties')); | ||
var _classCallCheck = _interopDefault(require('@babel/runtime/helpers/classCallCheck')); | ||
var _createClass = _interopDefault(require('@babel/runtime/helpers/createClass')); | ||
var _possibleConstructorReturn = _interopDefault(require('@babel/runtime/helpers/possibleConstructorReturn')); | ||
var _getPrototypeOf = _interopDefault(require('@babel/runtime/helpers/getPrototypeOf')); | ||
var _assertThisInitialized = _interopDefault(require('@babel/runtime/helpers/assertThisInitialized')); | ||
var _inherits = _interopDefault(require('@babel/runtime/helpers/inherits')); | ||
var _defineProperty = _interopDefault(require('@babel/runtime/helpers/defineProperty')); | ||
@@ -18,3 +24,5 @@ var core = require('@remirror/core'); | ||
const defaultHandler = () => false; | ||
var defaultHandler = function defaultHandler() { | ||
return false; | ||
}; | ||
/** | ||
@@ -27,311 +35,334 @@ * The mention extension manages suggestions through onChange, onKeyDown, onExit and onEnter callbacks. | ||
class MentionExtension extends core.MarkExtension { | ||
constructor(...args) { | ||
super(...args); | ||
var MentionExtension = | ||
/*#__PURE__*/ | ||
function (_MarkExtension) { | ||
_inherits(MentionExtension, _MarkExtension); | ||
_defineProperty(this, "createMention", (type, getState, shouldUpdate = false) => config => { | ||
if (!mentionUtils.isValidMentionAttrs(config)) { | ||
throw new Error('Invalid configuration attributes passed to the MentionExtension command.'); | ||
} | ||
function MentionExtension() { | ||
var _getPrototypeOf2; | ||
const { | ||
range, | ||
appendText, | ||
replacementType | ||
} = config, | ||
var _this; | ||
_classCallCheck(this, MentionExtension); | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(MentionExtension)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
_defineProperty(_assertThisInitialized(_this), "createMention", function (type, getState) { | ||
var shouldUpdate = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; | ||
return function (config) { | ||
if (!mentionUtils.isValidMentionAttrs(config)) { | ||
throw new Error('Invalid configuration attributes passed to the MentionExtension command.'); | ||
} | ||
var range = config.range, | ||
appendText = config.appendText, | ||
replacementType = config.replacementType, | ||
attrs = _objectWithoutProperties(config, ["range", "appendText", "replacementType"]); | ||
let name = attrs.name; | ||
var name = attrs.name; | ||
if (!name) { | ||
if (this.options.matchers.length >= 2) { | ||
throw new Error('The MentionExtension command must specify a name since there are multiple matchers configured'); | ||
if (!name) { | ||
if (_this.options.matchers.length >= 2) { | ||
throw new Error('The MentionExtension command must specify a name since there are multiple matchers configured'); | ||
} | ||
name = _this.options.matchers[0].name; | ||
} | ||
name = this.options.matchers[0].name; | ||
} | ||
var allowedNames = _this.options.matchers.map(function (_ref) { | ||
var name = _ref.name; | ||
return name; | ||
}); | ||
const allowedNames = this.options.matchers.map(({ | ||
name | ||
}) => name); | ||
if (!allowedNames.includes(name)) { | ||
throw new Error("The name '".concat(name, "' specified for this command is invalid. Please choose from: ").concat(JSON.stringify(allowedNames), ".")); | ||
} | ||
if (!allowedNames.includes(name)) { | ||
throw new Error("The name '".concat(name, "' specified for this command is invalid. Please choose from: ").concat(JSON.stringify(allowedNames), ".")); | ||
} | ||
var matcher = mentionUtils.getMatcher(name, _this.options.matchers); | ||
const matcher = mentionUtils.getMatcher(name, this.options.matchers); | ||
if (!matcher) { | ||
throw new Error("Mentions matcher not found for name ".concat(name, ".")); | ||
} | ||
if (!matcher) { | ||
throw new Error("Mentions matcher not found for name ".concat(name, ".")); | ||
} | ||
var _ref2 = range !== null && range !== void 0 ? range : getState().selection, | ||
from = _ref2.from, | ||
to = _ref2.to; | ||
const { | ||
from, | ||
to | ||
} = range !== null && range !== void 0 ? range : getState().selection; | ||
let startTransaction; | ||
var startTransaction; | ||
if (shouldUpdate) { | ||
// Remove all currently active marks before proceeding. | ||
startTransaction = (tr, state) => { | ||
// Remove mark at previous position | ||
let { | ||
oldFrom, | ||
oldTo | ||
} = { | ||
oldFrom: from, | ||
oldTo: range ? range.end : to | ||
}; | ||
const $oldTo = state.doc.resolve(oldTo); | ||
({ | ||
from: oldFrom, | ||
to: oldTo | ||
} = core.getMarkRange($oldTo, type) || { | ||
from: oldFrom, | ||
to: oldTo | ||
}); | ||
tr.removeMark(oldFrom, oldTo, type); | ||
tr.setMeta('addToHistory', false); // Remove mark at current position | ||
if (shouldUpdate) { | ||
// Remove all currently active marks before proceeding. | ||
startTransaction = function startTransaction(tr, state) { | ||
// Remove mark at previous position | ||
var _oldFrom$oldTo = { | ||
oldFrom: from, | ||
oldTo: range ? range.end : to | ||
}, | ||
oldFrom = _oldFrom$oldTo.oldFrom, | ||
oldTo = _oldFrom$oldTo.oldTo; | ||
var $oldTo = state.doc.resolve(oldTo); | ||
const $newTo = tr.selection.$from; | ||
const { | ||
from: newFrom, | ||
to: newTo | ||
} = core.getMarkRange($newTo, type) || { | ||
from: $newTo.pos, | ||
to: $newTo.pos | ||
var _ref3 = core.getMarkRange($oldTo, type) || { | ||
from: oldFrom, | ||
to: oldTo | ||
}; | ||
oldFrom = _ref3.from; | ||
oldTo = _ref3.to; | ||
tr.removeMark(oldFrom, oldTo, type); | ||
tr.setMeta('addToHistory', false); // Remove mark at current position | ||
var $newTo = tr.selection.$from; | ||
var _ref4 = core.getMarkRange($newTo, type) || { | ||
from: $newTo.pos, | ||
to: $newTo.pos | ||
}, | ||
newFrom = _ref4.from, | ||
newTo = _ref4.to; | ||
tr.removeMark(newFrom, newTo, type); | ||
return tr.setMeta('addToHistory', false); | ||
}; | ||
tr.removeMark(newFrom, newTo, type); | ||
return tr.setMeta('addToHistory', false); | ||
}; | ||
} | ||
} | ||
return core.replaceText({ | ||
type, | ||
attrs: _objectSpread({}, attrs, { | ||
name | ||
}), | ||
appendText: mentionUtils.getAppendText(appendText, matcher.appendText), | ||
range: range ? { | ||
from, | ||
to: replacementType === 'full' ? range.end || to : to | ||
} : undefined, | ||
content: attrs.label, | ||
startTransaction | ||
}); | ||
return core.replaceText({ | ||
type: type, | ||
attrs: _objectSpread({}, attrs, { | ||
name: name | ||
}), | ||
appendText: mentionUtils.getAppendText(appendText, matcher.appendText), | ||
range: range ? { | ||
from: from, | ||
to: replacementType === 'full' ? range.end || to : to | ||
} : undefined, | ||
content: attrs.label, | ||
startTransaction: startTransaction | ||
}); | ||
}; | ||
}); | ||
} | ||
get name() { | ||
return 'mention'; | ||
return _this; | ||
} | ||
/** | ||
* Provide the default options for this extension | ||
*/ | ||
_createClass(MentionExtension, [{ | ||
key: "commands", | ||
value: function commands(_ref5) { | ||
var type = _ref5.type, | ||
getState = _ref5.getState; | ||
return { | ||
createMention: this.createMention(type, getState), | ||
updateMention: this.createMention(type, getState, true), | ||
removeMention: function removeMention() { | ||
var _ref6 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Object.create(null), | ||
range = _ref6.range; | ||
get defaultOptions() { | ||
return { | ||
matchers: [], | ||
appendText: ' ', | ||
mentionClassName: 'mention', | ||
extraAttrs: [], | ||
mentionTag: 'a', | ||
suggestTag: 'a', | ||
onChange: defaultHandler, | ||
onExit: defaultHandler, | ||
onCharacterEntry: defaultHandler, | ||
keyBindings: {} | ||
}; | ||
} | ||
return core.removeMark({ | ||
type: type, | ||
expand: true, | ||
range: range | ||
}); | ||
} | ||
}; | ||
} | ||
}, { | ||
key: "pasteRules", | ||
value: function pasteRules(_ref7) { | ||
var type = _ref7.type; | ||
return this.options.matchers.map(function (matcher) { | ||
var _DEFAULT_MATCHER$matc = _objectSpread({}, mentionUtils.DEFAULT_MATCHER, {}, matcher), | ||
startOfLine = _DEFAULT_MATCHER$matc.startOfLine, | ||
_char = _DEFAULT_MATCHER$matc["char"], | ||
supportedCharacters = _DEFAULT_MATCHER$matc.supportedCharacters, | ||
name = _DEFAULT_MATCHER$matc.name; | ||
get schema() { | ||
const dataAttributeId = 'data-mention-id'; | ||
const dataAttributeName = 'data-mention-name'; | ||
return { | ||
attrs: _objectSpread({ | ||
id: {}, | ||
label: {}, | ||
name: {} | ||
}, this.extraAttrs()), | ||
group: core.MarkGroup.Behavior, | ||
excludes: '_', | ||
inclusive: false, | ||
parseDOM: [{ | ||
tag: "".concat(this.options.mentionTag, "[").concat(dataAttributeId, "]"), | ||
getAttrs: node => { | ||
if (!core.isElementDOMNode(node)) { | ||
return false; | ||
var regexp = new RegExp("(".concat(prosemirrorSuggest.getRegexPrefix(startOfLine)).concat(prosemirrorSuggest.escapeChar(_char)).concat(prosemirrorSuggest.regexToString(supportedCharacters), ")"), 'g'); | ||
return core.markPasteRule({ | ||
regexp: regexp, | ||
type: type, | ||
getAttrs: function getAttrs(str) { | ||
return { | ||
id: core.getMatchString(str.slice(_char.length, str.length)), | ||
label: core.getMatchString(str), | ||
name: name | ||
}; | ||
} | ||
}); | ||
}); | ||
} | ||
}, { | ||
key: "suggestions", | ||
value: function suggestions(_ref8) { | ||
var getActions = _ref8.getActions, | ||
type = _ref8.type, | ||
getState = _ref8.getState; | ||
var _this$options = this.options, | ||
matchers = _this$options.matchers, | ||
onChange = _this$options.onChange, | ||
onExit = _this$options.onExit, | ||
noDecorations = _this$options.noDecorations, | ||
keyBindings = _this$options.keyBindings, | ||
onCharacterEntry = _this$options.onCharacterEntry, | ||
suggestTag = _this$options.suggestTag; | ||
return matchers.map(function (matcher) { | ||
return _objectSpread({}, mentionUtils.DEFAULT_MATCHER, {}, matcher, { | ||
noDecorations: noDecorations, | ||
suggestTag: suggestTag, | ||
onChange: onChange, | ||
onExit: onExit, | ||
keyBindings: keyBindings, | ||
onCharacterEntry: onCharacterEntry, | ||
createCommand: function createCommand(_ref9) { | ||
var match = _ref9.match, | ||
reason = _ref9.reason, | ||
setMarkRemoved = _ref9.setMarkRemoved; | ||
var name = match.suggester.name, | ||
range = match.range; | ||
var create = getActions('createMention'); | ||
var update = getActions('updateMention'); | ||
var remove = getActions('removeMention'); | ||
var isActive = core.isMarkActive({ | ||
from: match.range.from, | ||
to: match.range.end, | ||
type: type, | ||
state: getState() | ||
}); | ||
var fn = isActive ? update : create; | ||
var isSplit = prosemirrorSuggest.isSplitReason(reason); | ||
var isInvalid = prosemirrorSuggest.isInvalidSplitReason(reason); | ||
var isRemoved = prosemirrorSuggest.isRemovedReason(reason); | ||
const id = node.getAttribute(dataAttributeId); | ||
const name = node.getAttribute(dataAttributeName); | ||
const label = node.innerText; | ||
return { | ||
id, | ||
label, | ||
name | ||
}; | ||
} | ||
}], | ||
toDOM: node => { | ||
var _matcher$mentionClass; | ||
var removeCommand = function removeCommand() { | ||
setMarkRemoved(); | ||
const _ref = node.attrs, | ||
{ | ||
label: _, | ||
id, | ||
name, | ||
replacementType, | ||
range | ||
} = _ref, | ||
attrs = _objectWithoutProperties(_ref, ["label", "id", "name", "replacementType", "range"]); | ||
try { | ||
// This might fail when a deletion has taken place. | ||
isInvalid ? remove({ | ||
range: match.range | ||
}) : core.noop(); | ||
} catch (_unused) {// This sometimes fails and it's best to ignore until more is | ||
// known about the impact. | ||
} | ||
}; | ||
const matcher = this.options.matchers.find(matcher => matcher.name === name); | ||
const mentionClassName = matcher ? (_matcher$mentionClass = matcher.mentionClassName) !== null && _matcher$mentionClass !== void 0 ? _matcher$mentionClass : mentionUtils.DEFAULT_MATCHER.mentionClassName : mentionUtils.DEFAULT_MATCHER.mentionClassName; | ||
return [this.options.mentionTag, _objectSpread({}, attrs, { | ||
class: name ? "".concat(mentionClassName, " ").concat(mentionClassName, "-").concat(name) : mentionClassName, | ||
[dataAttributeId]: id, | ||
[dataAttributeName]: name | ||
}), 0]; | ||
} | ||
}; | ||
} | ||
/** | ||
* A function for creating the mention for the first time. | ||
*/ | ||
var createCommand = function createCommand(_ref10) { | ||
var _ref10$replacementTyp = _ref10.replacementType, | ||
replacementType = _ref10$replacementTyp === void 0 ? isSplit ? 'partial' : 'full' : _ref10$replacementTyp, | ||
_ref10$id = _ref10.id, | ||
id = _ref10$id === void 0 ? match.queryText[replacementType] : _ref10$id, | ||
_ref10$label = _ref10.label, | ||
label = _ref10$label === void 0 ? match.matchText[replacementType] : _ref10$label, | ||
appendText = _ref10.appendText, | ||
attrs = _objectWithoutProperties(_ref10, ["replacementType", "id", "label", "appendText"]); | ||
fn(_objectSpread({ | ||
id: id, | ||
label: label, | ||
appendText: appendText, | ||
replacementType: replacementType, | ||
name: name, | ||
range: range | ||
}, attrs)); | ||
}; | ||
commands({ | ||
type, | ||
getState | ||
}) { | ||
return { | ||
createMention: this.createMention(type, getState), | ||
updateMention: this.createMention(type, getState, true), | ||
removeMention: ({ | ||
range | ||
} = Object.create(null)) => { | ||
return core.removeMark({ | ||
type, | ||
expand: true, | ||
range | ||
var command = isInvalid || isRemoved ? removeCommand : createCommand; | ||
return command; | ||
} | ||
}); | ||
} | ||
}; | ||
} | ||
pasteRules({ | ||
type | ||
}) { | ||
return this.options.matchers.map(matcher => { | ||
const { | ||
startOfLine, | ||
char, | ||
supportedCharacters, | ||
name | ||
} = _objectSpread({}, mentionUtils.DEFAULT_MATCHER, {}, matcher); | ||
const regexp = new RegExp("(".concat(prosemirrorSuggest.getRegexPrefix(startOfLine)).concat(prosemirrorSuggest.escapeChar(char)).concat(prosemirrorSuggest.regexToString(supportedCharacters), ")"), 'g'); | ||
return core.markPasteRule({ | ||
regexp, | ||
type, | ||
getAttrs: str => ({ | ||
id: core.getMatchString(str.slice(char.length, str.length)), | ||
label: core.getMatchString(str), | ||
name | ||
}) | ||
}); | ||
}); | ||
} | ||
} | ||
}, { | ||
key: "name", | ||
get: function get() { | ||
return 'mention'; | ||
} | ||
/** | ||
* Provide the default options for this extension | ||
*/ | ||
suggestions({ | ||
getActions, | ||
type, | ||
getState | ||
}) { | ||
const { | ||
matchers, | ||
onChange, | ||
onExit, | ||
noDecorations, | ||
keyBindings, | ||
onCharacterEntry, | ||
suggestTag | ||
} = this.options; | ||
return matchers.map(matcher => { | ||
return _objectSpread({}, mentionUtils.DEFAULT_MATCHER, {}, matcher, { | ||
noDecorations, | ||
suggestTag, | ||
onChange, | ||
onExit, | ||
keyBindings, | ||
onCharacterEntry, | ||
createCommand: ({ | ||
match, | ||
reason, | ||
setMarkRemoved | ||
}) => { | ||
const { | ||
suggester: { | ||
name | ||
}, | ||
range | ||
} = match; | ||
const create = getActions('createMention'); | ||
const update = getActions('updateMention'); | ||
const remove = getActions('removeMention'); | ||
const isActive = core.isMarkActive({ | ||
from: match.range.from, | ||
to: match.range.end, | ||
type: type, | ||
state: getState() | ||
}); | ||
const fn = isActive ? update : create; | ||
const isSplit = prosemirrorSuggest.isSplitReason(reason); | ||
const isInvalid = prosemirrorSuggest.isInvalidSplitReason(reason); | ||
const isRemoved = prosemirrorSuggest.isRemovedReason(reason); | ||
}, { | ||
key: "defaultOptions", | ||
get: function get() { | ||
return { | ||
matchers: [], | ||
appendText: ' ', | ||
mentionClassName: 'mention', | ||
extraAttrs: [], | ||
mentionTag: 'a', | ||
suggestTag: 'a', | ||
onChange: defaultHandler, | ||
onExit: defaultHandler, | ||
onCharacterEntry: defaultHandler, | ||
keyBindings: {} | ||
}; | ||
} | ||
}, { | ||
key: "schema", | ||
get: function get() { | ||
var _this2 = this; | ||
const removeCommand = () => { | ||
setMarkRemoved(); | ||
try { | ||
// This might fail when a deletion has taken place. | ||
isInvalid ? remove({ | ||
range: match.range | ||
}) : core.noop(); | ||
} catch (_unused) {// This sometimes fails and it's best to ignore until more is | ||
// known about the impact. | ||
var dataAttributeId = 'data-mention-id'; | ||
var dataAttributeName = 'data-mention-name'; | ||
return { | ||
attrs: _objectSpread({ | ||
id: {}, | ||
label: {}, | ||
name: {} | ||
}, this.extraAttrs()), | ||
group: core.MarkGroup.Behavior, | ||
excludes: '_', | ||
inclusive: false, | ||
parseDOM: [{ | ||
tag: "".concat(this.options.mentionTag, "[").concat(dataAttributeId, "]"), | ||
getAttrs: function getAttrs(node) { | ||
if (!core.isElementDOMNode(node)) { | ||
return false; | ||
} | ||
}; | ||
const createCommand = (_ref2) => { | ||
let { | ||
replacementType = isSplit ? 'partial' : 'full', | ||
id = match.queryText[replacementType], | ||
label = match.matchText[replacementType], | ||
appendText | ||
} = _ref2, | ||
attrs = _objectWithoutProperties(_ref2, ["replacementType", "id", "label", "appendText"]); | ||
var id = node.getAttribute(dataAttributeId); | ||
var name = node.getAttribute(dataAttributeName); | ||
var label = node.innerText; | ||
return { | ||
id: id, | ||
label: label, | ||
name: name | ||
}; | ||
} | ||
}], | ||
toDOM: function toDOM(node) { | ||
var _matcher$mentionClass, _objectSpread2; | ||
fn(_objectSpread({ | ||
id, | ||
label, | ||
appendText, | ||
replacementType, | ||
name, | ||
range | ||
}, attrs)); | ||
}; | ||
var _ref11 = node.attrs, | ||
_ = _ref11.label, | ||
id = _ref11.id, | ||
name = _ref11.name, | ||
replacementType = _ref11.replacementType, | ||
range = _ref11.range, | ||
attrs = _objectWithoutProperties(_ref11, ["label", "id", "name", "replacementType", "range"]); | ||
const command = isInvalid || isRemoved ? removeCommand : createCommand; | ||
return command; | ||
var matcher = _this2.options.matchers.find(function (matcher) { | ||
return matcher.name === name; | ||
}); | ||
var mentionClassName = matcher ? (_matcher$mentionClass = matcher.mentionClassName) !== null && _matcher$mentionClass !== void 0 ? _matcher$mentionClass : mentionUtils.DEFAULT_MATCHER.mentionClassName : mentionUtils.DEFAULT_MATCHER.mentionClassName; | ||
return [_this2.options.mentionTag, _objectSpread({}, attrs, (_objectSpread2 = { | ||
"class": name ? "".concat(mentionClassName, " ").concat(mentionClassName, "-").concat(name) : mentionClassName | ||
}, _defineProperty(_objectSpread2, dataAttributeId, id), _defineProperty(_objectSpread2, dataAttributeName, name), _objectSpread2)), 0]; | ||
} | ||
}); | ||
}); | ||
} | ||
}; | ||
} | ||
/** | ||
* A function for creating the mention for the first time. | ||
*/ | ||
} | ||
}]); | ||
return MentionExtension; | ||
}(core.MarkExtension); | ||
exports.MentionExtension = MentionExtension; | ||
//# sourceMappingURL=mention-extension.js.map |
@@ -18,3 +18,3 @@ 'use strict'; | ||
*/ | ||
const DEFAULT_MATCHER = _objectSpread({}, core.pick(prosemirrorSuggest.DEFAULT_SUGGESTER, ['startOfLine', 'supportedCharacters', 'validPrefixCharacters', 'invalidPrefixCharacters', 'appendText', 'suggestClassName']), { | ||
var DEFAULT_MATCHER = _objectSpread({}, core.pick(prosemirrorSuggest.DEFAULT_SUGGESTER, ['startOfLine', 'supportedCharacters', 'validPrefixCharacters', 'invalidPrefixCharacters', 'appendText', 'suggestClassName']), { | ||
appendText: ' ', | ||
@@ -29,3 +29,5 @@ matchOffset: 1, | ||
const isValidMentionAttrs = attrs => core.bool(attrs && core.isPlainObject(attrs) && attrs.id && attrs.label); | ||
var isValidMentionAttrs = function isValidMentionAttrs(attrs) { | ||
return core.bool(attrs && core.isPlainObject(attrs) && attrs.id && attrs.label); | ||
}; | ||
/** | ||
@@ -38,4 +40,6 @@ * Gets the matcher from the list of matchers if it exists. | ||
const getMatcher = (name, matchers) => { | ||
const matcher = matchers.find(matcher => matcher.name === name); | ||
var getMatcher = function getMatcher(name, matchers) { | ||
var matcher = matchers.find(function (matcher) { | ||
return matcher.name === name; | ||
}); | ||
return matcher ? _objectSpread({}, DEFAULT_MATCHER, {}, matcher) : undefined; | ||
@@ -48,3 +52,3 @@ }; | ||
const getAppendText = (preferred, fallback) => { | ||
var getAppendText = function getAppendText(preferred, fallback) { | ||
if (core.isString(preferred)) { | ||
@@ -51,0 +55,0 @@ return preferred; |
@@ -8,3 +8,3 @@ { | ||
"repository": "https://github.com/remirror/remirror/tree/master/@remirror/extension-mention", | ||
"version": "0.7.5", | ||
"version": "0.7.6", | ||
"main": "lib/index.js", | ||
@@ -20,3 +20,3 @@ "module": "lib/dist/extension-mention.esm.js", | ||
"@babel/runtime": "^7", | ||
"@remirror/core": "^0.8.0", | ||
"@remirror/core": "^0.9.0", | ||
"@types/prosemirror-keymap": "^1.0.1", | ||
@@ -27,3 +27,3 @@ "@types/prosemirror-state": "^1.2.3", | ||
"prosemirror-state": "^1.2.4", | ||
"prosemirror-suggest": "^0.7.5", | ||
"prosemirror-suggest": "^0.7.6", | ||
"prosemirror-view": "^1.12.0" | ||
@@ -30,0 +30,0 @@ }, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
150135
10.33%1986
4.09%+ Added
- Removed
- Removed
- Removed
- Removed
Updated
Updated