UNPKG

@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
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);