@lobehub/editor
Version:
A powerful and extensible rich text editor built on Meta's Lexical framework, providing a modern editing experience with React integration.
159 lines (156 loc) • 11.1 kB
JavaScript
var _class;
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
function _get() { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get.bind(); } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(arguments.length < 3 ? target : receiver); } return desc.value; }; } return _get.apply(this, arguments); }
function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); }
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
import { $getSelection, $isRangeSelection, COMMAND_PRIORITY_CRITICAL, KEY_DOWN_COMMAND } from 'lexical';
import { KernelPlugin } from "../../../editor-kernel/plugin";
import { ISlashService, SlashService } from "../service/i-slash-service";
import { getQueryTextForSearch, tryToPositionRange } from "../utils/utils";
export var SlashPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
_inherits(SlashPlugin, _KernelPlugin);
var _super = _createSuper(SlashPlugin);
function SlashPlugin(kernel, config) {
var _this;
_classCallCheck(this, SlashPlugin);
_this = _super.call(this);
_defineProperty(_assertThisInitialized(_this), "service", null);
_defineProperty(_assertThisInitialized(_this), "currentSlashTrigger", null);
_defineProperty(_assertThisInitialized(_this), "currentSlashTriggerIndex", -1);
_defineProperty(_assertThisInitialized(_this), "suppressOpen", false);
_this.config = config;
_this.service = new SlashService(kernel);
kernel.registerService(ISlashService, _this.service);
if (config !== null && config !== void 0 && config.slashOptions) {
config.slashOptions.forEach(function (option) {
var _this$service;
(_this$service = _this.service) === null || _this$service === void 0 || _this$service.registerSlash(option);
});
}
return _this;
}
_createClass(SlashPlugin, [{
key: "triggerClose",
value: function triggerClose() {
var _this$config;
(_this$config = this.config) === null || _this$config === void 0 || _this$config.triggerClose();
this.currentSlashTrigger = null;
this.currentSlashTriggerIndex = -1;
// After an explicit close, suppress reopening until next typing input
this.suppressOpen = true;
}
}, {
key: "onInit",
value: function onInit(editor) {
var _this2 = this;
// Reset suppression on typing-related key presses
this.register(editor.registerCommand(KEY_DOWN_COMMAND, function (event) {
if (event.isComposing) return false;
var key = event.key;
// Any character input or deletion should re-enable opening
if (key.length === 1 || key === 'Backspace' || key === 'Delete') {
_this2.suppressOpen = false;
}
return false;
}, COMMAND_PRIORITY_CRITICAL));
this.register(editor.registerUpdateListener(function () {
editor.getEditorState().read(function () {
var _this2$service, _this2$service2, _this2$service3;
if (!editor.isEditable()) {
// Trigger close
_this2.triggerClose();
return;
}
var isComposing = editor.isComposing();
if (isComposing) {
// Currently typing, do not handle
return;
}
var editorWindow = editor._window || window;
// Skip on server side
if (editorWindow === undefined || !editorWindow.document) {
return;
}
var range = editorWindow.document.createRange();
var selection = $getSelection();
var text = getQueryTextForSearch(editor);
if (!$isRangeSelection(selection) || !selection.isCollapsed() ||
// Do not trigger inside code
selection.hasFormat('code') || text === null || range === null || _this2.currentSlashTrigger === null && text.length > 1 && text.at(-2) !== ' ') {
_this2.triggerClose();
return;
}
// If we previously suppressed opening, do not reopen until user types
if (_this2.currentSlashTrigger === null && _this2.suppressOpen) {
_this2.triggerClose();
return;
}
var triggerText = _this2.currentSlashTrigger;
if (triggerText === null) {
triggerText = text.slice(-1);
_this2.currentSlashTriggerIndex = text.length - 1;
}
var lastIndex = text.lastIndexOf(triggerText);
if (lastIndex < _this2.currentSlashTriggerIndex) {
_this2.triggerClose();
return;
}
var slashOptions = (_this2$service = _this2.service) === null || _this2$service === void 0 ? void 0 : _this2$service.getSlashOptions(triggerText);
var maxLength = (slashOptions === null || slashOptions === void 0 ? void 0 : slashOptions.maxLength) || 75;
// Exceeds maximum length
if (text.length - lastIndex > maxLength || !slashOptions) {
_this2.triggerClose();
return;
}
var triggerFn = (_this2$service2 = _this2.service) === null || _this2$service2 === void 0 ? void 0 : _this2$service2.getSlashTriggerFn(triggerText);
var fuse = (_this2$service3 = _this2.service) === null || _this2$service3 === void 0 ? void 0 : _this2$service3.getSlashFuse(triggerText);
var isRangePositioned = tryToPositionRange(_this2.currentSlashTriggerIndex, range, editorWindow);
var match = triggerFn === null || triggerFn === void 0 ? void 0 : triggerFn(text.slice(_this2.currentSlashTriggerIndex));
// Check if there's a space in the current search text that should close the menu
var searchText = text.slice(_this2.currentSlashTriggerIndex);
var hasSpaceAfterTrigger = searchText.includes(' ') && !(slashOptions !== null && slashOptions !== void 0 && slashOptions.allowWhitespace);
if (hasSpaceAfterTrigger) {
_this2.triggerClose();
return;
}
var finalItems = fuse && match && match.matchingString.length > 0 ? fuse.search(match.matchingString).map(function (result) {
return result.item;
}) : slashOptions.items;
if (isRangePositioned !== null && finalItems.length > 0) {
var _this2$config;
_this2.currentSlashTrigger = triggerText;
(_this2$config = _this2.config) === null || _this2$config === void 0 || _this2$config.triggerOpen({
getRect: function getRect() {
return range.getBoundingClientRect();
},
items: finalItems,
lastIndex: lastIndex,
match: match,
trigger: slashOptions.trigger
});
return;
}
_this2.triggerClose();
});
}));
}
}, {
key: "destroy",
value: function destroy() {
_get(_getPrototypeOf(SlashPlugin.prototype), "destroy", this).call(this);
}
}]);
return SlashPlugin;
}(KernelPlugin), _defineProperty(_class, "pluginName", 'SlashPlugin'), _class);