UNPKG

@edtr-io/plugin-text

Version:
529 lines (433 loc) 17.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createTextEditor = void 0; var _core = require("@edtr-io/core"); var _isHotkey = _interopRequireDefault(require("is-hotkey")); var React = _interopRequireWildcard(require("react")); var _slateReact = require("slate-react"); var _slate = require("slate"); var _ = require(".."); var _katex = require("../plugins/katex"); var _link = require("../plugins/link"); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); } function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } var createTextEditor = function createTextEditor(options) { var _inlines; var schema = { inlines: (_inlines = {}, _defineProperty(_inlines, _katex.katexInlineNode, { isVoid: true }), _defineProperty(_inlines, _link.linkNode, { text: /.+/ }), _inlines), blocks: _defineProperty({}, _katex.katexBlockNode, { isVoid: true }) }; return function SlateEditor(props) { var _useEditorFocus = (0, _core.useEditorFocus)(), focusPrevious = _useEditorFocus.focusPrevious, focusNext = _useEditorFocus.focusNext; var editor = React.useRef(); var store = React.useContext(_core.EditorContext); var overlayContext = React.useContext(_core.OverlayContext); var plugins = (0, _core.getPlugins)(store.state); var _React$useState = React.useState(_slate.Value.fromJSON(props.state.value)), _React$useState2 = _slicedToArray(_React$useState, 2), rawState = _React$useState2[0], setRawState = _React$useState2[1]; var lastValue = React.useRef(props.state.value); React.useEffect(function () { if (lastValue.current !== props.state.value) { setRawState(_slate.Value.fromJSON(props.state.value)); lastValue.current = props.state.value; setTimeout(function () { if (!editor.current) return; if (props.focused) { editor.current.focus(); } }); } }, [lastValue, props.focused, props.state.value]); // PLEASE DONT FIX THIS! Closure needed because on* isn't recreated so doesnt use current props var slateClosure = React.useRef({ name: props.name, plugins: plugins, insert: props.insert, replace: props.replace, remove: props.remove, parent: props.parent, focusPrevious: focusPrevious, focusNext: focusNext, mergeWithNext: props.mergeWithNext, mergeWithPrevious: props.mergeWithPrevious }); slateClosure.current = { name: props.name, plugins: plugins, insert: props.insert, replace: props.replace, remove: props.remove, parent: props.parent, focusPrevious: focusPrevious, focusNext: focusNext, mergeWithNext: props.mergeWithNext, mergeWithPrevious: props.mergeWithPrevious }; React.useEffect(function () { if (!editor.current) return; if (props.focused) { setTimeout(editor.current.focus); } else { editor.current.blur(); } }, [props.focused]); var pluginClosure = React.useRef({ overlayContext: overlayContext, name: props.name, parent: props.parent }); pluginClosure.current = { overlayContext: overlayContext, name: props.name, parent: props.parent }; var slatePlugins = React.useRef(); if (slatePlugins.current === undefined) { slatePlugins.current = [].concat(_toConsumableArray(options.plugins.map(function (slatePluginFactory) { return slatePluginFactory(pluginClosure); })), [newSlateOnEnter(slateClosure)]); } return React.createElement(_slateReact.Editor, { ref: function ref(slateReact) { if (slateReact && !editor.current) { editor.current = slateReact; patchSlateInsertFragment(slateReact); } } // ref={editor as React.RefObject<Editor>} , onPaste: createOnPaste(slateClosure), onKeyDown: createOnKeyDown(slateClosure), onClick: function onClick(e, editor, next) { if (e.target) { // @ts-ignore var node = (0, _slateReact.findNode)(e.target, editor); if (!node) { return editor; } } next(); }, onChange: function onChange(change) { var nextValue = change.value.toJSON(); setRawState(change.value); var withoutSelections = change.operations.filter(function (operation) { return typeof operation !== 'undefined' && operation.type !== 'set_selection'; }); if (!withoutSelections.isEmpty()) { lastValue.current = nextValue; props.state.set(nextValue); } }, placeholder: props.editable ? options.placeholder : '', plugins: slatePlugins.current, readOnly: !props.focused, value: rawState, schema: schema }); }; }; // PLEASE DONT FIX THIS! Closure needed because onPaste isn't recreated so doesnt use props exports.createTextEditor = createTextEditor; function createOnPaste(slateClosure) { return function (e, editor, next) { if (!slateClosure.current) { next(); return; } var _slateClosure$current = slateClosure.current, plugins = _slateClosure$current.plugins, insert = _slateClosure$current.insert, name = _slateClosure$current.name; if (typeof insert !== 'function') { next(); return; } var _ref = e, clipboardData = _ref.clipboardData; var _loop = function _loop(key) { var onPaste = plugins[key].onPaste; if (typeof onPaste === 'function') { var result = onPaste(clipboardData); if (result !== undefined) { var nextSlateState = splitBlockAtSelection(editor); setTimeout(function () { insert({ plugin: name, state: nextSlateState }); insert({ plugin: key, state: result.state }); }); return { v: void 0 }; } } }; for (var key in plugins) { var _ret = _loop(key); if (_typeof(_ret) === "object") return _ret.v; } next(); }; } // PLEASE DONT FIX THIS! Closure needed because onKeyDown isn't recreated so doesnt use props function createOnKeyDown(slateClosure) { return function (e, editor, next) { var _ref2 = e, key = _ref2.key; if ((0, _isHotkey.default)('mod+z', e) || (0, _isHotkey.default)('mod+y', e) || (0, _isHotkey.default)('mod+shift+z', e)) { e.preventDefault(); return; } if (key === 'ArrowDown' || key === 'ArrowUp') { var lastRange = getRange(); if (lastRange) { var lastY = lastRange.getBoundingClientRect().top; setTimeout(function () { if (!slateClosure.current) { return; } var currentRange = getRange(); if (!currentRange) { return; } var currentY = currentRange.getBoundingClientRect().top; if (lastY === currentY) { if (key === 'ArrowDown') { slateClosure.current.focusNext(); } else { slateClosure.current.focusPrevious(); } } }); } } if (key === 'Backspace' && selectionAtStart(editor)) { if (!slateClosure.current) return; var mergeWithPrevious = slateClosure.current.mergeWithPrevious; if (typeof mergeWithPrevious !== 'function') return; mergeWithPrevious(function (previous) { var value = _slate.Value.fromJSON(previous); var selection = _slate.Range.create(editor.value.selection); return editor // hack because empty slate looses focus .insertTextAtRange(selection, ' ').insertFragmentAtRange(selection, value.document).moveFocusBackward(1).delete().value.toJSON(); }); return; } if (key === 'Delete' && selectionAtEnd(editor)) { if (!slateClosure.current) return; var mergeWithNext = slateClosure.current.mergeWithNext; if (typeof mergeWithNext !== 'function') return; mergeWithNext(function (next) { var value = _slate.Value.fromJSON(next); var selection = _slate.Range.create(editor.value.selection); editor.insertFragmentAtRange(selection, value.document).select(selection); }); return; } return next(); }; function getRange() { var selection = window.getSelection(); if (selection.rangeCount > 0) { return selection.getRangeAt(0); } return null; } function selectionAtStart(editor) { var selection = editor.value.selection; var startNode = editor.value.document.getFirstText(); return selection.isCollapsed && startNode && editor.value.startText.key === startNode.key && selection.start.offset === 0; } function selectionAtEnd(editor) { var selection = editor.value.selection; var endNode = editor.value.document.getLastText(); return selection.isCollapsed && endNode && editor.value.endText.key === endNode.key && selection.end.offset === editor.value.endText.text.length; } } function newSlateOnEnter(slateClosure) { return { commands: { replaceWithPlugin: function replaceWithPlugin(editor, options) { if (!slateClosure.current) return editor; var replace = slateClosure.current.replace; if (typeof replace !== 'function') return editor; replace(options); return editor; }, unwrapParent: function unwrapParent(editor) { if (!slateClosure.current) return editor; var parentWithReplace = findParentWith('replace', slateClosure.current); if (parentWithReplace && typeof parentWithReplace.replace === 'function') { parentWithReplace.replace({ plugin: slateClosure.current.name, state: editor.value.toJSON() }); } return editor; } }, onKeyDown: function onKeyDown(e, editor, next) { if ((0, _isHotkey.default)('enter', e) && !editor.value.selection.isExpanded) { // remove text plugin and insert on parent if plugin is empty if ((0, _.isValueEmpty)(editor.value) && slateClosure.current) { var parentWithInsert = findParentWith('insert', slateClosure.current); if (parentWithInsert) { e.preventDefault(); setTimeout(function () { if (!slateClosure.current) return next(); var remove = slateClosure.current.remove; if (typeof remove === 'function' && typeof parentWithInsert.insert === 'function') { parentWithInsert.insert({ plugin: slateClosure.current.name }); remove(); } }); return; } } // remove block and insert plugin on parent, if block is empty if (editor.value.startText.text === '' && editor.value.startBlock.nodes.size === 1 && slateClosure.current) { var _parentWithInsert = findParentWith('insert', slateClosure.current); if (_parentWithInsert) { e.preventDefault(); if (!slateClosure.current) return next(); if (typeof _parentWithInsert.insert === 'function') { editor.delete(); _parentWithInsert.insert({ plugin: slateClosure.current.name }); } return; } } if (slateClosure.current && typeof slateClosure.current.insert === 'function') { e.preventDefault(); var nextSlateState = splitBlockAtSelection(editor); setTimeout(function () { if (!slateClosure.current) return next(); var insert = slateClosure.current.insert; if (typeof insert !== 'function') return; insert({ plugin: slateClosure.current.name, state: nextSlateState }); }); return; } } return next(); } }; } // search recursively for a parent with the required function function findParentWith(funcQuery, closure) { if (!closure.parent) return; if (typeof closure.parent[funcQuery] === 'function') return closure.parent; return findParentWith(funcQuery, closure.parent); } function splitBlockAtSelection(editor) { if (editor.value.focusBlock.type == _katex.katexBlockNode) { // If katex block node is focused, don't attempt to split it, insert empty paragraph instead editor.moveToEndOfBlock(); editor.insertBlock('paragraph'); } else { editor.splitBlock(1); } var blocks = editor.value.document.getBlocks(); var afterSelected = blocks.skipUntil(function (block) { if (!block) { return false; } return editor.value.blocks.first().key === block.key; }); afterSelected.forEach(function (block) { if (!block) return; editor.removeNodeByKey(block.key); }); return { document: { nodes: _toConsumableArray(afterSelected.map(function (block) { return block && block.toJSON(); }).toJS()) } }; } // TEMPORARY // Testbed for integration of slate fix // polyfilling slate editor function patchSlateInsertFragment(reacteditor) { // @ts-ignore var editor = reacteditor; // @ts-ignore editor.insertFragment = function (fragment) { if (!fragment.nodes.size) return editor; if (editor.value.selection.isExpanded) { editor.delete(); } var value = editor.value; var _value = value, document = _value.document, selection = _value.selection; var start = selection.start, end = selection.end; var _value2 = value, startText = _value2.startText, endText = _value2.endText, startInline = _value2.startInline; var lastText = fragment.getLastText(); // @ts-ignore var lastInline = fragment.getClosestInline(lastText.key); // @ts-ignore var lastBlock = fragment.getClosestBlock(lastText.key); var firstChild = fragment.nodes.first(); var lastChild = fragment.nodes.last(); // @ts-ignore var keys = document.getTexts().map(function (text) { return text.key; }); var isAppending = !startInline || start.isAtStartOfNode(startText) || end.isAtStartOfNode(startText) || start.isAtEndOfNode(endText) || end.isAtEndOfNode(endText); var isInserting = firstChild.hasBlockChildren() || lastChild.hasBlockChildren(); // @ts-ignore editor.insertFragmentAtRange(selection, fragment); value = editor.value; document = value.document; // @ts-ignore var newTexts = document.getTexts().filter(function (n) { return !keys.includes(n.key); }); var newText = isAppending ? newTexts.last() : newTexts.takeLast(2).first(); if (newText && (lastInline || isInserting)) { editor.moveToEndOfNode(newText); } else if (newText && lastBlock) { // Changed code var lastInlineIndex = lastBlock.nodes.findLastIndex(function (node) { if (!node) return false; return node.object == 'inline'; }); var skipLength = lastBlock.nodes.takeLast(lastBlock.nodes.size - lastInlineIndex - 1).reduce(function (num, v) { if (!num) num = 0; if (v) return num + v.text.length; return num; }, 0); editor.moveToStartOfNode(newText).moveForward(skipLength); } return editor; }; } //# sourceMappingURL=editor.js.map