@edtr-io/plugin-text
Version:
529 lines (433 loc) • 17.9 kB
JavaScript
;
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