UNPKG

165 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5var React = require('react');
6var slate = require('slate');
7var getDirection = require('direction');
8var debounce = require('lodash/debounce');
9var throttle = require('lodash/throttle');
10var scrollIntoView = require('scroll-into-view-if-needed');
11var isHotkey = require('is-hotkey');
12var ReactDOM = require('react-dom');
13
14function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
15
16var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
17var getDirection__default = /*#__PURE__*/_interopDefaultLegacy(getDirection);
18var debounce__default = /*#__PURE__*/_interopDefaultLegacy(debounce);
19var throttle__default = /*#__PURE__*/_interopDefaultLegacy(throttle);
20var scrollIntoView__default = /*#__PURE__*/_interopDefaultLegacy(scrollIntoView);
21var ReactDOM__default = /*#__PURE__*/_interopDefaultLegacy(ReactDOM);
22
23function unwrapExports (x) {
24 return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
25}
26
27function createCommonjsModule(fn, module) {
28 return module = { exports: {} }, fn(module, module.exports), module.exports;
29}
30
31var defineProperty = createCommonjsModule(function (module) {
32function _defineProperty(obj, key, value) {
33 if (key in obj) {
34 Object.defineProperty(obj, key, {
35 value: value,
36 enumerable: true,
37 configurable: true,
38 writable: true
39 });
40 } else {
41 obj[key] = value;
42 }
43
44 return obj;
45}
46
47module.exports = _defineProperty;
48module.exports["default"] = module.exports, module.exports.__esModule = true;
49});
50
51var _defineProperty = unwrapExports(defineProperty);
52
53var arrayWithHoles = createCommonjsModule(function (module) {
54function _arrayWithHoles(arr) {
55 if (Array.isArray(arr)) return arr;
56}
57
58module.exports = _arrayWithHoles;
59module.exports["default"] = module.exports, module.exports.__esModule = true;
60});
61
62unwrapExports(arrayWithHoles);
63
64var iterableToArrayLimit = createCommonjsModule(function (module) {
65function _iterableToArrayLimit(arr, i) {
66 var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
67
68 if (_i == null) return;
69 var _arr = [];
70 var _n = true;
71 var _d = false;
72
73 var _s, _e;
74
75 try {
76 for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {
77 _arr.push(_s.value);
78
79 if (i && _arr.length === i) break;
80 }
81 } catch (err) {
82 _d = true;
83 _e = err;
84 } finally {
85 try {
86 if (!_n && _i["return"] != null) _i["return"]();
87 } finally {
88 if (_d) throw _e;
89 }
90 }
91
92 return _arr;
93}
94
95module.exports = _iterableToArrayLimit;
96module.exports["default"] = module.exports, module.exports.__esModule = true;
97});
98
99unwrapExports(iterableToArrayLimit);
100
101var arrayLikeToArray = createCommonjsModule(function (module) {
102function _arrayLikeToArray(arr, len) {
103 if (len == null || len > arr.length) len = arr.length;
104
105 for (var i = 0, arr2 = new Array(len); i < len; i++) {
106 arr2[i] = arr[i];
107 }
108
109 return arr2;
110}
111
112module.exports = _arrayLikeToArray;
113module.exports["default"] = module.exports, module.exports.__esModule = true;
114});
115
116unwrapExports(arrayLikeToArray);
117
118var unsupportedIterableToArray = createCommonjsModule(function (module) {
119function _unsupportedIterableToArray(o, minLen) {
120 if (!o) return;
121 if (typeof o === "string") return arrayLikeToArray(o, minLen);
122 var n = Object.prototype.toString.call(o).slice(8, -1);
123 if (n === "Object" && o.constructor) n = o.constructor.name;
124 if (n === "Map" || n === "Set") return Array.from(o);
125 if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return arrayLikeToArray(o, minLen);
126}
127
128module.exports = _unsupportedIterableToArray;
129module.exports["default"] = module.exports, module.exports.__esModule = true;
130});
131
132unwrapExports(unsupportedIterableToArray);
133
134var nonIterableRest = createCommonjsModule(function (module) {
135function _nonIterableRest() {
136 throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
137}
138
139module.exports = _nonIterableRest;
140module.exports["default"] = module.exports, module.exports.__esModule = true;
141});
142
143unwrapExports(nonIterableRest);
144
145var slicedToArray = createCommonjsModule(function (module) {
146function _slicedToArray(arr, i) {
147 return arrayWithHoles(arr) || iterableToArrayLimit(arr, i) || unsupportedIterableToArray(arr, i) || nonIterableRest();
148}
149
150module.exports = _slicedToArray;
151module.exports["default"] = module.exports, module.exports.__esModule = true;
152});
153
154var _slicedToArray = unwrapExports(slicedToArray);
155
156var objectWithoutPropertiesLoose = createCommonjsModule(function (module) {
157function _objectWithoutPropertiesLoose(source, excluded) {
158 if (source == null) return {};
159 var target = {};
160 var sourceKeys = Object.keys(source);
161 var key, i;
162
163 for (i = 0; i < sourceKeys.length; i++) {
164 key = sourceKeys[i];
165 if (excluded.indexOf(key) >= 0) continue;
166 target[key] = source[key];
167 }
168
169 return target;
170}
171
172module.exports = _objectWithoutPropertiesLoose;
173module.exports["default"] = module.exports, module.exports.__esModule = true;
174});
175
176unwrapExports(objectWithoutPropertiesLoose);
177
178var objectWithoutProperties = createCommonjsModule(function (module) {
179function _objectWithoutProperties(source, excluded) {
180 if (source == null) return {};
181 var target = objectWithoutPropertiesLoose(source, excluded);
182 var key, i;
183
184 if (Object.getOwnPropertySymbols) {
185 var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
186
187 for (i = 0; i < sourceSymbolKeys.length; i++) {
188 key = sourceSymbolKeys[i];
189 if (excluded.indexOf(key) >= 0) continue;
190 if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
191 target[key] = source[key];
192 }
193 }
194
195 return target;
196}
197
198module.exports = _objectWithoutProperties;
199module.exports["default"] = module.exports, module.exports.__esModule = true;
200});
201
202var _objectWithoutProperties = unwrapExports(objectWithoutProperties);
203
204var IS_IOS = typeof navigator !== 'undefined' && typeof window !== 'undefined' && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
205var IS_APPLE = typeof navigator !== 'undefined' && /Mac OS X/.test(navigator.userAgent);
206var IS_ANDROID = typeof navigator !== 'undefined' && /Android/.test(navigator.userAgent);
207var IS_FIREFOX = typeof navigator !== 'undefined' && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent);
208var IS_SAFARI = typeof navigator !== 'undefined' && /Version\/[\d\.]+.*Safari/.test(navigator.userAgent); // "modern" Edge was released at 79.x
209
210var IS_EDGE_LEGACY = typeof navigator !== 'undefined' && /Edge?\/(?:[0-6][0-9]|[0-7][0-8])/i.test(navigator.userAgent);
211var IS_CHROME = typeof navigator !== 'undefined' && /Chrome/i.test(navigator.userAgent); // Native `beforeInput` events don't work well with react on Chrome 75
212// and older, Chrome 76+ can use `beforeInput` though.
213
214var IS_CHROME_LEGACY = typeof navigator !== 'undefined' && /Chrome?\/(?:[0-7][0-5]|[0-6][0-9])/i.test(navigator.userAgent); // Firefox did not support `beforeInput` until `v87`.
215
216var IS_FIREFOX_LEGACY = typeof navigator !== 'undefined' && /^(?!.*Seamonkey)(?=.*Firefox\/(?:[0-7][0-9]|[0-8][0-6])).*/i.test(navigator.userAgent); // qq browser
217
218var IS_QQBROWSER = typeof navigator !== 'undefined' && /.*QQBrowser/.test(navigator.userAgent); // UC mobile browser
219
220var IS_UC_MOBILE = typeof navigator !== 'undefined' && /.*UCBrowser/.test(navigator.userAgent); // Wechat browser
221
222var IS_WECHATBROWSER = typeof navigator !== 'undefined' && /.*Wechat/.test(navigator.userAgent); // Check if DOM is available as React does internally.
223// https://github.com/facebook/react/blob/master/packages/shared/ExecutionEnvironment.js
224
225var CAN_USE_DOM = !!(typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined'); // COMPAT: Firefox/Edge Legacy don't support the `beforeinput` event
226// Chrome Legacy doesn't support `beforeinput` correctly
227
228var HAS_BEFORE_INPUT_SUPPORT = !IS_CHROME_LEGACY && !IS_EDGE_LEGACY && // globalThis is undefined in older browsers
229typeof globalThis !== 'undefined' && globalThis.InputEvent && // @ts-ignore The `getTargetRanges` property isn't recognized.
230typeof globalThis.InputEvent.prototype.getTargetRanges === 'function';
231
232/**
233 * Prevent warning on SSR by falling back to useEffect when DOM isn't available
234 */
235
236var useIsomorphicLayoutEffect = CAN_USE_DOM ? React.useLayoutEffect : React.useEffect;
237
238/**
239 * Leaf content strings.
240 */
241
242var String = function String(props) {
243 var isLast = props.isLast,
244 leaf = props.leaf,
245 parent = props.parent,
246 text = props.text;
247 var editor = useSlateStatic();
248 var path = ReactEditor.findPath(editor, text);
249 var parentPath = slate.Path.parent(path); // COMPAT: Render text inside void nodes with a zero-width space.
250 // So the node can contain selection but the text is not visible.
251
252 if (editor.isVoid(parent)) {
253 return /*#__PURE__*/React__default['default'].createElement(ZeroWidthString, {
254 length: slate.Node.string(parent).length
255 });
256 } // COMPAT: If this is the last text node in an empty block, render a zero-
257 // width space that will convert into a line break when copying and pasting
258 // to support expected plain text.
259
260
261 if (leaf.text === '' && parent.children[parent.children.length - 1] === text && !editor.isInline(parent) && slate.Editor.string(editor, parentPath) === '') {
262 return /*#__PURE__*/React__default['default'].createElement(ZeroWidthString, {
263 isLineBreak: true
264 });
265 } // COMPAT: If the text is empty, it's because it's on the edge of an inline
266 // node, so we render a zero-width space so that the selection can be
267 // inserted next to it still.
268
269
270 if (leaf.text === '') {
271 return /*#__PURE__*/React__default['default'].createElement(ZeroWidthString, null);
272 } // COMPAT: Browsers will collapse trailing new lines at the end of blocks,
273 // so we need to add an extra trailing new lines to prevent that.
274
275
276 if (isLast && leaf.text.slice(-1) === '\n') {
277 return /*#__PURE__*/React__default['default'].createElement(TextString, {
278 isTrailing: true,
279 text: leaf.text
280 });
281 }
282
283 return /*#__PURE__*/React__default['default'].createElement(TextString, {
284 text: leaf.text
285 });
286};
287/**
288 * Leaf strings with text in them.
289 */
290
291
292var TextString = function TextString(props) {
293 var text = props.text,
294 _props$isTrailing = props.isTrailing,
295 isTrailing = _props$isTrailing === void 0 ? false : _props$isTrailing;
296 var ref = React.useRef(null); // This is the actual text rendering boundary where we interface with the DOM
297 // The text is not rendered as part of the virtual DOM, as since we handle basic character insertions natively,
298 // updating the DOM is not a one way dataflow anymore. What we need here is not reconciliation and diffing
299 // with previous version of the virtual DOM, but rather diffing with the actual DOM element, and replace the DOM <span> content
300 // exactly if and only if its current content does not match our current virtual DOM.
301 // Otherwise the DOM TextNode would always be replaced by React as the user types, which interferes with native text features,
302 // eg makes native spellcheck opt out from checking the text node.
303 // useLayoutEffect: updating our span before browser paint
304
305 useIsomorphicLayoutEffect(function () {
306 // null coalescing text to make sure we're not outputing "null" as a string in the extreme case it is nullish at runtime
307 var textWithTrailing = "".concat(text !== null && text !== void 0 ? text : '').concat(isTrailing ? '\n' : '');
308
309 if (ref.current && ref.current.textContent !== textWithTrailing) {
310 ref.current.textContent = textWithTrailing;
311 } // intentionally not specifying dependencies, so that this effect runs on every render
312 // as this effectively replaces "specifying the text in the virtual DOM under the <span> below" on each render
313
314 }); // the span is intentionally same on every render in virtual DOM, actual rendering happens in the layout effect above
315
316 return /*#__PURE__*/React__default['default'].createElement("span", {
317 "data-slate-string": true,
318 ref: ref
319 });
320};
321/**
322 * Leaf strings without text, render as zero-width strings.
323 */
324
325
326var ZeroWidthString = function ZeroWidthString(props) {
327 var _props$length = props.length,
328 length = _props$length === void 0 ? 0 : _props$length,
329 _props$isLineBreak = props.isLineBreak,
330 isLineBreak = _props$isLineBreak === void 0 ? false : _props$isLineBreak;
331 return /*#__PURE__*/React__default['default'].createElement("span", {
332 "data-slate-zero-width": isLineBreak ? 'n' : 'z',
333 "data-slate-length": length
334 }, "\uFEFF", isLineBreak ? /*#__PURE__*/React__default['default'].createElement("br", null) : null);
335};
336
337/**
338 * Two weak maps that allow us rebuild a path given a node. They are populated
339 * at render time such that after a render occurs we can always backtrack.
340 */
341var NODE_TO_INDEX = new WeakMap();
342var NODE_TO_PARENT = new WeakMap();
343/**
344 * Weak maps that allow us to go between Slate nodes and DOM nodes. These
345 * are used to resolve DOM event-related logic into Slate actions.
346 */
347
348var EDITOR_TO_WINDOW = new WeakMap();
349var EDITOR_TO_ELEMENT = new WeakMap();
350var ELEMENT_TO_NODE = new WeakMap();
351var NODE_TO_ELEMENT = new WeakMap();
352var NODE_TO_KEY = new WeakMap();
353var EDITOR_TO_KEY_TO_ELEMENT = new WeakMap();
354/**
355 * Weak maps for storing editor-related state.
356 */
357
358var IS_READ_ONLY = new WeakMap();
359var IS_FOCUSED = new WeakMap();
360var IS_COMPOSING = new WeakMap();
361var IS_ON_COMPOSITION_END = new WeakMap();
362/**
363 * Weak maps for saving text on composition stage.
364 */
365
366var EDITOR_ON_COMPOSITION_TEXT = new WeakMap();
367/**
368 * Weak map for associating the context `onChange` context with the plugin.
369 */
370
371var EDITOR_TO_ON_CHANGE = new WeakMap();
372var NODE_TO_RESTORE_DOM = new WeakMap();
373/**
374 * Symbols.
375 */
376
377var PLACEHOLDER_SYMBOL = Symbol('placeholder');
378
379/**
380 * Individual leaves in a text node with unique formatting.
381 */
382
383var Leaf = function Leaf(props) {
384 var leaf = props.leaf,
385 isLast = props.isLast,
386 text = props.text,
387 parent = props.parent,
388 renderPlaceholder = props.renderPlaceholder,
389 _props$renderLeaf = props.renderLeaf,
390 renderLeaf = _props$renderLeaf === void 0 ? function (props) {
391 return /*#__PURE__*/React__default['default'].createElement(DefaultLeaf, Object.assign({}, props));
392 } : _props$renderLeaf;
393 var placeholderRef = React.useRef(null);
394 React.useEffect(function () {
395 var placeholderEl = placeholderRef === null || placeholderRef === void 0 ? void 0 : placeholderRef.current;
396 var editorEl = document.querySelector('[data-slate-editor="true"]');
397
398 if (!placeholderEl || !editorEl) {
399 return;
400 }
401
402 editorEl.style.minHeight = "".concat(placeholderEl.clientHeight, "px");
403 return function () {
404 editorEl.style.minHeight = 'auto';
405 };
406 }, [placeholderRef, leaf]);
407 var children = /*#__PURE__*/React__default['default'].createElement(String, {
408 isLast: isLast,
409 leaf: leaf,
410 parent: parent,
411 text: text
412 });
413
414 if (leaf[PLACEHOLDER_SYMBOL]) {
415 var placeholderProps = {
416 children: leaf.placeholder,
417 attributes: {
418 'data-slate-placeholder': true,
419 style: {
420 position: 'absolute',
421 pointerEvents: 'none',
422 width: '100%',
423 maxWidth: '100%',
424 display: 'block',
425 opacity: '0.333',
426 userSelect: 'none',
427 textDecoration: 'none'
428 },
429 contentEditable: false,
430 ref: placeholderRef
431 }
432 };
433 children = /*#__PURE__*/React__default['default'].createElement(React__default['default'].Fragment, null, renderPlaceholder(placeholderProps), children);
434 } // COMPAT: Having the `data-` attributes on these leaf elements ensures that
435 // in certain misbehaving browsers they aren't weirdly cloned/destroyed by
436 // contenteditable behaviors. (2019/05/08)
437
438
439 var attributes = {
440 'data-slate-leaf': true
441 };
442 return renderLeaf({
443 attributes: attributes,
444 children: children,
445 leaf: leaf,
446 text: text
447 });
448};
449
450var MemoizedLeaf = /*#__PURE__*/React__default['default'].memo(Leaf, function (prev, next) {
451 return next.parent === prev.parent && next.isLast === prev.isLast && next.renderLeaf === prev.renderLeaf && next.renderPlaceholder === prev.renderPlaceholder && next.text === prev.text && slate.Text.equals(next.leaf, prev.leaf) && next.leaf[PLACEHOLDER_SYMBOL] === prev.leaf[PLACEHOLDER_SYMBOL];
452});
453var DefaultLeaf = function DefaultLeaf(props) {
454 var attributes = props.attributes,
455 children = props.children;
456 return /*#__PURE__*/React__default['default'].createElement("span", Object.assign({}, attributes), children);
457};
458
459var _excluded$3 = ["anchor", "focus"],
460 _excluded2 = ["anchor", "focus"];
461var shallowCompare = function shallowCompare(obj1, obj2) {
462 return Object.keys(obj1).length === Object.keys(obj2).length && Object.keys(obj1).every(function (key) {
463 return obj2.hasOwnProperty(key) && obj1[key] === obj2[key];
464 });
465};
466/**
467 * Check if a list of decorator ranges are equal to another.
468 *
469 * PERF: this requires the two lists to also have the ranges inside them in the
470 * same order, but this is an okay constraint for us since decorations are
471 * kept in order, and the odd case where they aren't is okay to re-render for.
472 */
473
474var isDecoratorRangeListEqual = function isDecoratorRangeListEqual(list, another) {
475 if (list.length !== another.length) {
476 return false;
477 }
478
479 for (var i = 0; i < list.length; i++) {
480 var range = list[i];
481 var other = another[i];
482
483 range.anchor;
484 range.focus;
485 var rangeOwnProps = _objectWithoutProperties(range, _excluded$3);
486
487 other.anchor;
488 other.focus;
489 var otherOwnProps = _objectWithoutProperties(other, _excluded2);
490
491 if (!slate.Range.equals(range, other) || range[PLACEHOLDER_SYMBOL] !== other[PLACEHOLDER_SYMBOL] || !shallowCompare(rangeOwnProps, otherOwnProps)) {
492 return false;
493 }
494 }
495
496 return true;
497};
498
499function useContentKey(node) {
500 var contentKeyRef = React.useRef(0);
501 var updateAnimationFrameRef = React.useRef(null);
502
503 var _useState = React.useState(0),
504 _useState2 = _slicedToArray(_useState, 2),
505 setForceRerenderCounter = _useState2[1];
506
507 React.useEffect(function () {
508 NODE_TO_RESTORE_DOM.set(node, function () {
509 // Update is already queued and node hasn't re-render yet
510 if (updateAnimationFrameRef.current) {
511 return;
512 }
513
514 updateAnimationFrameRef.current = requestAnimationFrame(function () {
515 setForceRerenderCounter(function (state) {
516 return state + 1;
517 });
518 updateAnimationFrameRef.current = null;
519 });
520 contentKeyRef.current++;
521 });
522 return function () {
523 NODE_TO_RESTORE_DOM["delete"](node);
524 };
525 }, [node]); // Node was restored => clear scheduled update
526
527 if (updateAnimationFrameRef.current) {
528 cancelAnimationFrame(updateAnimationFrameRef.current);
529 updateAnimationFrameRef.current = null;
530 }
531
532 return contentKeyRef.current;
533}
534
535/**
536 * Text.
537 */
538
539var Text = function Text(props) {
540 var decorations = props.decorations,
541 isLast = props.isLast,
542 parent = props.parent,
543 renderPlaceholder = props.renderPlaceholder,
544 renderLeaf = props.renderLeaf,
545 text = props.text;
546 var editor = useSlateStatic();
547 var ref = React.useRef(null);
548 var leaves = slate.Text.decorations(text, decorations);
549 var key = ReactEditor.findKey(editor, text);
550 var children = [];
551
552 for (var i = 0; i < leaves.length; i++) {
553 var leaf = leaves[i];
554 children.push( /*#__PURE__*/React__default['default'].createElement(MemoizedLeaf, {
555 isLast: isLast && i === leaves.length - 1,
556 key: "".concat(key.id, "-").concat(i),
557 renderPlaceholder: renderPlaceholder,
558 leaf: leaf,
559 text: text,
560 parent: parent,
561 renderLeaf: renderLeaf
562 }));
563 } // Update element-related weak maps with the DOM element ref.
564
565
566 useIsomorphicLayoutEffect(function () {
567 var KEY_TO_ELEMENT = EDITOR_TO_KEY_TO_ELEMENT.get(editor);
568
569 if (ref.current) {
570 KEY_TO_ELEMENT === null || KEY_TO_ELEMENT === void 0 ? void 0 : KEY_TO_ELEMENT.set(key, ref.current);
571 NODE_TO_ELEMENT.set(text, ref.current);
572 ELEMENT_TO_NODE.set(ref.current, text);
573 } else {
574 KEY_TO_ELEMENT === null || KEY_TO_ELEMENT === void 0 ? void 0 : KEY_TO_ELEMENT["delete"](key);
575 NODE_TO_ELEMENT["delete"](text);
576 }
577 });
578 var contentKey = IS_ANDROID ? useContentKey(text) : undefined;
579 return /*#__PURE__*/React__default['default'].createElement("span", {
580 "data-slate-node": "text",
581 ref: ref,
582 key: contentKey
583 }, children);
584};
585
586var MemoizedText = /*#__PURE__*/React__default['default'].memo(Text, function (prev, next) {
587 return next.parent === prev.parent && next.isLast === prev.isLast && next.renderLeaf === prev.renderLeaf && next.text === prev.text && isDecoratorRangeListEqual(next.decorations, prev.decorations);
588});
589
590/**
591 * Element.
592 */
593
594var Element = function Element(props) {
595 var decorations = props.decorations,
596 element = props.element,
597 _props$renderElement = props.renderElement,
598 renderElement = _props$renderElement === void 0 ? function (p) {
599 return /*#__PURE__*/React__default['default'].createElement(DefaultElement, Object.assign({}, p));
600 } : _props$renderElement,
601 renderPlaceholder = props.renderPlaceholder,
602 renderLeaf = props.renderLeaf,
603 selection = props.selection;
604 var ref = React.useRef(null);
605 var editor = useSlateStatic();
606 var readOnly = useReadOnly();
607 var isInline = editor.isInline(element);
608 var key = ReactEditor.findKey(editor, element);
609 var children = useChildren({
610 decorations: decorations,
611 node: element,
612 renderElement: renderElement,
613 renderPlaceholder: renderPlaceholder,
614 renderLeaf: renderLeaf,
615 selection: selection
616 }); // Attributes that the developer must mix into the element in their
617 // custom node renderer component.
618
619 var attributes = {
620 'data-slate-node': 'element',
621 ref: ref
622 };
623
624 if (isInline) {
625 attributes['data-slate-inline'] = true;
626 } // If it's a block node with inline children, add the proper `dir` attribute
627 // for text direction.
628
629
630 if (!isInline && slate.Editor.hasInlines(editor, element)) {
631 var text = slate.Node.string(element);
632 var dir = getDirection__default['default'](text);
633
634 if (dir === 'rtl') {
635 attributes.dir = dir;
636 }
637 } // If it's a void node, wrap the children in extra void-specific elements.
638
639
640 if (slate.Editor.isVoid(editor, element)) {
641 attributes['data-slate-void'] = true;
642
643 if (!readOnly && isInline) {
644 attributes.contentEditable = false;
645 }
646
647 var Tag = isInline ? 'span' : 'div';
648
649 var _Node$texts = slate.Node.texts(element),
650 _Node$texts2 = _slicedToArray(_Node$texts, 1),
651 _Node$texts2$ = _slicedToArray(_Node$texts2[0], 1),
652 _text = _Node$texts2$[0];
653
654 children = readOnly ? null : /*#__PURE__*/React__default['default'].createElement(Tag, {
655 "data-slate-spacer": true,
656 style: {
657 height: '0',
658 color: 'transparent',
659 outline: 'none',
660 position: 'absolute'
661 }
662 }, /*#__PURE__*/React__default['default'].createElement(MemoizedText, {
663 renderPlaceholder: renderPlaceholder,
664 decorations: [],
665 isLast: false,
666 parent: element,
667 text: _text
668 }));
669 NODE_TO_INDEX.set(_text, 0);
670 NODE_TO_PARENT.set(_text, element);
671 } // Update element-related weak maps with the DOM element ref.
672
673
674 useIsomorphicLayoutEffect(function () {
675 var KEY_TO_ELEMENT = EDITOR_TO_KEY_TO_ELEMENT.get(editor);
676
677 if (ref.current) {
678 KEY_TO_ELEMENT === null || KEY_TO_ELEMENT === void 0 ? void 0 : KEY_TO_ELEMENT.set(key, ref.current);
679 NODE_TO_ELEMENT.set(element, ref.current);
680 ELEMENT_TO_NODE.set(ref.current, element);
681 } else {
682 KEY_TO_ELEMENT === null || KEY_TO_ELEMENT === void 0 ? void 0 : KEY_TO_ELEMENT["delete"](key);
683 NODE_TO_ELEMENT["delete"](element);
684 }
685 });
686 var content = renderElement({
687 attributes: attributes,
688 children: children,
689 element: element
690 });
691
692 if (IS_ANDROID) {
693 var contentKey = useContentKey(element);
694 return /*#__PURE__*/React__default['default'].createElement(React.Fragment, {
695 key: contentKey
696 }, content);
697 }
698
699 return content;
700};
701
702var MemoizedElement = /*#__PURE__*/React__default['default'].memo(Element, function (prev, next) {
703 return prev.element === next.element && prev.renderElement === next.renderElement && prev.renderLeaf === next.renderLeaf && isDecoratorRangeListEqual(prev.decorations, next.decorations) && (prev.selection === next.selection || !!prev.selection && !!next.selection && slate.Range.equals(prev.selection, next.selection));
704});
705/**
706 * The default element renderer.
707 */
708
709var DefaultElement = function DefaultElement(props) {
710 var attributes = props.attributes,
711 children = props.children,
712 element = props.element;
713 var editor = useSlateStatic();
714 var Tag = editor.isInline(element) ? 'span' : 'div';
715 return /*#__PURE__*/React__default['default'].createElement(Tag, Object.assign({}, attributes, {
716 style: {
717 position: 'relative'
718 }
719 }), children);
720};
721
722/**
723 * A React context for sharing the editor object.
724 */
725
726var EditorContext = /*#__PURE__*/React.createContext(null);
727/**
728 * Get the current editor object from the React context.
729 */
730
731var useSlateStatic = function useSlateStatic() {
732 var editor = React.useContext(EditorContext);
733
734 if (!editor) {
735 throw new Error("The `useSlateStatic` hook must be used inside the <Slate> component's context.");
736 }
737
738 return editor;
739};
740
741/**
742 * A React context for sharing the `decorate` prop of the editable.
743 */
744
745var DecorateContext = /*#__PURE__*/React.createContext(function () {
746 return [];
747});
748/**
749 * Get the current `decorate` prop of the editable.
750 */
751
752var useDecorate = function useDecorate() {
753 return React.useContext(DecorateContext);
754};
755
756/**
757 * A React context for sharing the `selected` state of an element.
758 */
759
760var SelectedContext = /*#__PURE__*/React.createContext(false);
761/**
762 * Get the current `selected` state of an element.
763 */
764
765var useSelected = function useSelected() {
766 return React.useContext(SelectedContext);
767};
768
769function _createForOfIteratorHelper$3(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray$3(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
770
771function _unsupportedIterableToArray$3(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray$3(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$3(o, minLen); }
772
773function _arrayLikeToArray$3(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
774/**
775 * Children.
776 */
777
778var useChildren = function useChildren(props) {
779 var decorations = props.decorations,
780 node = props.node,
781 renderElement = props.renderElement,
782 renderPlaceholder = props.renderPlaceholder,
783 renderLeaf = props.renderLeaf,
784 selection = props.selection;
785 var decorate = useDecorate();
786 var editor = useSlateStatic();
787 var path = ReactEditor.findPath(editor, node);
788 var children = [];
789 var isLeafBlock = slate.Element.isElement(node) && !editor.isInline(node) && slate.Editor.hasInlines(editor, node);
790
791 for (var i = 0; i < node.children.length; i++) {
792 var p = path.concat(i);
793 var n = node.children[i];
794 var key = ReactEditor.findKey(editor, n);
795 var range = slate.Editor.range(editor, p);
796 var sel = selection && slate.Range.intersection(range, selection);
797 var ds = decorate([n, p]);
798
799 var _iterator = _createForOfIteratorHelper$3(decorations),
800 _step;
801
802 try {
803 for (_iterator.s(); !(_step = _iterator.n()).done;) {
804 var dec = _step.value;
805 var d = slate.Range.intersection(dec, range);
806
807 if (d) {
808 ds.push(d);
809 }
810 }
811 } catch (err) {
812 _iterator.e(err);
813 } finally {
814 _iterator.f();
815 }
816
817 if (slate.Element.isElement(n)) {
818 children.push( /*#__PURE__*/React__default['default'].createElement(SelectedContext.Provider, {
819 key: "provider-".concat(key.id),
820 value: !!sel
821 }, /*#__PURE__*/React__default['default'].createElement(MemoizedElement, {
822 decorations: ds,
823 element: n,
824 key: key.id,
825 renderElement: renderElement,
826 renderPlaceholder: renderPlaceholder,
827 renderLeaf: renderLeaf,
828 selection: sel
829 })));
830 } else {
831 children.push( /*#__PURE__*/React__default['default'].createElement(MemoizedText, {
832 decorations: ds,
833 key: key.id,
834 isLast: isLeafBlock && i === node.children.length - 1,
835 parent: node,
836 renderPlaceholder: renderPlaceholder,
837 renderLeaf: renderLeaf,
838 text: n
839 }));
840 }
841
842 NODE_TO_INDEX.set(n, i);
843 NODE_TO_PARENT.set(n, node);
844 }
845
846 return children;
847};
848
849/**
850 * Hotkey mappings for each platform.
851 */
852
853var HOTKEYS = {
854 bold: 'mod+b',
855 compose: ['down', 'left', 'right', 'up', 'backspace', 'enter'],
856 moveBackward: 'left',
857 moveForward: 'right',
858 moveWordBackward: 'ctrl+left',
859 moveWordForward: 'ctrl+right',
860 deleteBackward: 'shift?+backspace',
861 deleteForward: 'shift?+delete',
862 extendBackward: 'shift+left',
863 extendForward: 'shift+right',
864 italic: 'mod+i',
865 splitBlock: 'shift?+enter',
866 undo: 'mod+z'
867};
868var APPLE_HOTKEYS = {
869 moveLineBackward: 'opt+up',
870 moveLineForward: 'opt+down',
871 moveWordBackward: 'opt+left',
872 moveWordForward: 'opt+right',
873 deleteBackward: ['ctrl+backspace', 'ctrl+h'],
874 deleteForward: ['ctrl+delete', 'ctrl+d'],
875 deleteLineBackward: 'cmd+shift?+backspace',
876 deleteLineForward: ['cmd+shift?+delete', 'ctrl+k'],
877 deleteWordBackward: 'opt+shift?+backspace',
878 deleteWordForward: 'opt+shift?+delete',
879 extendLineBackward: 'opt+shift+up',
880 extendLineForward: 'opt+shift+down',
881 redo: 'cmd+shift+z',
882 transposeCharacter: 'ctrl+t'
883};
884var WINDOWS_HOTKEYS = {
885 deleteWordBackward: 'ctrl+shift?+backspace',
886 deleteWordForward: 'ctrl+shift?+delete',
887 redo: ['ctrl+y', 'ctrl+shift+z']
888};
889/**
890 * Create a platform-aware hotkey checker.
891 */
892
893var create = function create(key) {
894 var generic = HOTKEYS[key];
895 var apple = APPLE_HOTKEYS[key];
896 var windows = WINDOWS_HOTKEYS[key];
897 var isGeneric = generic && isHotkey.isKeyHotkey(generic);
898 var isApple = apple && isHotkey.isKeyHotkey(apple);
899 var isWindows = windows && isHotkey.isKeyHotkey(windows);
900 return function (event) {
901 if (isGeneric && isGeneric(event)) return true;
902 if (IS_APPLE && isApple && isApple(event)) return true;
903 if (!IS_APPLE && isWindows && isWindows(event)) return true;
904 return false;
905 };
906};
907/**
908 * Hotkeys.
909 */
910
911
912var Hotkeys = {
913 isBold: create('bold'),
914 isCompose: create('compose'),
915 isMoveBackward: create('moveBackward'),
916 isMoveForward: create('moveForward'),
917 isDeleteBackward: create('deleteBackward'),
918 isDeleteForward: create('deleteForward'),
919 isDeleteLineBackward: create('deleteLineBackward'),
920 isDeleteLineForward: create('deleteLineForward'),
921 isDeleteWordBackward: create('deleteWordBackward'),
922 isDeleteWordForward: create('deleteWordForward'),
923 isExtendBackward: create('extendBackward'),
924 isExtendForward: create('extendForward'),
925 isExtendLineBackward: create('extendLineBackward'),
926 isExtendLineForward: create('extendLineForward'),
927 isItalic: create('italic'),
928 isMoveLineBackward: create('moveLineBackward'),
929 isMoveLineForward: create('moveLineForward'),
930 isMoveWordBackward: create('moveWordBackward'),
931 isMoveWordForward: create('moveWordForward'),
932 isRedo: create('redo'),
933 isSplitBlock: create('splitBlock'),
934 isTransposeCharacter: create('transposeCharacter'),
935 isUndo: create('undo')
936};
937
938/**
939 * A React context for sharing the `readOnly` state of the editor.
940 */
941
942var ReadOnlyContext = /*#__PURE__*/React.createContext(false);
943/**
944 * Get the current `readOnly` state of the editor.
945 */
946
947var useReadOnly = function useReadOnly() {
948 return React.useContext(ReadOnlyContext);
949};
950
951/**
952 * A React context for sharing the editor object, in a way that re-renders the
953 * context whenever changes occur.
954 */
955
956var SlateContext = /*#__PURE__*/React.createContext(null);
957/**
958 * Get the current editor object from the React context.
959 */
960
961var useSlate = function useSlate() {
962 var context = React.useContext(SlateContext);
963
964 if (!context) {
965 throw new Error("The `useSlate` hook must be used inside the <Slate> component's context.");
966 }
967
968 var _context = _slicedToArray(context, 1),
969 editor = _context[0];
970
971 return editor;
972};
973
974/**
975 * Returns the host window of a DOM node
976 */
977
978var getDefaultView = function getDefaultView(value) {
979 return value && value.ownerDocument && value.ownerDocument.defaultView || null;
980};
981/**
982 * Check if a DOM node is a comment node.
983 */
984
985var isDOMComment = function isDOMComment(value) {
986 return isDOMNode(value) && value.nodeType === 8;
987};
988/**
989 * Check if a DOM node is an element node.
990 */
991
992var isDOMElement = function isDOMElement(value) {
993 return isDOMNode(value) && value.nodeType === 1;
994};
995/**
996 * Check if a value is a DOM node.
997 */
998
999var isDOMNode = function isDOMNode(value) {
1000 var window = getDefaultView(value);
1001 return !!window && value instanceof window.Node;
1002};
1003/**
1004 * Check if a value is a DOM selection.
1005 */
1006
1007var isDOMSelection = function isDOMSelection(value) {
1008 var window = value && value.anchorNode && getDefaultView(value.anchorNode);
1009 return !!window && value instanceof window.Selection;
1010};
1011/**
1012 * Check if a DOM node is an element node.
1013 */
1014
1015var isDOMText = function isDOMText(value) {
1016 return isDOMNode(value) && value.nodeType === 3;
1017};
1018/**
1019 * Checks whether a paste event is a plaintext-only event.
1020 */
1021
1022var isPlainTextOnlyPaste = function isPlainTextOnlyPaste(event) {
1023 return event.clipboardData && event.clipboardData.getData('text/plain') !== '' && event.clipboardData.types.length === 1;
1024};
1025/**
1026 * Normalize a DOM point so that it always refers to a text node.
1027 */
1028
1029var normalizeDOMPoint = function normalizeDOMPoint(domPoint) {
1030 var _domPoint = _slicedToArray(domPoint, 2),
1031 node = _domPoint[0],
1032 offset = _domPoint[1]; // If it's an element node, its offset refers to the index of its children
1033 // including comment nodes, so try to find the right text child node.
1034
1035
1036 if (isDOMElement(node) && node.childNodes.length) {
1037 var isLast = offset === node.childNodes.length;
1038 var index = isLast ? offset - 1 : offset;
1039
1040 var _getEditableChildAndI = getEditableChildAndIndex(node, index, isLast ? 'backward' : 'forward');
1041
1042 var _getEditableChildAndI2 = _slicedToArray(_getEditableChildAndI, 2);
1043
1044 node = _getEditableChildAndI2[0];
1045 index = _getEditableChildAndI2[1];
1046 // If the editable child found is in front of input offset, we instead seek to its end
1047 isLast = index < offset; // If the node has children, traverse until we have a leaf node. Leaf nodes
1048 // can be either text nodes, or other void DOM nodes.
1049
1050 while (isDOMElement(node) && node.childNodes.length) {
1051 var i = isLast ? node.childNodes.length - 1 : 0;
1052 node = getEditableChild(node, i, isLast ? 'backward' : 'forward');
1053 } // Determine the new offset inside the text node.
1054
1055
1056 offset = isLast && node.textContent != null ? node.textContent.length : 0;
1057 } // Return the node and offset.
1058
1059
1060 return [node, offset];
1061};
1062/**
1063 * Determines wether the active element is nested within a shadowRoot
1064 */
1065
1066var hasShadowRoot = function hasShadowRoot() {
1067 return !!(window.document.activeElement && window.document.activeElement.shadowRoot);
1068};
1069/**
1070 * Get the nearest editable child and index at `index` in a `parent`, preferring
1071 * `direction`.
1072 */
1073
1074var getEditableChildAndIndex = function getEditableChildAndIndex(parent, index, direction) {
1075 var childNodes = parent.childNodes;
1076 var child = childNodes[index];
1077 var i = index;
1078 var triedForward = false;
1079 var triedBackward = false; // While the child is a comment node, or an element node with no children,
1080 // keep iterating to find a sibling non-void, non-comment node.
1081
1082 while (isDOMComment(child) || isDOMElement(child) && child.childNodes.length === 0 || isDOMElement(child) && child.getAttribute('contenteditable') === 'false') {
1083 if (triedForward && triedBackward) {
1084 break;
1085 }
1086
1087 if (i >= childNodes.length) {
1088 triedForward = true;
1089 i = index - 1;
1090 direction = 'backward';
1091 continue;
1092 }
1093
1094 if (i < 0) {
1095 triedBackward = true;
1096 i = index + 1;
1097 direction = 'forward';
1098 continue;
1099 }
1100
1101 child = childNodes[i];
1102 index = i;
1103 i += direction === 'forward' ? 1 : -1;
1104 }
1105
1106 return [child, index];
1107};
1108/**
1109 * Get the nearest editable child at `index` in a `parent`, preferring
1110 * `direction`.
1111 */
1112
1113var getEditableChild = function getEditableChild(parent, index, direction) {
1114 var _getEditableChildAndI3 = getEditableChildAndIndex(parent, index, direction),
1115 _getEditableChildAndI4 = _slicedToArray(_getEditableChildAndI3, 1),
1116 child = _getEditableChildAndI4[0];
1117
1118 return child;
1119};
1120/**
1121 * Get a plaintext representation of the content of a node, accounting for block
1122 * elements which get a newline appended.
1123 *
1124 * The domNode must be attached to the DOM.
1125 */
1126
1127var getPlainText = function getPlainText(domNode) {
1128 var text = '';
1129
1130 if (isDOMText(domNode) && domNode.nodeValue) {
1131 return domNode.nodeValue;
1132 }
1133
1134 if (isDOMElement(domNode)) {
1135 for (var _i = 0, _Array$from = Array.from(domNode.childNodes); _i < _Array$from.length; _i++) {
1136 var childNode = _Array$from[_i];
1137 text += getPlainText(childNode);
1138 }
1139
1140 var display = getComputedStyle(domNode).getPropertyValue('display');
1141
1142 if (display === 'block' || display === 'list' || domNode.tagName === 'BR') {
1143 text += '\n';
1144 }
1145 }
1146
1147 return text;
1148};
1149/**
1150 * Get x-slate-fragment attribute from data-slate-fragment
1151 */
1152
1153var catchSlateFragment = /data-slate-fragment="(.+?)"/m;
1154var getSlateFragmentAttribute = function getSlateFragmentAttribute(dataTransfer) {
1155 var htmlData = dataTransfer.getData('text/html');
1156
1157 var _ref = htmlData.match(catchSlateFragment) || [],
1158 _ref2 = _slicedToArray(_ref, 2),
1159 fragment = _ref2[1];
1160
1161 return fragment;
1162};
1163/**
1164 * Get the x-slate-fragment attribute that exist in text/html data
1165 * and append it to the DataTransfer object
1166 */
1167
1168var getClipboardData = function getClipboardData(dataTransfer) {
1169 if (!dataTransfer.getData('application/x-slate-fragment')) {
1170 var fragment = getSlateFragmentAttribute(dataTransfer);
1171
1172 if (fragment) {
1173 var clipboardData = new DataTransfer();
1174 dataTransfer.types.forEach(function (type) {
1175 clipboardData.setData(type, dataTransfer.getData(type));
1176 });
1177 clipboardData.setData('application/x-slate-fragment', fragment);
1178 return clipboardData;
1179 }
1180 }
1181
1182 return dataTransfer;
1183};
1184
1185var _excluded$2 = ["autoFocus", "decorate", "onDOMBeforeInput", "placeholder", "readOnly", "renderElement", "renderLeaf", "renderPlaceholder", "scrollSelectionIntoView", "style", "as"];
1186
1187function _createForOfIteratorHelper$2(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray$2(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
1188
1189function _unsupportedIterableToArray$2(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray$2(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$2(o, minLen); }
1190
1191function _arrayLikeToArray$2(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
1192
1193function ownKeys$1(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
1194
1195function _objectSpread$1(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$1(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$1(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
1196
1197var Children = function Children(props) {
1198 return /*#__PURE__*/React__default['default'].createElement(React__default['default'].Fragment, null, useChildren(props));
1199};
1200/**
1201 * Editable.
1202 */
1203
1204
1205var Editable$1 = function Editable(props) {
1206 var autoFocus = props.autoFocus,
1207 _props$decorate = props.decorate,
1208 decorate = _props$decorate === void 0 ? defaultDecorate : _props$decorate,
1209 propsOnDOMBeforeInput = props.onDOMBeforeInput,
1210 placeholder = props.placeholder,
1211 _props$readOnly = props.readOnly,
1212 readOnly = _props$readOnly === void 0 ? false : _props$readOnly,
1213 renderElement = props.renderElement,
1214 renderLeaf = props.renderLeaf,
1215 _props$renderPlacehol = props.renderPlaceholder,
1216 renderPlaceholder = _props$renderPlacehol === void 0 ? function (props) {
1217 return /*#__PURE__*/React__default['default'].createElement(DefaultPlaceholder, Object.assign({}, props));
1218 } : _props$renderPlacehol,
1219 _props$scrollSelectio = props.scrollSelectionIntoView,
1220 scrollSelectionIntoView = _props$scrollSelectio === void 0 ? defaultScrollSelectionIntoView : _props$scrollSelectio,
1221 _props$style = props.style,
1222 style = _props$style === void 0 ? {} : _props$style,
1223 _props$as = props.as,
1224 Component = _props$as === void 0 ? 'div' : _props$as,
1225 attributes = _objectWithoutProperties(props, _excluded$2);
1226
1227 var editor = useSlate(); // Rerender editor when composition status changed
1228
1229 var _useState = React.useState(false),
1230 _useState2 = _slicedToArray(_useState, 2),
1231 isComposing = _useState2[0],
1232 setIsComposing = _useState2[1];
1233
1234 var ref = React.useRef(null);
1235 var deferredOperations = React.useRef([]); // Update internal state on each render.
1236
1237 IS_READ_ONLY.set(editor, readOnly); // Keep track of some state for the event handler logic.
1238
1239 var state = React.useMemo(function () {
1240 return {
1241 isComposing: false,
1242 hasInsertPrefixInCompositon: false,
1243 isDraggingInternally: false,
1244 isUpdatingSelection: false,
1245 latestElement: null
1246 };
1247 }, []); // Whenever the editor updates...
1248
1249 useIsomorphicLayoutEffect(function () {
1250 // Update element-related weak maps with the DOM element ref.
1251 var window;
1252
1253 if (ref.current && (window = getDefaultView(ref.current))) {
1254 EDITOR_TO_WINDOW.set(editor, window);
1255 EDITOR_TO_ELEMENT.set(editor, ref.current);
1256 NODE_TO_ELEMENT.set(editor, ref.current);
1257 ELEMENT_TO_NODE.set(ref.current, editor);
1258 } else {
1259 NODE_TO_ELEMENT["delete"](editor);
1260 } // Make sure the DOM selection state is in sync.
1261
1262
1263 var selection = editor.selection;
1264 var root = ReactEditor.findDocumentOrShadowRoot(editor);
1265 var domSelection = root.getSelection();
1266
1267 if (state.isComposing || !domSelection || !ReactEditor.isFocused(editor)) {
1268 return;
1269 }
1270
1271 var hasDomSelection = domSelection.type !== 'None'; // If the DOM selection is properly unset, we're done.
1272
1273 if (!selection && !hasDomSelection) {
1274 return;
1275 } // verify that the dom selection is in the editor
1276
1277
1278 var editorElement = EDITOR_TO_ELEMENT.get(editor);
1279 var hasDomSelectionInEditor = false;
1280
1281 if (editorElement.contains(domSelection.anchorNode) && editorElement.contains(domSelection.focusNode)) {
1282 hasDomSelectionInEditor = true;
1283 } // If the DOM selection is in the editor and the editor selection is already correct, we're done.
1284
1285
1286 if (hasDomSelection && hasDomSelectionInEditor && selection) {
1287 var slateRange = ReactEditor.toSlateRange(editor, domSelection, {
1288 exactMatch: true,
1289 // domSelection is not necessarily a valid Slate range
1290 // (e.g. when clicking on contentEditable:false element)
1291 suppressThrow: true
1292 });
1293
1294 if (slateRange && slate.Range.equals(slateRange, selection)) {
1295 return;
1296 }
1297 } // when <Editable/> is being controlled through external value
1298 // then its children might just change - DOM responds to it on its own
1299 // but Slate's value is not being updated through any operation
1300 // and thus it doesn't transform selection on its own
1301
1302
1303 if (selection && !ReactEditor.hasRange(editor, selection)) {
1304 editor.selection = ReactEditor.toSlateRange(editor, domSelection, {
1305 exactMatch: false,
1306 suppressThrow: false
1307 });
1308 return;
1309 } // Otherwise the DOM selection is out of sync, so update it.
1310
1311
1312 state.isUpdatingSelection = true;
1313 var newDomRange = selection && hasDomSelectionInEditor && ReactEditor.toDOMRange(editor, selection);
1314
1315 if (newDomRange) {
1316 if (slate.Range.isBackward(selection)) {
1317 domSelection.setBaseAndExtent(newDomRange.endContainer, newDomRange.endOffset, newDomRange.startContainer, newDomRange.startOffset);
1318 } else {
1319 domSelection.setBaseAndExtent(newDomRange.startContainer, newDomRange.startOffset, newDomRange.endContainer, newDomRange.endOffset);
1320 }
1321
1322 scrollSelectionIntoView(editor, newDomRange);
1323 } else {
1324 domSelection.removeAllRanges();
1325 }
1326
1327 setTimeout(function () {
1328 // COMPAT: In Firefox, it's not enough to create a range, you also need
1329 // to focus the contenteditable element too. (2016/11/16)
1330 if (newDomRange && IS_FIREFOX) {
1331 var el = ReactEditor.toDOMNode(editor, editor);
1332 el.focus();
1333 }
1334
1335 state.isUpdatingSelection = false;
1336 });
1337 }); // The autoFocus TextareaHTMLAttribute doesn't do anything on a div, so it
1338 // needs to be manually focused.
1339
1340 React.useEffect(function () {
1341 if (ref.current && autoFocus) {
1342 ref.current.focus();
1343 }
1344 }, [autoFocus]); // Listen on the native `selectionchange` event to be able to update any time
1345 // the selection changes. This is required because React's `onSelect` is leaky
1346 // and non-standard so it doesn't fire until after a selection has been
1347 // released. This causes issues in situations where another change happens
1348 // while a selection is being dragged.
1349
1350 var onDOMSelectionChange = React.useCallback(throttle__default['default'](function () {
1351 if (!state.isComposing && !state.isUpdatingSelection && !state.isDraggingInternally) {
1352 var root = ReactEditor.findDocumentOrShadowRoot(editor);
1353 var activeElement = root.activeElement;
1354 var el = ReactEditor.toDOMNode(editor, editor);
1355 var domSelection = root.getSelection();
1356
1357 if (activeElement === el) {
1358 state.latestElement = activeElement;
1359 IS_FOCUSED.set(editor, true);
1360 } else {
1361 IS_FOCUSED["delete"](editor);
1362 }
1363
1364 if (!domSelection) {
1365 return slate.Transforms.deselect(editor);
1366 }
1367
1368 var anchorNode = domSelection.anchorNode,
1369 focusNode = domSelection.focusNode;
1370 var anchorNodeSelectable = hasEditableTarget(editor, anchorNode) || isTargetInsideNonReadonlyVoid(editor, anchorNode);
1371 var focusNodeSelectable = hasEditableTarget(editor, focusNode) || isTargetInsideNonReadonlyVoid(editor, focusNode);
1372
1373 if (anchorNodeSelectable && focusNodeSelectable) {
1374 var range = ReactEditor.toSlateRange(editor, domSelection, {
1375 exactMatch: false,
1376 suppressThrow: false
1377 });
1378 slate.Transforms.select(editor, range);
1379 }
1380 }
1381 }, 100), [readOnly]);
1382 var scheduleOnDOMSelectionChange = React.useMemo(function () {
1383 return debounce__default['default'](onDOMSelectionChange, 0);
1384 }, [onDOMSelectionChange]); // Listen on the native `beforeinput` event to get real "Level 2" events. This
1385 // is required because React's `beforeinput` is fake and never really attaches
1386 // to the real event sadly. (2019/11/01)
1387 // https://github.com/facebook/react/issues/11211
1388
1389 var onDOMBeforeInput = React.useCallback(function (event) {
1390 if (!readOnly && hasEditableTarget(editor, event.target) && !isDOMEventHandled(event, propsOnDOMBeforeInput)) {
1391 // Some IMEs/Chrome extensions like e.g. Grammarly set the selection immediately before
1392 // triggering a `beforeinput` expecting the change to be applied to the immediately before
1393 // set selection.
1394 scheduleOnDOMSelectionChange.flush();
1395 var selection = editor.selection;
1396 var type = event.inputType;
1397 var data = event.dataTransfer || event.data || undefined; // These two types occur while a user is composing text and can't be
1398 // cancelled. Let them through and wait for the composition to end.
1399
1400 if (type === 'insertCompositionText' || type === 'deleteCompositionText') {
1401 return;
1402 }
1403
1404 var _native = false;
1405
1406 if (type === 'insertText' && selection && slate.Range.isCollapsed(selection) && // Only use native character insertion for single characters a-z or space for now.
1407 // Long-press events (hold a + press 4 = ä) to choose a special character otherwise
1408 // causes duplicate inserts.
1409 event.data && event.data.length === 1 && /[a-z ]/i.test(event.data) && // Chrome has issues correctly editing the start of nodes: https://bugs.chromium.org/p/chromium/issues/detail?id=1249405
1410 // When there is an inline element, e.g. a link, and you select
1411 // right after it (the start of the next node).
1412 selection.anchor.offset !== 0) {
1413 _native = true; // Skip native if there are marks, as
1414 // `insertText` will insert a node, not just text.
1415
1416 if (editor.marks) {
1417 _native = false;
1418 } // Chrome also has issues correctly editing the end of nodes: https://bugs.chromium.org/p/chromium/issues/detail?id=1259100
1419 // Therefore we don't allow native events to insert text at the end of nodes.
1420
1421
1422 var anchor = selection.anchor;
1423 var inline = slate.Editor.above(editor, {
1424 at: anchor,
1425 match: function match(n) {
1426 return slate.Editor.isInline(editor, n);
1427 },
1428 mode: 'highest'
1429 });
1430
1431 if (inline) {
1432 var _inline = _slicedToArray(inline, 2),
1433 inlinePath = _inline[1];
1434
1435 if (slate.Editor.isEnd(editor, selection.anchor, inlinePath)) {
1436 _native = false;
1437 }
1438 }
1439 }
1440
1441 if (!_native) {
1442 event.preventDefault();
1443 } // COMPAT: For the deleting forward/backward input types we don't want
1444 // to change the selection because it is the range that will be deleted,
1445 // and those commands determine that for themselves.
1446
1447
1448 if (!type.startsWith('delete') || type.startsWith('deleteBy')) {
1449 var _event$getTargetRange = event.getTargetRanges(),
1450 _event$getTargetRange2 = _slicedToArray(_event$getTargetRange, 1),
1451 targetRange = _event$getTargetRange2[0];
1452
1453 if (targetRange) {
1454 var range = ReactEditor.toSlateRange(editor, targetRange, {
1455 exactMatch: false,
1456 suppressThrow: false
1457 });
1458
1459 if (!selection || !slate.Range.equals(selection, range)) {
1460 slate.Transforms.select(editor, range);
1461 }
1462 }
1463 } // COMPAT: If the selection is expanded, even if the command seems like
1464 // a delete forward/backward command it should delete the selection.
1465
1466
1467 if (selection && slate.Range.isExpanded(selection) && type.startsWith('delete')) {
1468 var direction = type.endsWith('Backward') ? 'backward' : 'forward';
1469 slate.Editor.deleteFragment(editor, {
1470 direction: direction
1471 });
1472 return;
1473 }
1474
1475 switch (type) {
1476 case 'deleteByComposition':
1477 case 'deleteByCut':
1478 case 'deleteByDrag':
1479 {
1480 slate.Editor.deleteFragment(editor);
1481 break;
1482 }
1483
1484 case 'deleteContent':
1485 case 'deleteContentForward':
1486 {
1487 slate.Editor.deleteForward(editor);
1488 break;
1489 }
1490
1491 case 'deleteContentBackward':
1492 {
1493 slate.Editor.deleteBackward(editor);
1494 break;
1495 }
1496
1497 case 'deleteEntireSoftLine':
1498 {
1499 slate.Editor.deleteBackward(editor, {
1500 unit: 'line'
1501 });
1502 slate.Editor.deleteForward(editor, {
1503 unit: 'line'
1504 });
1505 break;
1506 }
1507
1508 case 'deleteHardLineBackward':
1509 {
1510 slate.Editor.deleteBackward(editor, {
1511 unit: 'block'
1512 });
1513 break;
1514 }
1515
1516 case 'deleteSoftLineBackward':
1517 {
1518 slate.Editor.deleteBackward(editor, {
1519 unit: 'line'
1520 });
1521 break;
1522 }
1523
1524 case 'deleteHardLineForward':
1525 {
1526 slate.Editor.deleteForward(editor, {
1527 unit: 'block'
1528 });
1529 break;
1530 }
1531
1532 case 'deleteSoftLineForward':
1533 {
1534 slate.Editor.deleteForward(editor, {
1535 unit: 'line'
1536 });
1537 break;
1538 }
1539
1540 case 'deleteWordBackward':
1541 {
1542 slate.Editor.deleteBackward(editor, {
1543 unit: 'word'
1544 });
1545 break;
1546 }
1547
1548 case 'deleteWordForward':
1549 {
1550 slate.Editor.deleteForward(editor, {
1551 unit: 'word'
1552 });
1553 break;
1554 }
1555
1556 case 'insertLineBreak':
1557 case 'insertParagraph':
1558 {
1559 slate.Editor.insertBreak(editor);
1560 break;
1561 }
1562
1563 case 'insertFromComposition':
1564 case 'insertFromDrop':
1565 case 'insertFromPaste':
1566 case 'insertFromYank':
1567 case 'insertReplacementText':
1568 case 'insertText':
1569 {
1570 if (type === 'insertFromComposition') {
1571 // COMPAT: in Safari, `compositionend` is dispatched after the
1572 // `beforeinput` for "insertFromComposition". But if we wait for it
1573 // then we will abort because we're still composing and the selection
1574 // won't be updated properly.
1575 // https://www.w3.org/TR/input-events-2/
1576 state.isComposing && setIsComposing(false);
1577 state.isComposing = false;
1578 } // use a weak comparison instead of 'instanceof' to allow
1579 // programmatic access of paste events coming from external windows
1580 // like cypress where cy.window does not work realibly
1581
1582
1583 if ((data === null || data === void 0 ? void 0 : data.constructor.name) === 'DataTransfer') {
1584 ReactEditor.insertData(editor, data);
1585 } else if (typeof data === 'string') {
1586 // Only insertText operations use the native functionality, for now.
1587 // Potentially expand to single character deletes, as well.
1588 if (_native) {
1589 deferredOperations.current.push(function () {
1590 return slate.Editor.insertText(editor, data);
1591 });
1592 } else {
1593 slate.Editor.insertText(editor, data);
1594 }
1595 }
1596
1597 break;
1598 }
1599 }
1600 }
1601 }, [readOnly, propsOnDOMBeforeInput]); // Attach a native DOM event handler for `beforeinput` events, because React's
1602 // built-in `onBeforeInput` is actually a leaky polyfill that doesn't expose
1603 // real `beforeinput` events sadly... (2019/11/04)
1604 // https://github.com/facebook/react/issues/11211
1605
1606 useIsomorphicLayoutEffect(function () {
1607 if (ref.current && HAS_BEFORE_INPUT_SUPPORT) {
1608 // @ts-ignore The `beforeinput` event isn't recognized.
1609 ref.current.addEventListener('beforeinput', onDOMBeforeInput);
1610 }
1611
1612 return function () {
1613 if (ref.current && HAS_BEFORE_INPUT_SUPPORT) {
1614 // @ts-ignore The `beforeinput` event isn't recognized.
1615 ref.current.removeEventListener('beforeinput', onDOMBeforeInput);
1616 }
1617 };
1618 }, [onDOMBeforeInput]); // Attach a native DOM event handler for `selectionchange`, because React's
1619 // built-in `onSelect` handler doesn't fire for all selection changes. It's a
1620 // leaky polyfill that only fires on keypresses or clicks. Instead, we want to
1621 // fire for any change to the selection inside the editor. (2019/11/04)
1622 // https://github.com/facebook/react/issues/5785
1623
1624 useIsomorphicLayoutEffect(function () {
1625 var window = ReactEditor.getWindow(editor);
1626 window.document.addEventListener('selectionchange', scheduleOnDOMSelectionChange);
1627 return function () {
1628 window.document.removeEventListener('selectionchange', scheduleOnDOMSelectionChange);
1629 };
1630 }, [scheduleOnDOMSelectionChange]);
1631 var decorations = decorate([editor, []]);
1632
1633 if (placeholder && editor.children.length === 1 && Array.from(slate.Node.texts(editor)).length === 1 && slate.Node.string(editor) === '' && !isComposing) {
1634 var _decorations$push;
1635
1636 var start = slate.Editor.start(editor, []);
1637 decorations.push((_decorations$push = {}, _defineProperty(_decorations$push, PLACEHOLDER_SYMBOL, true), _defineProperty(_decorations$push, "placeholder", placeholder), _defineProperty(_decorations$push, "anchor", start), _defineProperty(_decorations$push, "focus", start), _decorations$push));
1638 }
1639
1640 return /*#__PURE__*/React__default['default'].createElement(ReadOnlyContext.Provider, {
1641 value: readOnly
1642 }, /*#__PURE__*/React__default['default'].createElement(DecorateContext.Provider, {
1643 value: decorate
1644 }, /*#__PURE__*/React__default['default'].createElement(Component, Object.assign({
1645 role: readOnly ? undefined : 'textbox'
1646 }, attributes, {
1647 // COMPAT: Certain browsers don't support the `beforeinput` event, so we'd
1648 // have to use hacks to make these replacement-based features work.
1649 // For SSR situations HAS_BEFORE_INPUT_SUPPORT is false and results in prop
1650 // mismatch warning app moves to browser. Pass-through consumer props when
1651 // not CAN_USE_DOM (SSR) and default to falsy value
1652 spellCheck: HAS_BEFORE_INPUT_SUPPORT || !CAN_USE_DOM ? attributes.spellCheck : false,
1653 autoCorrect: HAS_BEFORE_INPUT_SUPPORT || !CAN_USE_DOM ? attributes.autoCorrect : 'false',
1654 autoCapitalize: HAS_BEFORE_INPUT_SUPPORT || !CAN_USE_DOM ? attributes.autoCapitalize : 'false',
1655 "data-slate-editor": true,
1656 "data-slate-node": "value",
1657 // explicitly set this
1658 contentEditable: !readOnly,
1659 // in some cases, a decoration needs access to the range / selection to decorate a text node,
1660 // then you will select the whole text node when you select part the of text
1661 // this magic zIndex="-1" will fix it
1662 zindex: -1,
1663 suppressContentEditableWarning: true,
1664 ref: ref,
1665 style: _objectSpread$1({
1666 // Allow positioning relative to the editable element.
1667 position: 'relative',
1668 // Prevent the default outline styles.
1669 outline: 'none',
1670 // Preserve adjacent whitespace and new lines.
1671 whiteSpace: 'pre-wrap',
1672 // Allow words to break if they are too long.
1673 wordWrap: 'break-word'
1674 }, style),
1675 onBeforeInput: React.useCallback(function (event) {
1676 // COMPAT: Certain browsers don't support the `beforeinput` event, so we
1677 // fall back to React's leaky polyfill instead just for it. It
1678 // only works for the `insertText` input type.
1679 if (!HAS_BEFORE_INPUT_SUPPORT && !readOnly && !isEventHandled(event, attributes.onBeforeInput) && hasEditableTarget(editor, event.target)) {
1680 event.preventDefault();
1681
1682 if (!state.isComposing) {
1683 var text = event.data;
1684 slate.Editor.insertText(editor, text);
1685 }
1686 }
1687 }, [readOnly]),
1688 onInput: React.useCallback(function (event) {
1689 // Flush native operations, as native events will have propogated
1690 // and we can correctly compare DOM text values in components
1691 // to stop rendering, so that browser functions like autocorrect
1692 // and spellcheck work as expected.
1693 var _iterator = _createForOfIteratorHelper$2(deferredOperations.current),
1694 _step;
1695
1696 try {
1697 for (_iterator.s(); !(_step = _iterator.n()).done;) {
1698 var op = _step.value;
1699 op();
1700 }
1701 } catch (err) {
1702 _iterator.e(err);
1703 } finally {
1704 _iterator.f();
1705 }
1706
1707 deferredOperations.current = [];
1708 }, []),
1709 onBlur: React.useCallback(function (event) {
1710 if (readOnly || state.isUpdatingSelection || !hasEditableTarget(editor, event.target) || isEventHandled(event, attributes.onBlur)) {
1711 return;
1712 } // COMPAT: If the current `activeElement` is still the previous
1713 // one, this is due to the window being blurred when the tab
1714 // itself becomes unfocused, so we want to abort early to allow to
1715 // editor to stay focused when the tab becomes focused again.
1716
1717
1718 var root = ReactEditor.findDocumentOrShadowRoot(editor);
1719
1720 if (state.latestElement === root.activeElement) {
1721 return;
1722 }
1723
1724 var relatedTarget = event.relatedTarget;
1725 var el = ReactEditor.toDOMNode(editor, editor); // COMPAT: The event should be ignored if the focus is returning
1726 // to the editor from an embedded editable element (eg. an <input>
1727 // element inside a void node).
1728
1729 if (relatedTarget === el) {
1730 return;
1731 } // COMPAT: The event should be ignored if the focus is moving from
1732 // the editor to inside a void node's spacer element.
1733
1734
1735 if (isDOMElement(relatedTarget) && relatedTarget.hasAttribute('data-slate-spacer')) {
1736 return;
1737 } // COMPAT: The event should be ignored if the focus is moving to a
1738 // non- editable section of an element that isn't a void node (eg.
1739 // a list item of the check list example).
1740
1741
1742 if (relatedTarget != null && isDOMNode(relatedTarget) && ReactEditor.hasDOMNode(editor, relatedTarget)) {
1743 var node = ReactEditor.toSlateNode(editor, relatedTarget);
1744
1745 if (slate.Element.isElement(node) && !editor.isVoid(node)) {
1746 return;
1747 }
1748 } // COMPAT: Safari doesn't always remove the selection even if the content-
1749 // editable element no longer has focus. Refer to:
1750 // https://stackoverflow.com/questions/12353247/force-contenteditable-div-to-stop-accepting-input-after-it-loses-focus-under-web
1751
1752
1753 if (IS_SAFARI) {
1754 var domSelection = root.getSelection();
1755 domSelection === null || domSelection === void 0 ? void 0 : domSelection.removeAllRanges();
1756 }
1757
1758 IS_FOCUSED["delete"](editor);
1759 }, [readOnly, attributes.onBlur]),
1760 onClick: React.useCallback(function (event) {
1761 if (!readOnly && hasTarget(editor, event.target) && !isEventHandled(event, attributes.onClick) && isDOMNode(event.target)) {
1762 var node = ReactEditor.toSlateNode(editor, event.target);
1763 var path = ReactEditor.findPath(editor, node); // At this time, the Slate document may be arbitrarily different,
1764 // because onClick handlers can change the document before we get here.
1765 // Therefore we must check that this path actually exists,
1766 // and that it still refers to the same node.
1767
1768 if (slate.Editor.hasPath(editor, path)) {
1769 var lookupNode = slate.Node.get(editor, path);
1770
1771 if (lookupNode === node) {
1772 var _start = slate.Editor.start(editor, path);
1773
1774 var end = slate.Editor.end(editor, path);
1775 var startVoid = slate.Editor["void"](editor, {
1776 at: _start
1777 });
1778 var endVoid = slate.Editor["void"](editor, {
1779 at: end
1780 });
1781
1782 if (startVoid && endVoid && slate.Path.equals(startVoid[1], endVoid[1])) {
1783 var range = slate.Editor.range(editor, _start);
1784 slate.Transforms.select(editor, range);
1785 }
1786 }
1787 }
1788 }
1789 }, [readOnly, attributes.onClick]),
1790 onCompositionEnd: React.useCallback(function (event) {
1791 if (hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onCompositionEnd)) {
1792 state.isComposing && setIsComposing(false);
1793 state.isComposing = false; // COMPAT: In Chrome, `beforeinput` events for compositions
1794 // aren't correct and never fire the "insertFromComposition"
1795 // type that we need. So instead, insert whenever a composition
1796 // ends since it will already have been committed to the DOM.
1797
1798 if (!IS_SAFARI && !IS_FIREFOX_LEGACY && !IS_IOS && !IS_QQBROWSER && !IS_WECHATBROWSER && !IS_UC_MOBILE && event.data) {
1799 slate.Editor.insertText(editor, event.data);
1800 }
1801
1802 if (editor.selection && slate.Range.isCollapsed(editor.selection)) {
1803 var leafPath = editor.selection.anchor.path;
1804 var currentTextNode = slate.Node.leaf(editor, leafPath);
1805
1806 if (state.hasInsertPrefixInCompositon) {
1807 state.hasInsertPrefixInCompositon = false;
1808 slate.Editor.withoutNormalizing(editor, function () {
1809 // remove Unicode BOM prefix added in `onCompositionStart`
1810 var text = currentTextNode.text.replace(/^\uFEFF/, '');
1811 slate.Transforms["delete"](editor, {
1812 distance: currentTextNode.text.length,
1813 reverse: true
1814 });
1815 slate.Editor.insertText(editor, text);
1816 });
1817 }
1818 }
1819 }
1820 }, [attributes.onCompositionEnd]),
1821 onCompositionUpdate: React.useCallback(function (event) {
1822 if (hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onCompositionUpdate)) {
1823 !state.isComposing && setIsComposing(true);
1824 state.isComposing = true;
1825 }
1826 }, [attributes.onCompositionUpdate]),
1827 onCompositionStart: React.useCallback(function (event) {
1828 if (hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onCompositionStart)) {
1829 var selection = editor.selection,
1830 marks = editor.marks;
1831
1832 if (selection) {
1833 if (slate.Range.isExpanded(selection)) {
1834 slate.Editor.deleteFragment(editor);
1835 return;
1836 }
1837
1838 var inline = slate.Editor.above(editor, {
1839 match: function match(n) {
1840 return slate.Editor.isInline(editor, n);
1841 },
1842 mode: 'highest'
1843 });
1844
1845 if (inline) {
1846 var _inline2 = _slicedToArray(inline, 2),
1847 inlinePath = _inline2[1];
1848
1849 if (slate.Editor.isEnd(editor, selection.anchor, inlinePath)) {
1850 var point = slate.Editor.after(editor, inlinePath);
1851 slate.Transforms.setSelection(editor, {
1852 anchor: point,
1853 focus: point
1854 });
1855 }
1856 } // insert new node in advance to ensure composition text will insert
1857 // along with final input text
1858 // add Unicode BOM prefix to avoid normalize removing this node
1859
1860
1861 if (marks) {
1862 state.hasInsertPrefixInCompositon = true;
1863 slate.Transforms.insertNodes(editor, _objectSpread$1({
1864 text: "\uFEFF"
1865 }, marks), {
1866 select: true
1867 });
1868 }
1869 }
1870 }
1871 }, [attributes.onCompositionStart]),
1872 onCopy: React.useCallback(function (event) {
1873 if (hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onCopy)) {
1874 event.preventDefault();
1875 ReactEditor.setFragmentData(editor, event.clipboardData, 'copy');
1876 }
1877 }, [attributes.onCopy]),
1878 onCut: React.useCallback(function (event) {
1879 if (!readOnly && hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onCut)) {
1880 event.preventDefault();
1881 ReactEditor.setFragmentData(editor, event.clipboardData, 'cut');
1882 var selection = editor.selection;
1883
1884 if (selection) {
1885 if (slate.Range.isExpanded(selection)) {
1886 slate.Editor.deleteFragment(editor);
1887 } else {
1888 var node = slate.Node.parent(editor, selection.anchor.path);
1889
1890 if (slate.Editor.isVoid(editor, node)) {
1891 slate.Transforms["delete"](editor);
1892 }
1893 }
1894 }
1895 }
1896 }, [readOnly, attributes.onCut]),
1897 onDragOver: React.useCallback(function (event) {
1898 if (hasTarget(editor, event.target) && !isEventHandled(event, attributes.onDragOver)) {
1899 // Only when the target is void, call `preventDefault` to signal
1900 // that drops are allowed. Editable content is droppable by
1901 // default, and calling `preventDefault` hides the cursor.
1902 var node = ReactEditor.toSlateNode(editor, event.target);
1903
1904 if (slate.Editor.isVoid(editor, node)) {
1905 event.preventDefault();
1906 }
1907 }
1908 }, [attributes.onDragOver]),
1909 onDragStart: React.useCallback(function (event) {
1910 if (!readOnly && hasTarget(editor, event.target) && !isEventHandled(event, attributes.onDragStart)) {
1911 var node = ReactEditor.toSlateNode(editor, event.target);
1912 var path = ReactEditor.findPath(editor, node);
1913 var voidMatch = slate.Editor.isVoid(editor, node) || slate.Editor["void"](editor, {
1914 at: path,
1915 voids: true
1916 }); // If starting a drag on a void node, make sure it is selected
1917 // so that it shows up in the selection's fragment.
1918
1919 if (voidMatch) {
1920 var range = slate.Editor.range(editor, path);
1921 slate.Transforms.select(editor, range);
1922 }
1923
1924 state.isDraggingInternally = true;
1925 ReactEditor.setFragmentData(editor, event.dataTransfer, 'drag');
1926 }
1927 }, [readOnly, attributes.onDragStart]),
1928 onDrop: React.useCallback(function (event) {
1929 if (!readOnly && hasTarget(editor, event.target) && !isEventHandled(event, attributes.onDrop)) {
1930 event.preventDefault(); // Keep a reference to the dragged range before updating selection
1931
1932 var draggedRange = editor.selection; // Find the range where the drop happened
1933
1934 var range = ReactEditor.findEventRange(editor, event);
1935 var data = event.dataTransfer;
1936 slate.Transforms.select(editor, range);
1937
1938 if (state.isDraggingInternally) {
1939 if (draggedRange && !slate.Range.equals(draggedRange, range) && !slate.Editor["void"](editor, {
1940 at: range,
1941 voids: true
1942 })) {
1943 slate.Transforms["delete"](editor, {
1944 at: draggedRange
1945 });
1946 }
1947
1948 state.isDraggingInternally = false;
1949 }
1950
1951 ReactEditor.insertData(editor, data); // When dragging from another source into the editor, it's possible
1952 // that the current editor does not have focus.
1953
1954 if (!ReactEditor.isFocused(editor)) {
1955 ReactEditor.focus(editor);
1956 }
1957 }
1958 }, [readOnly, attributes.onDrop]),
1959 onDragEnd: React.useCallback(function (event) {
1960 // When dropping on a different droppable element than the current editor,
1961 // `onDrop` is not called. So we need to clean up in `onDragEnd` instead.
1962 // Note: `onDragEnd` is only called when `onDrop` is not called
1963 if (!readOnly && state.isDraggingInternally && hasTarget(editor, event.target) && !isEventHandled(event, attributes.onDragEnd)) {
1964 state.isDraggingInternally = false;
1965 }
1966 }, [readOnly, attributes.onDragEnd]),
1967 onFocus: React.useCallback(function (event) {
1968 if (!readOnly && !state.isUpdatingSelection && hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onFocus)) {
1969 var el = ReactEditor.toDOMNode(editor, editor);
1970 var root = ReactEditor.findDocumentOrShadowRoot(editor);
1971 state.latestElement = root.activeElement; // COMPAT: If the editor has nested editable elements, the focus
1972 // can go to them. In Firefox, this must be prevented because it
1973 // results in issues with keyboard navigation. (2017/03/30)
1974
1975 if (IS_FIREFOX && event.target !== el) {
1976 el.focus();
1977 return;
1978 }
1979
1980 IS_FOCUSED.set(editor, true);
1981 }
1982 }, [readOnly, attributes.onFocus]),
1983 onKeyDown: React.useCallback(function (event) {
1984 if (!readOnly && !state.isComposing && hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onKeyDown)) {
1985 var nativeEvent = event.nativeEvent;
1986 var selection = editor.selection;
1987 var element = editor.children[selection !== null ? selection.focus.path[0] : 0];
1988 var isRTL = getDirection__default['default'](slate.Node.string(element)) === 'rtl'; // COMPAT: Since we prevent the default behavior on
1989 // `beforeinput` events, the browser doesn't think there's ever
1990 // any history stack to undo or redo, so we have to manage these
1991 // hotkeys ourselves. (2019/11/06)
1992
1993 if (Hotkeys.isRedo(nativeEvent)) {
1994 event.preventDefault();
1995 var maybeHistoryEditor = editor;
1996
1997 if (typeof maybeHistoryEditor.redo === 'function') {
1998 maybeHistoryEditor.redo();
1999 }
2000
2001 return;
2002 }
2003
2004 if (Hotkeys.isUndo(nativeEvent)) {
2005 event.preventDefault();
2006 var _maybeHistoryEditor = editor;
2007
2008 if (typeof _maybeHistoryEditor.undo === 'function') {
2009 _maybeHistoryEditor.undo();
2010 }
2011
2012 return;
2013 } // COMPAT: Certain browsers don't handle the selection updates
2014 // properly. In Chrome, the selection isn't properly extended.
2015 // And in Firefox, the selection isn't properly collapsed.
2016 // (2017/10/17)
2017
2018
2019 if (Hotkeys.isMoveLineBackward(nativeEvent)) {
2020 event.preventDefault();
2021 slate.Transforms.move(editor, {
2022 unit: 'line',
2023 reverse: true
2024 });
2025 return;
2026 }
2027
2028 if (Hotkeys.isMoveLineForward(nativeEvent)) {
2029 event.preventDefault();
2030 slate.Transforms.move(editor, {
2031 unit: 'line'
2032 });
2033 return;
2034 }
2035
2036 if (Hotkeys.isExtendLineBackward(nativeEvent)) {
2037 event.preventDefault();
2038 slate.Transforms.move(editor, {
2039 unit: 'line',
2040 edge: 'focus',
2041 reverse: true
2042 });
2043 return;
2044 }
2045
2046 if (Hotkeys.isExtendLineForward(nativeEvent)) {
2047 event.preventDefault();
2048 slate.Transforms.move(editor, {
2049 unit: 'line',
2050 edge: 'focus'
2051 });
2052 return;
2053 } // COMPAT: If a void node is selected, or a zero-width text node
2054 // adjacent to an inline is selected, we need to handle these
2055 // hotkeys manually because browsers won't be able to skip over
2056 // the void node with the zero-width space not being an empty
2057 // string.
2058
2059
2060 if (Hotkeys.isMoveBackward(nativeEvent)) {
2061 event.preventDefault();
2062
2063 if (selection && slate.Range.isCollapsed(selection)) {
2064 slate.Transforms.move(editor, {
2065 reverse: !isRTL
2066 });
2067 } else {
2068 slate.Transforms.collapse(editor, {
2069 edge: 'start'
2070 });
2071 }
2072
2073 return;
2074 }
2075
2076 if (Hotkeys.isMoveForward(nativeEvent)) {
2077 event.preventDefault();
2078
2079 if (selection && slate.Range.isCollapsed(selection)) {
2080 slate.Transforms.move(editor, {
2081 reverse: isRTL
2082 });
2083 } else {
2084 slate.Transforms.collapse(editor, {
2085 edge: 'end'
2086 });
2087 }
2088
2089 return;
2090 }
2091
2092 if (Hotkeys.isMoveWordBackward(nativeEvent)) {
2093 event.preventDefault();
2094
2095 if (selection && slate.Range.isExpanded(selection)) {
2096 slate.Transforms.collapse(editor, {
2097 edge: 'focus'
2098 });
2099 }
2100
2101 slate.Transforms.move(editor, {
2102 unit: 'word',
2103 reverse: !isRTL
2104 });
2105 return;
2106 }
2107
2108 if (Hotkeys.isMoveWordForward(nativeEvent)) {
2109 event.preventDefault();
2110
2111 if (selection && slate.Range.isExpanded(selection)) {
2112 slate.Transforms.collapse(editor, {
2113 edge: 'focus'
2114 });
2115 }
2116
2117 slate.Transforms.move(editor, {
2118 unit: 'word',
2119 reverse: isRTL
2120 });
2121 return;
2122 } // COMPAT: Certain browsers don't support the `beforeinput` event, so we
2123 // fall back to guessing at the input intention for hotkeys.
2124 // COMPAT: In iOS, some of these hotkeys are handled in the
2125
2126
2127 if (!HAS_BEFORE_INPUT_SUPPORT) {
2128 // We don't have a core behavior for these, but they change the
2129 // DOM if we don't prevent them, so we have to.
2130 if (Hotkeys.isBold(nativeEvent) || Hotkeys.isItalic(nativeEvent) || Hotkeys.isTransposeCharacter(nativeEvent)) {
2131 event.preventDefault();
2132 return;
2133 }
2134
2135 if (Hotkeys.isSplitBlock(nativeEvent)) {
2136 event.preventDefault();
2137 slate.Editor.insertBreak(editor);
2138 return;
2139 }
2140
2141 if (Hotkeys.isDeleteBackward(nativeEvent)) {
2142 event.preventDefault();
2143
2144 if (selection && slate.Range.isExpanded(selection)) {
2145 slate.Editor.deleteFragment(editor, {
2146 direction: 'backward'
2147 });
2148 } else {
2149 slate.Editor.deleteBackward(editor);
2150 }
2151
2152 return;
2153 }
2154
2155 if (Hotkeys.isDeleteForward(nativeEvent)) {
2156 event.preventDefault();
2157
2158 if (selection && slate.Range.isExpanded(selection)) {
2159 slate.Editor.deleteFragment(editor, {
2160 direction: 'forward'
2161 });
2162 } else {
2163 slate.Editor.deleteForward(editor);
2164 }
2165
2166 return;
2167 }
2168
2169 if (Hotkeys.isDeleteLineBackward(nativeEvent)) {
2170 event.preventDefault();
2171
2172 if (selection && slate.Range.isExpanded(selection)) {
2173 slate.Editor.deleteFragment(editor, {
2174 direction: 'backward'
2175 });
2176 } else {
2177 slate.Editor.deleteBackward(editor, {
2178 unit: 'line'
2179 });
2180 }
2181
2182 return;
2183 }
2184
2185 if (Hotkeys.isDeleteLineForward(nativeEvent)) {
2186 event.preventDefault();
2187
2188 if (selection && slate.Range.isExpanded(selection)) {
2189 slate.Editor.deleteFragment(editor, {
2190 direction: 'forward'
2191 });
2192 } else {
2193 slate.Editor.deleteForward(editor, {
2194 unit: 'line'
2195 });
2196 }
2197
2198 return;
2199 }
2200
2201 if (Hotkeys.isDeleteWordBackward(nativeEvent)) {
2202 event.preventDefault();
2203
2204 if (selection && slate.Range.isExpanded(selection)) {
2205 slate.Editor.deleteFragment(editor, {
2206 direction: 'backward'
2207 });
2208 } else {
2209 slate.Editor.deleteBackward(editor, {
2210 unit: 'word'
2211 });
2212 }
2213
2214 return;
2215 }
2216
2217 if (Hotkeys.isDeleteWordForward(nativeEvent)) {
2218 event.preventDefault();
2219
2220 if (selection && slate.Range.isExpanded(selection)) {
2221 slate.Editor.deleteFragment(editor, {
2222 direction: 'forward'
2223 });
2224 } else {
2225 slate.Editor.deleteForward(editor, {
2226 unit: 'word'
2227 });
2228 }
2229
2230 return;
2231 }
2232 } else {
2233 if (IS_CHROME || IS_SAFARI) {
2234 // COMPAT: Chrome and Safari support `beforeinput` event but do not fire
2235 // an event when deleting backwards in a selected void inline node
2236 if (selection && (Hotkeys.isDeleteBackward(nativeEvent) || Hotkeys.isDeleteForward(nativeEvent)) && slate.Range.isCollapsed(selection)) {
2237 var currentNode = slate.Node.parent(editor, selection.anchor.path);
2238
2239 if (slate.Element.isElement(currentNode) && slate.Editor.isVoid(editor, currentNode) && slate.Editor.isInline(editor, currentNode)) {
2240 event.preventDefault();
2241 slate.Editor.deleteBackward(editor, {
2242 unit: 'block'
2243 });
2244 return;
2245 }
2246 }
2247 }
2248 }
2249 }
2250 }, [readOnly, attributes.onKeyDown]),
2251 onPaste: React.useCallback(function (event) {
2252 if (!readOnly && hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onPaste)) {
2253 // COMPAT: Certain browsers don't support the `beforeinput` event, so we
2254 // fall back to React's `onPaste` here instead.
2255 // COMPAT: Firefox, Chrome and Safari don't emit `beforeinput` events
2256 // when "paste without formatting" is used, so fallback. (2020/02/20)
2257 if (!HAS_BEFORE_INPUT_SUPPORT || isPlainTextOnlyPaste(event.nativeEvent)) {
2258 event.preventDefault();
2259 ReactEditor.insertData(editor, event.clipboardData);
2260 }
2261 }
2262 }, [readOnly, attributes.onPaste])
2263 }), /*#__PURE__*/React__default['default'].createElement(Children, {
2264 decorations: decorations,
2265 node: editor,
2266 renderElement: renderElement,
2267 renderPlaceholder: renderPlaceholder,
2268 renderLeaf: renderLeaf,
2269 selection: editor.selection
2270 }))));
2271};
2272/**
2273 * The default placeholder element
2274 */
2275
2276var DefaultPlaceholder = function DefaultPlaceholder(_ref) {
2277 var attributes = _ref.attributes,
2278 children = _ref.children;
2279 return /*#__PURE__*/React__default['default'].createElement("span", Object.assign({}, attributes), children);
2280};
2281/**
2282 * A default memoized decorate function.
2283 */
2284
2285var defaultDecorate = function defaultDecorate() {
2286 return [];
2287};
2288/**
2289 * A default implement to scroll dom range into view.
2290 */
2291
2292var defaultScrollSelectionIntoView = function defaultScrollSelectionIntoView(editor, domRange) {
2293 // This was affecting the selection of multiple blocks and dragging behavior,
2294 // so enabled only if the selection has been collapsed.
2295 if (!editor.selection || editor.selection && slate.Range.isCollapsed(editor.selection)) {
2296 var leafEl = domRange.startContainer.parentElement;
2297 leafEl.getBoundingClientRect = domRange.getBoundingClientRect.bind(domRange);
2298 scrollIntoView__default['default'](leafEl, {
2299 scrollMode: 'if-needed'
2300 });
2301 delete leafEl.getBoundingClientRect;
2302 }
2303};
2304/**
2305 * Check if the target is in the editor.
2306 */
2307
2308var hasTarget = function hasTarget(editor, target) {
2309 return isDOMNode(target) && ReactEditor.hasDOMNode(editor, target);
2310};
2311/**
2312 * Check if the target is editable and in the editor.
2313 */
2314
2315var hasEditableTarget = function hasEditableTarget(editor, target) {
2316 return isDOMNode(target) && ReactEditor.hasDOMNode(editor, target, {
2317 editable: true
2318 });
2319};
2320/**
2321 * Check if the target is inside void and in an non-readonly editor.
2322 */
2323
2324var isTargetInsideNonReadonlyVoid = function isTargetInsideNonReadonlyVoid(editor, target) {
2325 if (IS_READ_ONLY.get(editor)) return false;
2326 var slateNode = hasTarget(editor, target) && ReactEditor.toSlateNode(editor, target);
2327 return slate.Editor.isVoid(editor, slateNode);
2328};
2329/**
2330 * Check if an event is overrided by a handler.
2331 */
2332
2333var isEventHandled = function isEventHandled(event, handler) {
2334 if (!handler) {
2335 return false;
2336 } // The custom event handler may return a boolean to specify whether the event
2337 // shall be treated as being handled or not.
2338
2339
2340 var shouldTreatEventAsHandled = handler(event);
2341
2342 if (shouldTreatEventAsHandled != null) {
2343 return shouldTreatEventAsHandled;
2344 }
2345
2346 return event.isDefaultPrevented() || event.isPropagationStopped();
2347};
2348/**
2349 * Check if a DOM event is overrided by a handler.
2350 */
2351
2352var isDOMEventHandled = function isDOMEventHandled(event, handler) {
2353 if (!handler) {
2354 return false;
2355 } // The custom event handler may return a boolean to specify whether the event
2356 // shall be treated as being handled or not.
2357
2358
2359 var shouldTreatEventAsHandled = handler(event);
2360
2361 if (shouldTreatEventAsHandled != null) {
2362 return shouldTreatEventAsHandled;
2363 }
2364
2365 return event.defaultPrevented;
2366};
2367
2368/**
2369 * Returns the number of characters that are the same at the beginning of the
2370 * String.
2371 *
2372 * @param prev the previous text
2373 * @param next the next text
2374 * @returns the offset of the start of the difference; null if there is no difference
2375 */
2376
2377function getDiffStart(prev, next) {
2378 var length = Math.min(prev.length, next.length);
2379
2380 for (var i = 0; i < length; i++) {
2381 if (prev.charAt(i) !== next.charAt(i)) return i;
2382 }
2383
2384 if (prev.length !== next.length) return length;
2385 return null;
2386}
2387/**
2388 * Returns the number of characters that are the same at the end of the String
2389 * up to `max`. Max prevents double-counting characters when there are
2390 * multiple duplicate characters around the diff area.
2391 *
2392 * @param prev the previous text
2393 * @param next the next text
2394 * @param max the max length to test.
2395 * @returns number of characters that are the same at the end of the string
2396 */
2397
2398
2399function getDiffEnd(prev, next, max) {
2400 var prevLength = prev.length;
2401 var nextLength = next.length;
2402 var length = Math.min(prevLength, nextLength, max);
2403
2404 for (var i = 0; i < length; i++) {
2405 var prevChar = prev.charAt(prevLength - i - 1);
2406 var nextChar = next.charAt(nextLength - i - 1);
2407 if (prevChar !== nextChar) return i;
2408 }
2409
2410 if (prev.length !== next.length) return length;
2411 return null;
2412}
2413/**
2414 * Takes two strings and returns an object representing two offsets. The
2415 * first, `start` represents the number of characters that are the same at
2416 * the front of the String. The `end` represents the number of characters
2417 * that are the same at the end of the String.
2418 *
2419 * Returns null if they are identical.
2420 *
2421 * @param prev the previous text
2422 * @param next the next text
2423 * @returns the difference text range; null if there are no differences.
2424 */
2425
2426
2427function getDiffOffsets(prev, next) {
2428 if (prev === next) return null;
2429 var start = getDiffStart(prev, next);
2430 if (start === null) return null;
2431 var maxEnd = Math.min(prev.length - start, next.length - start);
2432 var end = getDiffEnd(prev, next, maxEnd);
2433 if (end === null) return null;
2434 return {
2435 start: start,
2436 end: end
2437 };
2438}
2439/**
2440 * Takes a text string and returns a slice from the string at the given text range
2441 *
2442 * @param text the text
2443 * @param offsets the text range
2444 * @returns the text slice at text range
2445 */
2446
2447
2448function sliceText(text, offsets) {
2449 return text.slice(offsets.start, text.length - offsets.end);
2450}
2451/**
2452 * Takes two strings and returns a smart diff that can be used to describe the
2453 * change in a way that can be used as operations like inserting, removing or
2454 * replacing text.
2455 *
2456 * @param prev the previous text
2457 * @param next the next text
2458 * @returns the text difference
2459 */
2460
2461
2462function diffText(prev, next) {
2463 if (prev === undefined || next === undefined) return null;
2464 var offsets = getDiffOffsets(prev, next);
2465 if (offsets == null) return null;
2466 var insertText = sliceText(next, offsets);
2467 var removeText = sliceText(prev, offsets);
2468 return {
2469 start: offsets.start,
2470 end: prev.length - offsets.end,
2471 insertText: insertText,
2472 removeText: removeText
2473 };
2474}
2475function combineInsertedText(insertedText) {
2476 return insertedText.reduce(function (acc, _ref) {
2477 var text = _ref.text;
2478 return "".concat(acc).concat(text.insertText);
2479 }, '');
2480}
2481function getTextInsertion(editor, domNode) {
2482 var node = ReactEditor.toSlateNode(editor, domNode);
2483
2484 if (!slate.Text.isText(node)) {
2485 return undefined;
2486 }
2487
2488 var prevText = node.text;
2489 var nextText = domNode.textContent; // textContent will pad an extra \n when the textContent ends with an \n
2490
2491 if (nextText.endsWith('\n')) {
2492 nextText = nextText.slice(0, nextText.length - 1);
2493 } // If the text is no different, there is no diff.
2494
2495
2496 if (nextText !== prevText) {
2497 var textDiff = diffText(prevText, nextText);
2498
2499 if (textDiff !== null) {
2500 var textPath = ReactEditor.findPath(editor, node);
2501 return {
2502 text: textDiff,
2503 path: textPath
2504 };
2505 }
2506 }
2507
2508 return undefined;
2509}
2510function normalizeTextInsertionRange(editor, range, _ref2) {
2511 var path = _ref2.path,
2512 text = _ref2.text;
2513 var insertionRange = {
2514 anchor: {
2515 path: path,
2516 offset: text.start
2517 },
2518 focus: {
2519 path: path,
2520 offset: text.end
2521 }
2522 };
2523
2524 if (!range || !slate.Range.isCollapsed(range)) {
2525 return insertionRange;
2526 }
2527
2528 var insertText = text.insertText,
2529 removeText = text.removeText;
2530 var isSingleCharacterInsertion = insertText.length === 1 || removeText.length === 1;
2531 /**
2532 * This code handles edge cases that arise from text diffing when the
2533 * inserted or removed character is a single character, and the character
2534 * right before or after the anchor is the same as the one being inserted or
2535 * removed.
2536 *
2537 * Take this example: hello|o
2538 *
2539 * If another `o` is inserted at the selection's anchor in the example above,
2540 * it should be inserted at the anchor, but using text diffing, we actually
2541 * detect that the character was inserted after the second `o`:
2542 *
2543 * helloo[o]|
2544 *
2545 * Instead, in these very specific edge cases, we assume that the character
2546 * needs to be inserted after the anchor rather than where the diff was found:
2547 *
2548 * hello[o]|o
2549 */
2550
2551 if (isSingleCharacterInsertion && slate.Path.equals(range.anchor.path, path)) {
2552 var _Array$from = Array.from(slate.Editor.nodes(editor, {
2553 at: range,
2554 match: slate.Text.isText
2555 })),
2556 _Array$from2 = _slicedToArray(_Array$from, 1),
2557 _text = _Array$from2[0];
2558
2559 if (_text) {
2560 var _text2 = _slicedToArray(_text, 1),
2561 node = _text2[0];
2562
2563 var anchor = range.anchor;
2564 var characterBeforeAnchor = node.text[anchor.offset - 1];
2565 var characterAfterAnchor = node.text[anchor.offset];
2566
2567 if (insertText.length === 1 && insertText === characterAfterAnchor) {
2568 // Assume text should be inserted at the anchor
2569 return range;
2570 }
2571
2572 if (removeText.length === 1 && removeText === characterBeforeAnchor) {
2573 // Assume text should be removed right before the anchor
2574 return {
2575 anchor: {
2576 path: path,
2577 offset: anchor.offset - 1
2578 },
2579 focus: {
2580 path: path,
2581 offset: anchor.offset
2582 }
2583 };
2584 }
2585 }
2586 }
2587
2588 return insertionRange;
2589}
2590
2591var classCallCheck = createCommonjsModule(function (module) {
2592function _classCallCheck(instance, Constructor) {
2593 if (!(instance instanceof Constructor)) {
2594 throw new TypeError("Cannot call a class as a function");
2595 }
2596}
2597
2598module.exports = _classCallCheck;
2599module.exports["default"] = module.exports, module.exports.__esModule = true;
2600});
2601
2602var _classCallCheck = unwrapExports(classCallCheck);
2603
2604var arrayWithoutHoles = createCommonjsModule(function (module) {
2605function _arrayWithoutHoles(arr) {
2606 if (Array.isArray(arr)) return arrayLikeToArray(arr);
2607}
2608
2609module.exports = _arrayWithoutHoles;
2610module.exports["default"] = module.exports, module.exports.__esModule = true;
2611});
2612
2613unwrapExports(arrayWithoutHoles);
2614
2615var iterableToArray = createCommonjsModule(function (module) {
2616function _iterableToArray(iter) {
2617 if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
2618}
2619
2620module.exports = _iterableToArray;
2621module.exports["default"] = module.exports, module.exports.__esModule = true;
2622});
2623
2624unwrapExports(iterableToArray);
2625
2626var nonIterableSpread = createCommonjsModule(function (module) {
2627function _nonIterableSpread() {
2628 throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
2629}
2630
2631module.exports = _nonIterableSpread;
2632module.exports["default"] = module.exports, module.exports.__esModule = true;
2633});
2634
2635unwrapExports(nonIterableSpread);
2636
2637var toConsumableArray = createCommonjsModule(function (module) {
2638function _toConsumableArray(arr) {
2639 return arrayWithoutHoles(arr) || iterableToArray(arr) || unsupportedIterableToArray(arr) || nonIterableSpread();
2640}
2641
2642module.exports = _toConsumableArray;
2643module.exports["default"] = module.exports, module.exports.__esModule = true;
2644});
2645
2646var _toConsumableArray = unwrapExports(toConsumableArray);
2647
2648/**
2649 * An auto-incrementing identifier for keys.
2650 */
2651var n = 0;
2652/**
2653 * A class that keeps track of a key string. We use a full class here because we
2654 * want to be able to use them as keys in `WeakMap` objects.
2655 */
2656
2657var Key = function Key() {
2658 _classCallCheck(this, Key);
2659
2660 this.id = "".concat(n++);
2661};
2662
2663var ReactEditor = {
2664 /**
2665 * Return the host window of the current editor.
2666 */
2667 getWindow: function getWindow(editor) {
2668 var window = EDITOR_TO_WINDOW.get(editor);
2669
2670 if (!window) {
2671 throw new Error('Unable to find a host window element for this editor');
2672 }
2673
2674 return window;
2675 },
2676
2677 /**
2678 * Find a key for a Slate node.
2679 */
2680 findKey: function findKey(editor, node) {
2681 var key = NODE_TO_KEY.get(node);
2682
2683 if (!key) {
2684 key = new Key();
2685 NODE_TO_KEY.set(node, key);
2686 }
2687
2688 return key;
2689 },
2690
2691 /**
2692 * Find the path of Slate node.
2693 */
2694 findPath: function findPath(editor, node) {
2695 var path = [];
2696 var child = node;
2697
2698 while (true) {
2699 var parent = NODE_TO_PARENT.get(child);
2700
2701 if (parent == null) {
2702 if (slate.Editor.isEditor(child)) {
2703 return path;
2704 } else {
2705 break;
2706 }
2707 }
2708
2709 var i = NODE_TO_INDEX.get(child);
2710
2711 if (i == null) {
2712 break;
2713 }
2714
2715 path.unshift(i);
2716 child = parent;
2717 }
2718
2719 throw new Error("Unable to find the path for Slate node: ".concat(JSON.stringify(node)));
2720 },
2721
2722 /**
2723 * Find the DOM node that implements DocumentOrShadowRoot for the editor.
2724 */
2725 findDocumentOrShadowRoot: function findDocumentOrShadowRoot(editor) {
2726 var el = ReactEditor.toDOMNode(editor, editor);
2727 var root = el.getRootNode();
2728
2729 if ((root instanceof Document || root instanceof ShadowRoot) && root.getSelection != null) {
2730 return root;
2731 }
2732
2733 return el.ownerDocument;
2734 },
2735
2736 /**
2737 * Check if the editor is focused.
2738 */
2739 isFocused: function isFocused(editor) {
2740 return !!IS_FOCUSED.get(editor);
2741 },
2742
2743 /**
2744 * Check if the editor is in read-only mode.
2745 */
2746 isReadOnly: function isReadOnly(editor) {
2747 return !!IS_READ_ONLY.get(editor);
2748 },
2749
2750 /**
2751 * Blur the editor.
2752 */
2753 blur: function blur(editor) {
2754 var el = ReactEditor.toDOMNode(editor, editor);
2755 var root = ReactEditor.findDocumentOrShadowRoot(editor);
2756 IS_FOCUSED.set(editor, false);
2757
2758 if (root.activeElement === el) {
2759 el.blur();
2760 }
2761 },
2762
2763 /**
2764 * Focus the editor.
2765 */
2766 focus: function focus(editor) {
2767 var el = ReactEditor.toDOMNode(editor, editor);
2768 var root = ReactEditor.findDocumentOrShadowRoot(editor);
2769 IS_FOCUSED.set(editor, true);
2770
2771 if (root.activeElement !== el) {
2772 el.focus({
2773 preventScroll: true
2774 });
2775 }
2776 },
2777
2778 /**
2779 * Deselect the editor.
2780 */
2781 deselect: function deselect(editor) {
2782 ReactEditor.toDOMNode(editor, editor);
2783 var selection = editor.selection;
2784 var root = ReactEditor.findDocumentOrShadowRoot(editor);
2785 var domSelection = root.getSelection();
2786
2787 if (domSelection && domSelection.rangeCount > 0) {
2788 domSelection.removeAllRanges();
2789 }
2790
2791 if (selection) {
2792 slate.Transforms.deselect(editor);
2793 }
2794 },
2795
2796 /**
2797 * Check if a DOM node is within the editor.
2798 */
2799 hasDOMNode: function hasDOMNode(editor, target) {
2800 var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
2801 var _options$editable = options.editable,
2802 editable = _options$editable === void 0 ? false : _options$editable;
2803 var editorEl = ReactEditor.toDOMNode(editor, editor);
2804 var targetEl; // COMPAT: In Firefox, reading `target.nodeType` will throw an error if
2805 // target is originating from an internal "restricted" element (e.g. a
2806 // stepper arrow on a number input). (2018/05/04)
2807 // https://github.com/ianstormtaylor/slate/issues/1819
2808
2809 try {
2810 targetEl = isDOMElement(target) ? target : target.parentElement;
2811 } catch (err) {
2812 if (!err.message.includes('Permission denied to access property "nodeType"')) {
2813 throw err;
2814 }
2815 }
2816
2817 if (!targetEl) {
2818 return false;
2819 }
2820
2821 return targetEl.closest("[data-slate-editor]") === editorEl && (!editable || targetEl.isContentEditable ? true : typeof targetEl.isContentEditable === 'boolean' && // isContentEditable exists only on HTMLElement, and on other nodes it will be undefined
2822 // this is the core logic that lets you know you got the right editor.selection instead of null when editor is contenteditable="false"(readOnly)
2823 targetEl.closest('[contenteditable="false"]') === editorEl || !!targetEl.getAttribute('data-slate-zero-width'));
2824 },
2825
2826 /**
2827 * Insert data from a `DataTransfer` into the editor.
2828 */
2829 insertData: function insertData(editor, data) {
2830 editor.insertData(data);
2831 },
2832
2833 /**
2834 * Insert fragment data from a `DataTransfer` into the editor.
2835 */
2836 insertFragmentData: function insertFragmentData(editor, data) {
2837 return editor.insertFragmentData(data);
2838 },
2839
2840 /**
2841 * Insert text data from a `DataTransfer` into the editor.
2842 */
2843 insertTextData: function insertTextData(editor, data) {
2844 return editor.insertTextData(data);
2845 },
2846
2847 /**
2848 * Sets data from the currently selected fragment on a `DataTransfer`.
2849 */
2850 setFragmentData: function setFragmentData(editor, data, originEvent) {
2851 editor.setFragmentData(data, originEvent);
2852 },
2853
2854 /**
2855 * Find the native DOM element from a Slate node.
2856 */
2857 toDOMNode: function toDOMNode(editor, node) {
2858 var KEY_TO_ELEMENT = EDITOR_TO_KEY_TO_ELEMENT.get(editor);
2859 var domNode = slate.Editor.isEditor(node) ? EDITOR_TO_ELEMENT.get(editor) : KEY_TO_ELEMENT === null || KEY_TO_ELEMENT === void 0 ? void 0 : KEY_TO_ELEMENT.get(ReactEditor.findKey(editor, node));
2860
2861 if (!domNode) {
2862 throw new Error("Cannot resolve a DOM node from Slate node: ".concat(JSON.stringify(node)));
2863 }
2864
2865 return domNode;
2866 },
2867
2868 /**
2869 * Find a native DOM selection point from a Slate point.
2870 */
2871 toDOMPoint: function toDOMPoint(editor, point) {
2872 var _Editor$node = slate.Editor.node(editor, point.path),
2873 _Editor$node2 = _slicedToArray(_Editor$node, 1),
2874 node = _Editor$node2[0];
2875
2876 var el = ReactEditor.toDOMNode(editor, node);
2877 var domPoint; // If we're inside a void node, force the offset to 0, otherwise the zero
2878 // width spacing character will result in an incorrect offset of 1
2879
2880 if (slate.Editor["void"](editor, {
2881 at: point
2882 })) {
2883 point = {
2884 path: point.path,
2885 offset: 0
2886 };
2887 } // For each leaf, we need to isolate its content, which means filtering
2888 // to its direct text and zero-width spans. (We have to filter out any
2889 // other siblings that may have been rendered alongside them.)
2890
2891
2892 var selector = "[data-slate-string], [data-slate-zero-width]";
2893 var texts = Array.from(el.querySelectorAll(selector));
2894 var start = 0;
2895
2896 for (var _i = 0, _texts = texts; _i < _texts.length; _i++) {
2897 var text = _texts[_i];
2898 var domNode = text.childNodes[0];
2899
2900 if (domNode == null || domNode.textContent == null) {
2901 continue;
2902 }
2903
2904 var length = domNode.textContent.length;
2905 var attr = text.getAttribute('data-slate-length');
2906 var trueLength = attr == null ? length : parseInt(attr, 10);
2907 var end = start + trueLength;
2908
2909 if (point.offset <= end) {
2910 var offset = Math.min(length, Math.max(0, point.offset - start));
2911 domPoint = [domNode, offset];
2912 break;
2913 }
2914
2915 start = end;
2916 }
2917
2918 if (!domPoint) {
2919 throw new Error("Cannot resolve a DOM point from Slate point: ".concat(JSON.stringify(point)));
2920 }
2921
2922 return domPoint;
2923 },
2924
2925 /**
2926 * Find a native DOM range from a Slate `range`.
2927 *
2928 * Notice: the returned range will always be ordinal regardless of the direction of Slate `range` due to DOM API limit.
2929 *
2930 * there is no way to create a reverse DOM Range using Range.setStart/setEnd
2931 * according to https://dom.spec.whatwg.org/#concept-range-bp-set.
2932 */
2933 toDOMRange: function toDOMRange(editor, range) {
2934 var anchor = range.anchor,
2935 focus = range.focus;
2936 var isBackward = slate.Range.isBackward(range);
2937 var domAnchor = ReactEditor.toDOMPoint(editor, anchor);
2938 var domFocus = slate.Range.isCollapsed(range) ? domAnchor : ReactEditor.toDOMPoint(editor, focus);
2939 var window = ReactEditor.getWindow(editor);
2940 var domRange = window.document.createRange();
2941
2942 var _ref = isBackward ? domFocus : domAnchor,
2943 _ref2 = _slicedToArray(_ref, 2),
2944 startNode = _ref2[0],
2945 startOffset = _ref2[1];
2946
2947 var _ref3 = isBackward ? domAnchor : domFocus,
2948 _ref4 = _slicedToArray(_ref3, 2),
2949 endNode = _ref4[0],
2950 endOffset = _ref4[1]; // A slate Point at zero-width Leaf always has an offset of 0 but a native DOM selection at
2951 // zero-width node has an offset of 1 so we have to check if we are in a zero-width node and
2952 // adjust the offset accordingly.
2953
2954
2955 var startEl = isDOMElement(startNode) ? startNode : startNode.parentElement;
2956 var isStartAtZeroWidth = !!startEl.getAttribute('data-slate-zero-width');
2957 var endEl = isDOMElement(endNode) ? endNode : endNode.parentElement;
2958 var isEndAtZeroWidth = !!endEl.getAttribute('data-slate-zero-width');
2959 domRange.setStart(startNode, isStartAtZeroWidth ? 1 : startOffset);
2960 domRange.setEnd(endNode, isEndAtZeroWidth ? 1 : endOffset);
2961 return domRange;
2962 },
2963
2964 /**
2965 * Find a Slate node from a native DOM `element`.
2966 */
2967 toSlateNode: function toSlateNode(editor, domNode) {
2968 var domEl = isDOMElement(domNode) ? domNode : domNode.parentElement;
2969
2970 if (domEl && !domEl.hasAttribute('data-slate-node')) {
2971 domEl = domEl.closest("[data-slate-node]");
2972 }
2973
2974 var node = domEl ? ELEMENT_TO_NODE.get(domEl) : null;
2975
2976 if (!node) {
2977 throw new Error("Cannot resolve a Slate node from DOM node: ".concat(domEl));
2978 }
2979
2980 return node;
2981 },
2982
2983 /**
2984 * Get the target range from a DOM `event`.
2985 */
2986 findEventRange: function findEventRange(editor, event) {
2987 if ('nativeEvent' in event) {
2988 event = event.nativeEvent;
2989 }
2990
2991 var _event = event,
2992 x = _event.clientX,
2993 y = _event.clientY,
2994 target = _event.target;
2995
2996 if (x == null || y == null) {
2997 throw new Error("Cannot resolve a Slate range from a DOM event: ".concat(event));
2998 }
2999
3000 var node = ReactEditor.toSlateNode(editor, event.target);
3001 var path = ReactEditor.findPath(editor, node); // If the drop target is inside a void node, move it into either the
3002 // next or previous node, depending on which side the `x` and `y`
3003 // coordinates are closest to.
3004
3005 if (slate.Editor.isVoid(editor, node)) {
3006 var rect = target.getBoundingClientRect();
3007 var isPrev = editor.isInline(node) ? x - rect.left < rect.left + rect.width - x : y - rect.top < rect.top + rect.height - y;
3008 var edge = slate.Editor.point(editor, path, {
3009 edge: isPrev ? 'start' : 'end'
3010 });
3011 var point = isPrev ? slate.Editor.before(editor, edge) : slate.Editor.after(editor, edge);
3012
3013 if (point) {
3014 var _range = slate.Editor.range(editor, point);
3015
3016 return _range;
3017 }
3018 } // Else resolve a range from the caret position where the drop occured.
3019
3020
3021 var domRange;
3022
3023 var _ReactEditor$getWindo = ReactEditor.getWindow(editor),
3024 document = _ReactEditor$getWindo.document; // COMPAT: In Firefox, `caretRangeFromPoint` doesn't exist. (2016/07/25)
3025
3026
3027 if (document.caretRangeFromPoint) {
3028 domRange = document.caretRangeFromPoint(x, y);
3029 } else {
3030 var position = document.caretPositionFromPoint(x, y);
3031
3032 if (position) {
3033 domRange = document.createRange();
3034 domRange.setStart(position.offsetNode, position.offset);
3035 domRange.setEnd(position.offsetNode, position.offset);
3036 }
3037 }
3038
3039 if (!domRange) {
3040 throw new Error("Cannot resolve a Slate range from a DOM event: ".concat(event));
3041 } // Resolve a Slate range from the DOM range.
3042
3043
3044 var range = ReactEditor.toSlateRange(editor, domRange, {
3045 exactMatch: false,
3046 suppressThrow: false
3047 });
3048 return range;
3049 },
3050
3051 /**
3052 * Find a Slate point from a DOM selection's `domNode` and `domOffset`.
3053 */
3054 toSlatePoint: function toSlatePoint(editor, domPoint, options) {
3055 var exactMatch = options.exactMatch,
3056 suppressThrow = options.suppressThrow;
3057
3058 var _ref5 = exactMatch ? domPoint : normalizeDOMPoint(domPoint),
3059 _ref6 = _slicedToArray(_ref5, 2),
3060 nearestNode = _ref6[0],
3061 nearestOffset = _ref6[1];
3062
3063 var parentNode = nearestNode.parentNode;
3064 var textNode = null;
3065 var offset = 0;
3066
3067 if (parentNode) {
3068 var _domNode$textContent;
3069
3070 var voidNode = parentNode.closest('[data-slate-void="true"]');
3071 var leafNode = parentNode.closest('[data-slate-leaf]');
3072 var domNode = null; // Calculate how far into the text node the `nearestNode` is, so that we
3073 // can determine what the offset relative to the text node is.
3074
3075 if (leafNode) {
3076 textNode = leafNode.closest('[data-slate-node="text"]');
3077 var window = ReactEditor.getWindow(editor);
3078 var range = window.document.createRange();
3079 range.setStart(textNode, 0);
3080 range.setEnd(nearestNode, nearestOffset);
3081 var contents = range.cloneContents();
3082 var removals = [].concat(_toConsumableArray(Array.prototype.slice.call(contents.querySelectorAll('[data-slate-zero-width]'))), _toConsumableArray(Array.prototype.slice.call(contents.querySelectorAll('[contenteditable=false]'))));
3083 removals.forEach(function (el) {
3084 el.parentNode.removeChild(el);
3085 }); // COMPAT: Edge has a bug where Range.prototype.toString() will
3086 // convert \n into \r\n. The bug causes a loop when slate-react
3087 // attempts to reposition its cursor to match the native position. Use
3088 // textContent.length instead.
3089 // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/10291116/
3090
3091 offset = contents.textContent.length;
3092 domNode = textNode;
3093 } else if (voidNode) {
3094 // For void nodes, the element with the offset key will be a cousin, not an
3095 // ancestor, so find it by going down from the nearest void parent.
3096 leafNode = voidNode.querySelector('[data-slate-leaf]'); // COMPAT: In read-only editors the leaf is not rendered.
3097
3098 if (!leafNode) {
3099 offset = 1;
3100 } else {
3101 textNode = leafNode.closest('[data-slate-node="text"]');
3102 domNode = leafNode;
3103 offset = domNode.textContent.length;
3104 domNode.querySelectorAll('[data-slate-zero-width]').forEach(function (el) {
3105 offset -= el.textContent.length;
3106 });
3107 }
3108 }
3109
3110 if (domNode && offset === domNode.textContent.length && (parentNode.hasAttribute('data-slate-zero-width') || IS_FIREFOX && (_domNode$textContent = domNode.textContent) !== null && _domNode$textContent !== void 0 && _domNode$textContent.endsWith('\n\n'))) {
3111 offset--;
3112 }
3113 }
3114
3115 if (!textNode) {
3116 if (suppressThrow) {
3117 return null;
3118 }
3119
3120 throw new Error("Cannot resolve a Slate point from DOM point: ".concat(domPoint));
3121 } // COMPAT: If someone is clicking from one Slate editor into another,
3122 // the select event fires twice, once for the old editor's `element`
3123 // first, and then afterwards for the correct `element`. (2017/03/03)
3124
3125
3126 var slateNode = ReactEditor.toSlateNode(editor, textNode);
3127 var path = ReactEditor.findPath(editor, slateNode);
3128 return {
3129 path: path,
3130 offset: offset
3131 };
3132 },
3133
3134 /**
3135 * Find a Slate range from a DOM range or selection.
3136 */
3137 toSlateRange: function toSlateRange(editor, domRange, options) {
3138 var exactMatch = options.exactMatch,
3139 suppressThrow = options.suppressThrow;
3140 var el = isDOMSelection(domRange) ? domRange.anchorNode : domRange.startContainer;
3141 var anchorNode;
3142 var anchorOffset;
3143 var focusNode;
3144 var focusOffset;
3145 var isCollapsed;
3146
3147 if (el) {
3148 if (isDOMSelection(domRange)) {
3149 anchorNode = domRange.anchorNode;
3150 anchorOffset = domRange.anchorOffset;
3151 focusNode = domRange.focusNode;
3152 focusOffset = domRange.focusOffset; // COMPAT: There's a bug in chrome that always returns `true` for
3153 // `isCollapsed` for a Selection that comes from a ShadowRoot.
3154 // (2020/08/08)
3155 // https://bugs.chromium.org/p/chromium/issues/detail?id=447523
3156
3157 if (IS_CHROME && hasShadowRoot()) {
3158 isCollapsed = domRange.anchorNode === domRange.focusNode && domRange.anchorOffset === domRange.focusOffset;
3159 } else {
3160 isCollapsed = domRange.isCollapsed;
3161 }
3162 } else {
3163 anchorNode = domRange.startContainer;
3164 anchorOffset = domRange.startOffset;
3165 focusNode = domRange.endContainer;
3166 focusOffset = domRange.endOffset;
3167 isCollapsed = domRange.collapsed;
3168 }
3169 }
3170
3171 if (anchorNode == null || focusNode == null || anchorOffset == null || focusOffset == null) {
3172 throw new Error("Cannot resolve a Slate range from DOM range: ".concat(domRange));
3173 }
3174
3175 var anchor = ReactEditor.toSlatePoint(editor, [anchorNode, anchorOffset], {
3176 exactMatch: exactMatch,
3177 suppressThrow: suppressThrow
3178 });
3179
3180 if (!anchor) {
3181 return null;
3182 }
3183
3184 var focus = isCollapsed ? anchor : ReactEditor.toSlatePoint(editor, [focusNode, focusOffset], {
3185 exactMatch: exactMatch,
3186 suppressThrow: suppressThrow
3187 });
3188
3189 if (!focus) {
3190 return null;
3191 }
3192
3193 var range = {
3194 anchor: anchor,
3195 focus: focus
3196 }; // if the selection is a hanging range that ends in a void
3197 // and the DOM focus is an Element
3198 // (meaning that the selection ends before the element)
3199 // unhang the range to avoid mistakenly including the void
3200
3201 if (slate.Range.isExpanded(range) && slate.Range.isForward(range) && isDOMElement(focusNode) && slate.Editor["void"](editor, {
3202 at: range.focus,
3203 mode: 'highest'
3204 })) {
3205 range = slate.Editor.unhangRange(editor, range, {
3206 voids: true
3207 });
3208 }
3209
3210 return range;
3211 },
3212 hasRange: function hasRange(editor, range) {
3213 var anchor = range.anchor,
3214 focus = range.focus;
3215 return slate.Editor.hasPath(editor, anchor.path) && slate.Editor.hasPath(editor, focus.path);
3216 }
3217};
3218
3219function gatherMutationData(editor, mutations) {
3220 var addedNodes = [];
3221 var removedNodes = [];
3222 var insertedText = [];
3223 var characterDataMutations = [];
3224 mutations.forEach(function (mutation) {
3225 switch (mutation.type) {
3226 case 'childList':
3227 {
3228 if (mutation.addedNodes.length) {
3229 mutation.addedNodes.forEach(function (addedNode) {
3230 addedNodes.push(addedNode);
3231 });
3232 }
3233
3234 mutation.removedNodes.forEach(function (removedNode) {
3235 removedNodes.push(removedNode);
3236 });
3237 break;
3238 }
3239
3240 case 'characterData':
3241 {
3242 characterDataMutations.push(mutation); // Changes to text nodes should consider the parent element
3243
3244 var parentNode = mutation.target.parentNode;
3245
3246 if (!parentNode) {
3247 return;
3248 }
3249
3250 var textInsertion = getTextInsertion(editor, parentNode);
3251
3252 if (!textInsertion) {
3253 return;
3254 } // If we've already detected a diff at that path, we can return early
3255
3256
3257 if (insertedText.some(function (_ref) {
3258 var path = _ref.path;
3259 return slate.Path.equals(path, textInsertion.path);
3260 })) {
3261 return;
3262 } // Add the text diff to the array of detected text insertions that need to be reconciled
3263
3264
3265 insertedText.push(textInsertion);
3266 }
3267 }
3268 });
3269 return {
3270 addedNodes: addedNodes,
3271 removedNodes: removedNodes,
3272 insertedText: insertedText,
3273 characterDataMutations: characterDataMutations
3274 };
3275}
3276/**
3277 * In general, when a line break occurs, there will be more `addedNodes` than `removedNodes`.
3278 *
3279 * This isn't always the case however. In some cases, there will be more `removedNodes` than
3280 * `addedNodes`.
3281 *
3282 * To account for these edge cases, the most reliable strategy to detect line break mutations
3283 * is to check whether a new block was inserted of the same type as the current block.
3284 */
3285
3286var isLineBreak = function isLineBreak(editor, _ref2) {
3287 var addedNodes = _ref2.addedNodes;
3288 var selection = editor.selection;
3289 var parentNode = selection ? slate.Node.parent(editor, selection.anchor.path) : null;
3290 var parentDOMNode = parentNode ? ReactEditor.toDOMNode(editor, parentNode) : null;
3291
3292 if (!parentDOMNode) {
3293 return false;
3294 }
3295
3296 return addedNodes.some(function (addedNode) {
3297 return addedNode instanceof HTMLElement && addedNode.tagName === (parentDOMNode === null || parentDOMNode === void 0 ? void 0 : parentDOMNode.tagName);
3298 });
3299};
3300/**
3301 * So long as we check for line break mutations before deletion mutations,
3302 * we can safely assume that a set of mutations was a deletion if there are
3303 * removed nodes.
3304 */
3305
3306var isDeletion = function isDeletion(_, _ref3) {
3307 var removedNodes = _ref3.removedNodes;
3308 return removedNodes.length > 0;
3309};
3310/**
3311 * If the selection was expanded and there are removed nodes,
3312 * the contents of the selection need to be replaced with the diff
3313 */
3314
3315var isReplaceExpandedSelection = function isReplaceExpandedSelection(_ref4, _ref5) {
3316 var selection = _ref4.selection;
3317 var removedNodes = _ref5.removedNodes;
3318 return selection ? slate.Range.isExpanded(selection) && removedNodes.length > 0 : false;
3319};
3320/**
3321 * Plain text insertion
3322 */
3323
3324var isTextInsertion = function isTextInsertion(_, _ref6) {
3325 var insertedText = _ref6.insertedText;
3326 return insertedText.length > 0;
3327};
3328/**
3329 * Edge case. Detect mutations that remove leaf nodes and also update character data
3330 */
3331
3332var isRemoveLeafNodes = function isRemoveLeafNodes(_, _ref7) {
3333 var addedNodes = _ref7.addedNodes,
3334 characterDataMutations = _ref7.characterDataMutations,
3335 removedNodes = _ref7.removedNodes;
3336 return removedNodes.length > 0 && addedNodes.length === 0 && characterDataMutations.length > 0;
3337};
3338
3339function _createForOfIteratorHelper$1(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray$1(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
3340
3341function _unsupportedIterableToArray$1(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray$1(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$1(o, minLen); }
3342
3343function _arrayLikeToArray$1(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
3344/**
3345 * Based loosely on:
3346 *
3347 * https://github.com/facebook/draft-js/blob/master/src/component/handlers/composition/DOMObserver.js
3348 * https://github.com/ProseMirror/prosemirror-view/blob/master/src/domobserver.js
3349 *
3350 * The input manager attempts to map observed mutations on the document to a
3351 * set of operations in order to reconcile Slate's internal value with the DOM.
3352 *
3353 * Mutations are processed synchronously as they come in. Only mutations that occur
3354 * during a user input loop are processed, as other mutations can occur within the
3355 * document that were not initiated by user input.
3356 *
3357 * The mutation reconciliation process attempts to match mutations to the following
3358 * patterns:
3359 *
3360 * - Text updates
3361 * - Deletions
3362 * - Line breaks
3363 *
3364 * @param editor
3365 * @param restoreDOM
3366 */
3367
3368
3369var AndroidInputManager = function AndroidInputManager(editor, restoreDOM) {
3370 var _this = this;
3371
3372 _classCallCheck(this, AndroidInputManager);
3373
3374 this.editor = editor;
3375 this.restoreDOM = restoreDOM;
3376 /**
3377 * Handle MutationObserver flush
3378 *
3379 * @param mutations
3380 */
3381
3382 this.flush = function (mutations) {
3383
3384 try {
3385 _this.reconcileMutations(mutations);
3386 } catch (err) {
3387 // eslint-disable-next-line no-console
3388 console.error(err); // Failed to reconcile mutations, restore DOM to its previous state
3389
3390 _this.restoreDOM();
3391 }
3392 };
3393 /**
3394 * Reconcile a batch of mutations
3395 *
3396 * @param mutations
3397 */
3398
3399
3400 this.reconcileMutations = function (mutations) {
3401 var mutationData = gatherMutationData(_this.editor, mutations);
3402 var insertedText = mutationData.insertedText,
3403 removedNodes = mutationData.removedNodes;
3404
3405 if (isReplaceExpandedSelection(_this.editor, mutationData)) {
3406 var text = combineInsertedText(insertedText);
3407
3408 _this.replaceExpandedSelection(text);
3409 } else if (isLineBreak(_this.editor, mutationData)) {
3410 _this.insertBreak();
3411 } else if (isRemoveLeafNodes(_this.editor, mutationData)) {
3412 _this.removeLeafNodes(removedNodes);
3413 } else if (isDeletion(_this.editor, mutationData)) {
3414 _this.deleteBackward();
3415 } else if (isTextInsertion(_this.editor, mutationData)) {
3416 _this.insertText(insertedText);
3417 }
3418 };
3419 /**
3420 * Apply text diff
3421 */
3422
3423
3424 this.insertText = function (insertedText) {
3425 var selection = _this.editor.selection; // If it is in composing or after `onCompositionend`, set `EDITOR_ON_COMPOSITION_TEXT` and return.
3426 // Text will be inserted on compositionend event.
3427
3428 if (IS_COMPOSING.get(_this.editor) || IS_ON_COMPOSITION_END.get(_this.editor)) {
3429 EDITOR_ON_COMPOSITION_TEXT.set(_this.editor, insertedText);
3430 IS_ON_COMPOSITION_END.set(_this.editor, false);
3431 return;
3432 } // Insert the batched text diffs
3433
3434
3435 insertedText.forEach(function (insertion) {
3436 var text = insertion.text.insertText;
3437 var at = normalizeTextInsertionRange(_this.editor, selection, insertion);
3438 slate.Transforms.setSelection(_this.editor, at);
3439 slate.Editor.insertText(_this.editor, text);
3440 });
3441 };
3442 /**
3443 * Handle line breaks
3444 */
3445
3446
3447 this.insertBreak = function () {
3448 var selection = _this.editor.selection;
3449 slate.Editor.insertBreak(_this.editor);
3450
3451 _this.restoreDOM();
3452
3453 if (selection) {
3454 // Compat: Move selection to the newly inserted block if it has not moved
3455 setTimeout(function () {
3456 if (_this.editor.selection && slate.Range.equals(selection, _this.editor.selection)) {
3457 slate.Transforms.move(_this.editor);
3458 }
3459 }, 100);
3460 }
3461 };
3462 /**
3463 * Handle expanded selection being deleted or replaced by text
3464 */
3465
3466
3467 this.replaceExpandedSelection = function (text) {
3468
3469 slate.Editor.deleteFragment(_this.editor);
3470
3471 if (text.length) {
3472 // Selection was replaced by text, insert the entire text diff
3473 slate.Editor.insertText(_this.editor, text);
3474 }
3475
3476 _this.restoreDOM();
3477 };
3478 /**
3479 * Handle `backspace` that merges blocks
3480 */
3481
3482
3483 this.deleteBackward = function () {
3484 slate.Editor.deleteBackward(_this.editor);
3485 ReactEditor.focus(_this.editor);
3486
3487 _this.restoreDOM();
3488 };
3489 /**
3490 * Handle mutations that remove specific leaves
3491 */
3492
3493
3494 this.removeLeafNodes = function (nodes) {
3495 var _iterator = _createForOfIteratorHelper$1(nodes),
3496 _step;
3497
3498 try {
3499 for (_iterator.s(); !(_step = _iterator.n()).done;) {
3500 var node = _step.value;
3501 var slateNode = ReactEditor.toSlateNode(_this.editor, node);
3502
3503 if (slateNode) {
3504 var path = ReactEditor.findPath(_this.editor, slateNode);
3505 slate.Transforms["delete"](_this.editor, {
3506 at: path
3507 });
3508
3509 _this.restoreDOM();
3510 }
3511 }
3512 } catch (err) {
3513 _iterator.e(err);
3514 } finally {
3515 _iterator.f();
3516 }
3517 };
3518
3519 this.editor = editor;
3520 this.restoreDOM = restoreDOM;
3521};
3522
3523function useMutationObserver(node, callback, options) {
3524 var _useState = React.useState(function () {
3525 return new MutationObserver(callback);
3526 }),
3527 _useState2 = _slicedToArray(_useState, 1),
3528 mutationObserver = _useState2[0];
3529
3530 useIsomorphicLayoutEffect(function () {
3531 // Disconnect mutation observer during render phase
3532 mutationObserver.disconnect();
3533 });
3534 React.useEffect(function () {
3535 if (!node.current) {
3536 throw new Error('Failed to attach MutationObserver, `node` is undefined');
3537 } // Attach mutation observer after render phase has finished
3538
3539
3540 mutationObserver.observe(node.current, options); // Clean up after effect
3541
3542 return mutationObserver.disconnect.bind(mutationObserver);
3543 });
3544}
3545
3546var MUTATION_OBSERVER_CONFIG$1 = {
3547 childList: true,
3548 characterData: true,
3549 subtree: true
3550};
3551
3552function findClosestKnowSlateNode(domNode) {
3553 var _domEl;
3554
3555 var domEl = isDOMElement(domNode) ? domNode : domNode.parentElement;
3556
3557 if (domEl && !domEl.hasAttribute('data-slate-node')) {
3558 domEl = domEl.closest("[data-slate-node]");
3559 }
3560
3561 var slateNode = domEl && ELEMENT_TO_NODE.get(domEl);
3562
3563 if (slateNode) {
3564 return slateNode;
3565 } // Unknown dom element with a slate-slate-node attribute => the IME
3566 // most likely duplicated the node so we have to restore the parent
3567
3568
3569 return (_domEl = domEl) !== null && _domEl !== void 0 && _domEl.parentElement ? findClosestKnowSlateNode(domEl.parentElement) : null;
3570}
3571
3572function useRestoreDom(node, receivedUserInput) {
3573 var editor = useSlateStatic();
3574 var mutatedNodes = React.useRef(new Set());
3575 var handleDOMMutation = React.useCallback(function (mutations) {
3576 if (!receivedUserInput.current) {
3577 return;
3578 }
3579
3580 mutations.forEach(function (_ref) {
3581 var target = _ref.target;
3582 var slateNode = findClosestKnowSlateNode(target);
3583
3584 if (!slateNode) {
3585 return;
3586 }
3587
3588 return mutatedNodes.current.add(slateNode);
3589 });
3590 }, []);
3591 useMutationObserver(node, handleDOMMutation, MUTATION_OBSERVER_CONFIG$1); // Clear mutated nodes on every render
3592
3593 mutatedNodes.current.clear();
3594 var restore = React.useCallback(function () {
3595 var mutated = Array.from(mutatedNodes.current.values()); // Filter out child nodes of nodes that will be restored anyway
3596
3597 var nodesToRestore = mutated.filter(function (n) {
3598 return !mutated.some(function (m) {
3599 return slate.Path.isParent(ReactEditor.findPath(editor, m), ReactEditor.findPath(editor, n));
3600 });
3601 });
3602 nodesToRestore.forEach(function (n) {
3603 var _NODE_TO_RESTORE_DOM$;
3604
3605 (_NODE_TO_RESTORE_DOM$ = NODE_TO_RESTORE_DOM.get(n)) === null || _NODE_TO_RESTORE_DOM$ === void 0 ? void 0 : _NODE_TO_RESTORE_DOM$();
3606 });
3607 mutatedNodes.current.clear();
3608 }, []);
3609 return restore;
3610}
3611
3612function useTrackUserInput() {
3613 var editor = useSlateStatic();
3614 var receivedUserInput = React.useRef(false);
3615 var animationFrameRef = React.useRef(null);
3616 var onUserInput = React.useCallback(function () {
3617 if (receivedUserInput.current === false) {
3618 var window = ReactEditor.getWindow(editor);
3619 receivedUserInput.current = true;
3620
3621 if (animationFrameRef.current) {
3622 window.cancelAnimationFrame(animationFrameRef.current);
3623 }
3624
3625 animationFrameRef.current = window.requestAnimationFrame(function () {
3626 receivedUserInput.current = false;
3627 animationFrameRef.current = null;
3628 });
3629 }
3630 }, []);
3631 React.useEffect(function () {
3632 // Reset user input tracking on every render
3633 if (receivedUserInput.current) {
3634 receivedUserInput.current = false;
3635 }
3636 });
3637 return {
3638 receivedUserInput: receivedUserInput,
3639 onUserInput: onUserInput
3640 };
3641}
3642
3643var MUTATION_OBSERVER_CONFIG = {
3644 childList: true,
3645 characterData: true,
3646 characterDataOldValue: true,
3647 subtree: true
3648};
3649function useAndroidInputManager(node) {
3650 var editor = useSlateStatic();
3651
3652 var _useTrackUserInput = useTrackUserInput(),
3653 receivedUserInput = _useTrackUserInput.receivedUserInput,
3654 onUserInput = _useTrackUserInput.onUserInput;
3655
3656 var restoreDom = useRestoreDom(node, receivedUserInput);
3657 var inputManager = React.useMemo(function () {
3658 return new AndroidInputManager(editor, restoreDom);
3659 }, [restoreDom, editor]);
3660 var timeoutId = React.useRef(null);
3661 var isReconciling = React.useRef(false);
3662 var flush = React.useCallback(function (mutations) {
3663 if (!receivedUserInput.current) {
3664 return;
3665 }
3666
3667 isReconciling.current = true;
3668 inputManager.flush(mutations);
3669
3670 if (timeoutId.current) {
3671 clearTimeout(timeoutId.current);
3672 }
3673
3674 timeoutId.current = setTimeout(function () {
3675 isReconciling.current = false;
3676 timeoutId.current = null;
3677 }, 250);
3678 }, []);
3679 useMutationObserver(node, flush, MUTATION_OBSERVER_CONFIG);
3680 return {
3681 isReconciling: isReconciling,
3682 onUserInput: onUserInput
3683 };
3684}
3685
3686var _excluded$1 = ["autoFocus", "decorate", "onDOMBeforeInput", "placeholder", "readOnly", "renderElement", "renderLeaf", "renderPlaceholder", "style", "as"];
3687
3688function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
3689
3690function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
3691/**
3692 * Editable.
3693 */
3694// https://github.com/facebook/draft-js/blob/main/src/component/handlers/composition/DraftEditorCompositionHandler.js#L41
3695// When using keyboard English association function, conpositionEnd triggered too fast, resulting in after `insertText` still maintain association state.
3696
3697var RESOLVE_DELAY = 20;
3698var AndroidEditable = function AndroidEditable(props) {
3699 var autoFocus = props.autoFocus,
3700 _props$decorate = props.decorate,
3701 decorate = _props$decorate === void 0 ? defaultDecorate : _props$decorate,
3702 propsOnDOMBeforeInput = props.onDOMBeforeInput,
3703 placeholder = props.placeholder,
3704 _props$readOnly = props.readOnly,
3705 readOnly = _props$readOnly === void 0 ? false : _props$readOnly,
3706 renderElement = props.renderElement,
3707 renderLeaf = props.renderLeaf,
3708 _props$renderPlacehol = props.renderPlaceholder,
3709 renderPlaceholder = _props$renderPlacehol === void 0 ? function (props) {
3710 return /*#__PURE__*/React__default['default'].createElement(DefaultPlaceholder, Object.assign({}, props));
3711 } : _props$renderPlacehol,
3712 _props$style = props.style,
3713 style = _props$style === void 0 ? {} : _props$style,
3714 _props$as = props.as,
3715 Component = _props$as === void 0 ? 'div' : _props$as,
3716 attributes = _objectWithoutProperties(props, _excluded$1);
3717
3718 var editor = useSlate(); // Rerender editor when composition status changed
3719
3720 var _useState = React.useState(false),
3721 _useState2 = _slicedToArray(_useState, 2),
3722 isComposing = _useState2[0],
3723 setIsComposing = _useState2[1];
3724
3725 var ref = React.useRef(null);
3726 var inputManager = useAndroidInputManager(ref); // Update internal state on each render.
3727
3728 IS_READ_ONLY.set(editor, readOnly); // Keep track of some state for the event handler logic.
3729
3730 var state = React.useMemo(function () {
3731 return {
3732 isComposing: false,
3733 isUpdatingSelection: false,
3734 latestElement: null
3735 };
3736 }, []);
3737 var contentKey = useContentKey(editor); // Whenever the editor updates...
3738
3739 useIsomorphicLayoutEffect(function () {
3740 // Update element-related weak maps with the DOM element ref.
3741 var window;
3742
3743 if (ref.current && (window = getDefaultView(ref.current))) {
3744 EDITOR_TO_WINDOW.set(editor, window);
3745 EDITOR_TO_ELEMENT.set(editor, ref.current);
3746 NODE_TO_ELEMENT.set(editor, ref.current);
3747 ELEMENT_TO_NODE.set(ref.current, editor);
3748 } else {
3749 NODE_TO_ELEMENT["delete"](editor);
3750 }
3751
3752 try {
3753 // Make sure the DOM selection state is in sync.
3754 var selection = editor.selection;
3755 var root = ReactEditor.findDocumentOrShadowRoot(editor);
3756 var domSelection = root.getSelection();
3757
3758 if (state.isComposing || !domSelection || !ReactEditor.isFocused(editor)) {
3759 return;
3760 }
3761
3762 var hasDomSelection = domSelection.type !== 'None'; // If the DOM selection is properly unset, we're done.
3763
3764 if (!selection && !hasDomSelection) {
3765 return;
3766 } // verify that the dom selection is in the editor
3767
3768
3769 var editorElement = EDITOR_TO_ELEMENT.get(editor);
3770 var hasDomSelectionInEditor = false;
3771
3772 if (editorElement.contains(domSelection.anchorNode) && editorElement.contains(domSelection.focusNode)) {
3773 hasDomSelectionInEditor = true;
3774 } // If the DOM selection is in the editor and the editor selection is already correct, we're done.
3775
3776
3777 if (hasDomSelection && hasDomSelectionInEditor && selection) {
3778 var slateRange = ReactEditor.toSlateRange(editor, domSelection, {
3779 exactMatch: true,
3780 suppressThrow: true
3781 });
3782
3783 if (slateRange && slate.Range.equals(slateRange, selection)) {
3784 return;
3785 }
3786 } // when <Editable/> is being controlled through external value
3787 // then its children might just change - DOM responds to it on its own
3788 // but Slate's value is not being updated through any operation
3789 // and thus it doesn't transform selection on its own
3790
3791
3792 if (selection && !ReactEditor.hasRange(editor, selection)) {
3793 editor.selection = ReactEditor.toSlateRange(editor, domSelection, {
3794 exactMatch: false,
3795 suppressThrow: false
3796 });
3797 return;
3798 } // Otherwise the DOM selection is out of sync, so update it.
3799
3800
3801 var el = ReactEditor.toDOMNode(editor, editor);
3802 state.isUpdatingSelection = true;
3803 var newDomRange = selection && ReactEditor.toDOMRange(editor, selection);
3804
3805 if (newDomRange) {
3806 if (slate.Range.isBackward(selection)) {
3807 domSelection.setBaseAndExtent(newDomRange.endContainer, newDomRange.endOffset, newDomRange.startContainer, newDomRange.startOffset);
3808 } else {
3809 domSelection.setBaseAndExtent(newDomRange.startContainer, newDomRange.startOffset, newDomRange.endContainer, newDomRange.endOffset);
3810 }
3811
3812 var leafEl = newDomRange.startContainer.parentElement;
3813 leafEl.getBoundingClientRect = newDomRange.getBoundingClientRect.bind(newDomRange);
3814 scrollIntoView__default['default'](leafEl, {
3815 scrollMode: 'if-needed',
3816 boundary: el
3817 }); // @ts-ignore
3818
3819 delete leafEl.getBoundingClientRect;
3820 } else {
3821 domSelection.removeAllRanges();
3822 }
3823
3824 setTimeout(function () {
3825 state.isUpdatingSelection = false;
3826 });
3827 } catch (_unused) {
3828 // Failed to update selection, likely due to reconciliation error
3829 state.isUpdatingSelection = false;
3830 }
3831 }); // The autoFocus TextareaHTMLAttribute doesn't do anything on a div, so it
3832 // needs to be manually focused.
3833
3834 React.useEffect(function () {
3835 if (ref.current && autoFocus) {
3836 ref.current.focus();
3837 }
3838 }, [autoFocus]); // Listen on the native `selectionchange` event to be able to update any time
3839 // the selection changes. This is required because React's `onSelect` is leaky
3840 // and non-standard so it doesn't fire until after a selection has been
3841 // released. This causes issues in situations where another change happens
3842 // while a selection is being dragged.
3843
3844 var onDOMSelectionChange = React.useCallback(throttle__default['default'](function () {
3845 try {
3846 if (!state.isComposing && !state.isUpdatingSelection && !inputManager.isReconciling.current) {
3847 var root = ReactEditor.findDocumentOrShadowRoot(editor);
3848 var activeElement = root.activeElement;
3849 var el = ReactEditor.toDOMNode(editor, editor);
3850 var domSelection = root.getSelection();
3851
3852 if (activeElement === el) {
3853 state.latestElement = activeElement;
3854 IS_FOCUSED.set(editor, true);
3855 } else {
3856 IS_FOCUSED["delete"](editor);
3857 }
3858
3859 if (!domSelection) {
3860 return slate.Transforms.deselect(editor);
3861 }
3862
3863 var anchorNode = domSelection.anchorNode,
3864 focusNode = domSelection.focusNode;
3865 var anchorNodeSelectable = hasEditableTarget(editor, anchorNode) || isTargetInsideNonReadonlyVoid(editor, anchorNode);
3866 var focusNodeSelectable = hasEditableTarget(editor, focusNode) || isTargetInsideNonReadonlyVoid(editor, focusNode);
3867
3868 if (anchorNodeSelectable && focusNodeSelectable) {
3869 var range = ReactEditor.toSlateRange(editor, domSelection, {
3870 exactMatch: false,
3871 suppressThrow: false
3872 });
3873 slate.Transforms.select(editor, range);
3874 } else {
3875 slate.Transforms.deselect(editor);
3876 }
3877 }
3878 } catch (_unused2) {// Failed to update selection, likely due to reconciliation error
3879 }
3880 }, 100), [readOnly]);
3881 var scheduleOnDOMSelectionChange = React.useMemo(function () {
3882 return debounce__default['default'](onDOMSelectionChange, 0);
3883 }, [onDOMSelectionChange]); // Listen on the native `beforeinput` event to get real "Level 2" events. This
3884 // is required because React's `beforeinput` is fake and never really attaches
3885 // to the real event sadly. (2019/11/01)
3886 // https://github.com/facebook/react/issues/11211
3887
3888 var onDOMBeforeInput = React.useCallback(function (event) {
3889 if (!readOnly && hasEditableTarget(editor, event.target) && !isDOMEventHandled(event, propsOnDOMBeforeInput)) {
3890 // Some IMEs/Chrome extensions like e.g. Grammarly set the selection immediately before
3891 // triggering a `beforeinput` expecting the change to be applied to the immediately before
3892 // set selection.
3893 scheduleOnDOMSelectionChange.flush();
3894 inputManager.onUserInput();
3895 }
3896 }, [readOnly, propsOnDOMBeforeInput]); // Attach a native DOM event handler for `beforeinput` events, because React's
3897 // built-in `onBeforeInput` is actually a leaky polyfill that doesn't expose
3898 // real `beforeinput` events sadly... (2019/11/04)
3899
3900 useIsomorphicLayoutEffect(function () {
3901 var node = ref.current; // @ts-ignore The `beforeinput` event isn't recognized.
3902
3903 node === null || node === void 0 ? void 0 : node.addEventListener('beforeinput', onDOMBeforeInput); // @ts-ignore The `beforeinput` event isn't recognized.
3904
3905 return function () {
3906 return node === null || node === void 0 ? void 0 : node.removeEventListener('beforeinput', onDOMBeforeInput);
3907 };
3908 }, [contentKey, propsOnDOMBeforeInput]); // Attach a native DOM event handler for `selectionchange`, because React's
3909 // built-in `onSelect` handler doesn't fire for all selection changes. It's a
3910 // leaky polyfill that only fires on keypresses or clicks. Instead, we want to
3911 // fire for any change to the selection inside the editor. (2019/11/04)
3912 // https://github.com/facebook/react/issues/5785
3913
3914 useIsomorphicLayoutEffect(function () {
3915 var window = ReactEditor.getWindow(editor);
3916 window.document.addEventListener('selectionchange', scheduleOnDOMSelectionChange);
3917 return function () {
3918 window.document.removeEventListener('selectionchange', scheduleOnDOMSelectionChange);
3919 };
3920 }, [scheduleOnDOMSelectionChange]);
3921 var decorations = decorate([editor, []]);
3922
3923 if (placeholder && editor.children.length === 1 && Array.from(slate.Node.texts(editor)).length === 1 && slate.Node.string(editor) === '' && !isComposing) {
3924 var _decorations$push;
3925
3926 var start = slate.Editor.start(editor, []);
3927 decorations.push((_decorations$push = {}, _defineProperty(_decorations$push, PLACEHOLDER_SYMBOL, true), _defineProperty(_decorations$push, "placeholder", placeholder), _defineProperty(_decorations$push, "anchor", start), _defineProperty(_decorations$push, "focus", start), _decorations$push));
3928 }
3929
3930 return /*#__PURE__*/React__default['default'].createElement(ReadOnlyContext.Provider, {
3931 value: readOnly
3932 }, /*#__PURE__*/React__default['default'].createElement(DecorateContext.Provider, {
3933 value: decorate
3934 }, /*#__PURE__*/React__default['default'].createElement(Component, Object.assign({
3935 key: contentKey,
3936 role: readOnly ? undefined : 'textbox'
3937 }, attributes, {
3938 spellCheck: attributes.spellCheck,
3939 autoCorrect: attributes.autoCorrect,
3940 autoCapitalize: attributes.autoCapitalize,
3941 "data-slate-editor": true,
3942 "data-slate-node": "value",
3943 contentEditable: readOnly ? undefined : true,
3944 suppressContentEditableWarning: true,
3945 ref: ref,
3946 style: _objectSpread({
3947 // Allow positioning relative to the editable element.
3948 position: 'relative',
3949 // Prevent the default outline styles.
3950 outline: 'none',
3951 // Preserve adjacent whitespace and new lines.
3952 whiteSpace: 'pre-wrap',
3953 // Allow words to break if they are too long.
3954 wordWrap: 'break-word'
3955 }, style),
3956 onCopy: React.useCallback(function (event) {
3957 if (hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onCopy)) {
3958 event.preventDefault();
3959 ReactEditor.setFragmentData(editor, event.clipboardData, 'copy');
3960 }
3961 }, [attributes.onCopy]),
3962 onCut: React.useCallback(function (event) {
3963 if (!readOnly && hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onCut)) {
3964 event.preventDefault();
3965 ReactEditor.setFragmentData(editor, event.clipboardData, 'cut');
3966 var selection = editor.selection;
3967
3968 if (selection) {
3969 if (slate.Range.isExpanded(selection)) {
3970 slate.Editor.deleteFragment(editor);
3971 } else {
3972 var node = slate.Node.parent(editor, selection.anchor.path);
3973
3974 if (slate.Editor.isVoid(editor, node)) {
3975 slate.Transforms["delete"](editor);
3976 }
3977 }
3978 }
3979 }
3980 }, [readOnly, attributes.onCut]),
3981 onFocus: React.useCallback(function (event) {
3982 if (!readOnly && !state.isUpdatingSelection && hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onFocus)) {
3983 var root = ReactEditor.findDocumentOrShadowRoot(editor);
3984 state.latestElement = root.activeElement;
3985 IS_FOCUSED.set(editor, true);
3986 }
3987 }, [readOnly, attributes.onFocus]),
3988 onBlur: React.useCallback(function (event) {
3989 if (readOnly || state.isUpdatingSelection || !hasEditableTarget(editor, event.target) || isEventHandled(event, attributes.onBlur)) {
3990 return;
3991 } // COMPAT: If the current `activeElement` is still the previous
3992 // one, this is due to the window being blurred when the tab
3993 // itself becomes unfocused, so we want to abort early to allow to
3994 // editor to stay focused when the tab becomes focused again.
3995
3996
3997 var root = ReactEditor.findDocumentOrShadowRoot(editor);
3998
3999 if (state.latestElement === root.activeElement) {
4000 return;
4001 }
4002
4003 var relatedTarget = event.relatedTarget;
4004 var el = ReactEditor.toDOMNode(editor, editor); // COMPAT: The event should be ignored if the focus is returning
4005 // to the editor from an embedded editable element (eg. an <input>
4006 // element inside a void node).
4007
4008 if (relatedTarget === el) {
4009 return;
4010 } // COMPAT: The event should be ignored if the focus is moving from
4011 // the editor to inside a void node's spacer element.
4012
4013
4014 if (isDOMElement(relatedTarget) && relatedTarget.hasAttribute('data-slate-spacer')) {
4015 return;
4016 } // COMPAT: The event should be ignored if the focus is moving to a
4017 // non- editable section of an element that isn't a void node (eg.
4018 // a list item of the check list example).
4019
4020
4021 if (relatedTarget != null && isDOMNode(relatedTarget) && ReactEditor.hasDOMNode(editor, relatedTarget)) {
4022 var node = ReactEditor.toSlateNode(editor, relatedTarget);
4023
4024 if (slate.Element.isElement(node) && !editor.isVoid(node)) {
4025 return;
4026 }
4027 }
4028
4029 IS_FOCUSED["delete"](editor);
4030 }, [readOnly, attributes.onBlur]),
4031 onClick: React.useCallback(function (event) {
4032 if (!readOnly && hasTarget(editor, event.target) && !isEventHandled(event, attributes.onClick) && isDOMNode(event.target)) {
4033 var node = ReactEditor.toSlateNode(editor, event.target);
4034 var path = ReactEditor.findPath(editor, node); // At this time, the Slate document may be arbitrarily different,
4035 // because onClick handlers can change the document before we get here.
4036 // Therefore we must check that this path actually exists,
4037 // and that it still refers to the same node.
4038
4039 if (slate.Editor.hasPath(editor, path)) {
4040 var lookupNode = slate.Node.get(editor, path);
4041
4042 if (lookupNode === node) {
4043 var _start = slate.Editor.start(editor, path);
4044
4045 var end = slate.Editor.end(editor, path);
4046 var startVoid = slate.Editor["void"](editor, {
4047 at: _start
4048 });
4049 var endVoid = slate.Editor["void"](editor, {
4050 at: end
4051 });
4052
4053 if (startVoid && endVoid && slate.Path.equals(startVoid[1], endVoid[1])) {
4054 var range = slate.Editor.range(editor, _start);
4055 slate.Transforms.select(editor, range);
4056 }
4057 }
4058 }
4059 }
4060 }, [readOnly, attributes.onClick]),
4061 onCompositionEnd: React.useCallback(function (event) {
4062 if (hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onCompositionEnd)) {
4063 scheduleOnDOMSelectionChange.flush();
4064 setTimeout(function () {
4065 state.isComposing && setIsComposing(false);
4066 state.isComposing = false;
4067 IS_COMPOSING.set(editor, false);
4068 IS_ON_COMPOSITION_END.set(editor, true);
4069 var insertedText = EDITOR_ON_COMPOSITION_TEXT.get(editor) || []; // `insertedText` is set in `MutationObserver` constructor.
4070 // If open phone keyboard association function, `CompositionEvent` will be triggered.
4071
4072 if (!insertedText.length) {
4073 return;
4074 }
4075
4076 EDITOR_ON_COMPOSITION_TEXT.set(editor, []);
4077 var selection = editor.selection;
4078 insertedText.forEach(function (insertion) {
4079 var text = insertion.text.insertText;
4080 var at = normalizeTextInsertionRange(editor, selection, insertion);
4081 slate.Transforms.setSelection(editor, at);
4082 slate.Editor.insertText(editor, text);
4083 });
4084 }, RESOLVE_DELAY);
4085 }
4086 }, [attributes.onCompositionEnd]),
4087 onCompositionUpdate: React.useCallback(function (event) {
4088 if (hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onCompositionUpdate)) {
4089 !state.isComposing && setIsComposing(true);
4090 state.isComposing = true;
4091 IS_COMPOSING.set(editor, true);
4092 }
4093 }, [attributes.onCompositionUpdate]),
4094 onCompositionStart: React.useCallback(function (event) {
4095 if (hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onCompositionStart)) {
4096 !state.isComposing && setIsComposing(true);
4097 state.isComposing = true;
4098 IS_COMPOSING.set(editor, true);
4099 }
4100 }, [attributes.onCompositionStart]),
4101 onPaste: React.useCallback(function (event) {
4102 // this will make application/x-slate-fragment exist when onPaste attributes is passed
4103 event.clipboardData = getClipboardData(event.clipboardData); // This unfortunately needs to be handled with paste events instead.
4104
4105 if (hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onPaste) && !readOnly) {
4106 event.preventDefault();
4107 ReactEditor.insertData(editor, event.clipboardData);
4108 }
4109 }, [readOnly, attributes.onPaste])
4110 }), useChildren({
4111 decorations: decorations,
4112 node: editor,
4113 renderElement: renderElement,
4114 renderPlaceholder: renderPlaceholder,
4115 renderLeaf: renderLeaf,
4116 selection: editor.selection
4117 }))));
4118};
4119
4120/**
4121 * A React context for sharing the `focused` state of the editor.
4122 */
4123
4124var FocusedContext = /*#__PURE__*/React.createContext(false);
4125/**
4126 * Get the current `focused` state of the editor.
4127 */
4128
4129var useFocused = function useFocused() {
4130 return React.useContext(FocusedContext);
4131};
4132
4133var _excluded = ["editor", "children", "onChange", "value"];
4134/**
4135 * A wrapper around the provider to handle `onChange` events, because the editor
4136 * is a mutable singleton so it won't ever register as "changed" otherwise.
4137 */
4138
4139var Slate = function Slate(props) {
4140 var editor = props.editor,
4141 children = props.children,
4142 onChange = props.onChange,
4143 value = props.value,
4144 rest = _objectWithoutProperties(props, _excluded);
4145
4146 var _React$useState = React__default['default'].useState(function () {
4147 if (!slate.Node.isNodeList(value)) {
4148 throw new Error("[Slate] value is invalid! Expected a list of elements" + "but got: ".concat(JSON.stringify(value)));
4149 }
4150
4151 if (!slate.Editor.isEditor(editor)) {
4152 throw new Error("[Slate] editor is invalid! you passed:" + "".concat(JSON.stringify(editor)));
4153 }
4154
4155 editor.children = value;
4156 Object.assign(editor, rest);
4157 return [editor];
4158 }),
4159 _React$useState2 = _slicedToArray(_React$useState, 2),
4160 context = _React$useState2[0],
4161 setContext = _React$useState2[1];
4162
4163 var onContextChange = React.useCallback(function () {
4164 onChange(editor.children);
4165 setContext([editor]);
4166 }, [onChange]);
4167 EDITOR_TO_ON_CHANGE.set(editor, onContextChange);
4168 React.useEffect(function () {
4169 return function () {
4170 EDITOR_TO_ON_CHANGE.set(editor, function () {});
4171 };
4172 }, []);
4173
4174 var _useState = React.useState(ReactEditor.isFocused(editor)),
4175 _useState2 = _slicedToArray(_useState, 2),
4176 isFocused = _useState2[0],
4177 setIsFocused = _useState2[1];
4178
4179 React.useEffect(function () {
4180 setIsFocused(ReactEditor.isFocused(editor));
4181 });
4182 useIsomorphicLayoutEffect(function () {
4183 var fn = function fn() {
4184 setTimeout(function () {
4185 setIsFocused(ReactEditor.isFocused(editor));
4186 }, 0);
4187 };
4188
4189 document.addEventListener('focus', fn, true);
4190 document.addEventListener('blur', fn, true);
4191 return function () {
4192 document.removeEventListener('focus', fn, true);
4193 document.removeEventListener('blur', fn, true);
4194 };
4195 }, []);
4196 return /*#__PURE__*/React__default['default'].createElement(SlateContext.Provider, {
4197 value: context
4198 }, /*#__PURE__*/React__default['default'].createElement(EditorContext.Provider, {
4199 value: editor
4200 }, /*#__PURE__*/React__default['default'].createElement(FocusedContext.Provider, {
4201 value: isFocused
4202 }, children)));
4203};
4204
4205/**
4206 * Get the current editor object from the React context.
4207 * @deprecated Use useSlateStatic instead.
4208 */
4209
4210var useEditor = function useEditor() {
4211 var editor = React.useContext(EditorContext);
4212
4213 if (!editor) {
4214 throw new Error("The `useEditor` hook must be used inside the <Slate> component's context.");
4215 }
4216
4217 return editor;
4218};
4219
4220/**
4221 * Utilities for single-line deletion
4222 */
4223
4224var doRectsIntersect = function doRectsIntersect(rect, compareRect) {
4225 var middle = (compareRect.top + compareRect.bottom) / 2;
4226 return rect.top <= middle && rect.bottom >= middle;
4227};
4228
4229var areRangesSameLine = function areRangesSameLine(editor, range1, range2) {
4230 var rect1 = ReactEditor.toDOMRange(editor, range1).getBoundingClientRect();
4231 var rect2 = ReactEditor.toDOMRange(editor, range2).getBoundingClientRect();
4232 return doRectsIntersect(rect1, rect2) && doRectsIntersect(rect2, rect1);
4233};
4234/**
4235 * A helper utility that returns the end portion of a `Range`
4236 * which is located on a single line.
4237 *
4238 * @param {Editor} editor The editor object to compare against
4239 * @param {Range} parentRange The parent range to compare against
4240 * @returns {Range} A valid portion of the parentRange which is one a single line
4241 */
4242
4243
4244var findCurrentLineRange = function findCurrentLineRange(editor, parentRange) {
4245 var parentRangeBoundary = slate.Editor.range(editor, slate.Range.end(parentRange));
4246 var positions = Array.from(slate.Editor.positions(editor, {
4247 at: parentRange
4248 }));
4249 var left = 0;
4250 var right = positions.length;
4251 var middle = Math.floor(right / 2);
4252
4253 if (areRangesSameLine(editor, slate.Editor.range(editor, positions[left]), parentRangeBoundary)) {
4254 return slate.Editor.range(editor, positions[left], parentRangeBoundary);
4255 }
4256
4257 if (positions.length < 2) {
4258 return slate.Editor.range(editor, positions[positions.length - 1], parentRangeBoundary);
4259 }
4260
4261 while (middle !== positions.length && middle !== left) {
4262 if (areRangesSameLine(editor, slate.Editor.range(editor, positions[middle]), parentRangeBoundary)) {
4263 right = middle;
4264 } else {
4265 left = middle;
4266 }
4267
4268 middle = Math.floor((left + right) / 2);
4269 }
4270
4271 return slate.Editor.range(editor, positions[right], parentRangeBoundary);
4272};
4273
4274function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
4275
4276function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
4277
4278function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
4279/**
4280 * `withReact` adds React and DOM specific behaviors to the editor.
4281 *
4282 * If you are using TypeScript, you must extend Slate's CustomTypes to use
4283 * this plugin.
4284 *
4285 * See https://docs.slatejs.org/concepts/11-typescript to learn how.
4286 */
4287
4288var withReact = function withReact(editor) {
4289 var e = editor;
4290 var apply = e.apply,
4291 onChange = e.onChange,
4292 deleteBackward = e.deleteBackward; // The WeakMap which maps a key to a specific HTMLElement must be scoped to the editor instance to
4293 // avoid collisions between editors in the DOM that share the same value.
4294
4295 EDITOR_TO_KEY_TO_ELEMENT.set(e, new WeakMap());
4296
4297 e.deleteBackward = function (unit) {
4298 if (unit !== 'line') {
4299 return deleteBackward(unit);
4300 }
4301
4302 if (editor.selection && slate.Range.isCollapsed(editor.selection)) {
4303 var parentBlockEntry = slate.Editor.above(editor, {
4304 match: function match(n) {
4305 return slate.Editor.isBlock(editor, n);
4306 },
4307 at: editor.selection
4308 });
4309
4310 if (parentBlockEntry) {
4311 var _parentBlockEntry = _slicedToArray(parentBlockEntry, 2),
4312 parentBlockPath = _parentBlockEntry[1];
4313
4314 var parentElementRange = slate.Editor.range(editor, parentBlockPath, editor.selection.anchor);
4315 var currentLineRange = findCurrentLineRange(e, parentElementRange);
4316
4317 if (!slate.Range.isCollapsed(currentLineRange)) {
4318 slate.Transforms["delete"](editor, {
4319 at: currentLineRange
4320 });
4321 }
4322 }
4323 }
4324 };
4325
4326 e.apply = function (op) {
4327 var matches = [];
4328
4329 switch (op.type) {
4330 case 'insert_text':
4331 case 'remove_text':
4332 case 'set_node':
4333 {
4334 var _iterator = _createForOfIteratorHelper(slate.Editor.levels(e, {
4335 at: op.path
4336 })),
4337 _step;
4338
4339 try {
4340 for (_iterator.s(); !(_step = _iterator.n()).done;) {
4341 var _step$value = _slicedToArray(_step.value, 2),
4342 node = _step$value[0],
4343 path = _step$value[1];
4344
4345 var key = ReactEditor.findKey(e, node);
4346 matches.push([path, key]);
4347 }
4348 } catch (err) {
4349 _iterator.e(err);
4350 } finally {
4351 _iterator.f();
4352 }
4353
4354 break;
4355 }
4356
4357 case 'insert_node':
4358 case 'remove_node':
4359 case 'merge_node':
4360 case 'split_node':
4361 {
4362 var _iterator2 = _createForOfIteratorHelper(slate.Editor.levels(e, {
4363 at: slate.Path.parent(op.path)
4364 })),
4365 _step2;
4366
4367 try {
4368 for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
4369 var _step2$value = _slicedToArray(_step2.value, 2),
4370 _node = _step2$value[0],
4371 _path = _step2$value[1];
4372
4373 var _key = ReactEditor.findKey(e, _node);
4374
4375 matches.push([_path, _key]);
4376 }
4377 } catch (err) {
4378 _iterator2.e(err);
4379 } finally {
4380 _iterator2.f();
4381 }
4382
4383 break;
4384 }
4385
4386 case 'move_node':
4387 {
4388 var _iterator3 = _createForOfIteratorHelper(slate.Editor.levels(e, {
4389 at: slate.Path.common(slate.Path.parent(op.path), slate.Path.parent(op.newPath))
4390 })),
4391 _step3;
4392
4393 try {
4394 for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
4395 var _step3$value = _slicedToArray(_step3.value, 2),
4396 _node2 = _step3$value[0],
4397 _path2 = _step3$value[1];
4398
4399 var _key2 = ReactEditor.findKey(e, _node2);
4400
4401 matches.push([_path2, _key2]);
4402 }
4403 } catch (err) {
4404 _iterator3.e(err);
4405 } finally {
4406 _iterator3.f();
4407 }
4408
4409 break;
4410 }
4411 }
4412
4413 apply(op);
4414
4415 for (var _i = 0, _matches = matches; _i < _matches.length; _i++) {
4416 var _matches$_i = _slicedToArray(_matches[_i], 2),
4417 _path3 = _matches$_i[0],
4418 _key3 = _matches$_i[1];
4419
4420 var _Editor$node = slate.Editor.node(e, _path3),
4421 _Editor$node2 = _slicedToArray(_Editor$node, 1),
4422 _node3 = _Editor$node2[0];
4423
4424 NODE_TO_KEY.set(_node3, _key3);
4425 }
4426 };
4427
4428 e.setFragmentData = function (data) {
4429 var selection = e.selection;
4430
4431 if (!selection) {
4432 return;
4433 }
4434
4435 var _Range$edges = slate.Range.edges(selection),
4436 _Range$edges2 = _slicedToArray(_Range$edges, 2),
4437 start = _Range$edges2[0],
4438 end = _Range$edges2[1];
4439
4440 var startVoid = slate.Editor["void"](e, {
4441 at: start.path
4442 });
4443 var endVoid = slate.Editor["void"](e, {
4444 at: end.path
4445 });
4446
4447 if (slate.Range.isCollapsed(selection) && !startVoid) {
4448 return;
4449 } // Create a fake selection so that we can add a Base64-encoded copy of the
4450 // fragment to the HTML, to decode on future pastes.
4451
4452
4453 var domRange = ReactEditor.toDOMRange(e, selection);
4454 var contents = domRange.cloneContents();
4455 var attach = contents.childNodes[0]; // Make sure attach is non-empty, since empty nodes will not get copied.
4456
4457 contents.childNodes.forEach(function (node) {
4458 if (node.textContent && node.textContent.trim() !== '') {
4459 attach = node;
4460 }
4461 }); // COMPAT: If the end node is a void node, we need to move the end of the
4462 // range from the void node's spacer span, to the end of the void node's
4463 // content, since the spacer is before void's content in the DOM.
4464
4465 if (endVoid) {
4466 var _endVoid = _slicedToArray(endVoid, 1),
4467 voidNode = _endVoid[0];
4468
4469 var r = domRange.cloneRange();
4470 var domNode = ReactEditor.toDOMNode(e, voidNode);
4471 r.setEndAfter(domNode);
4472 contents = r.cloneContents();
4473 } // COMPAT: If the start node is a void node, we need to attach the encoded
4474 // fragment to the void node's content node instead of the spacer, because
4475 // attaching it to empty `<div>/<span>` nodes will end up having it erased by
4476 // most browsers. (2018/04/27)
4477
4478
4479 if (startVoid) {
4480 attach = contents.querySelector('[data-slate-spacer]');
4481 } // Remove any zero-width space spans from the cloned DOM so that they don't
4482 // show up elsewhere when pasted.
4483
4484
4485 Array.from(contents.querySelectorAll('[data-slate-zero-width]')).forEach(function (zw) {
4486 var isNewline = zw.getAttribute('data-slate-zero-width') === 'n';
4487 zw.textContent = isNewline ? '\n' : '';
4488 }); // Set a `data-slate-fragment` attribute on a non-empty node, so it shows up
4489 // in the HTML, and can be used for intra-Slate pasting. If it's a text
4490 // node, wrap it in a `<span>` so we have something to set an attribute on.
4491
4492 if (isDOMText(attach)) {
4493 var span = attach.ownerDocument.createElement('span'); // COMPAT: In Chrome and Safari, if we don't add the `white-space` style
4494 // then leading and trailing spaces will be ignored. (2017/09/21)
4495
4496 span.style.whiteSpace = 'pre';
4497 span.appendChild(attach);
4498 contents.appendChild(span);
4499 attach = span;
4500 }
4501
4502 var fragment = e.getFragment();
4503 var string = JSON.stringify(fragment);
4504 var encoded = window.btoa(encodeURIComponent(string));
4505 attach.setAttribute('data-slate-fragment', encoded);
4506 data.setData('application/x-slate-fragment', encoded); // Add the content to a <div> so that we can get its inner HTML.
4507
4508 var div = contents.ownerDocument.createElement('div');
4509 div.appendChild(contents);
4510 div.setAttribute('hidden', 'true');
4511 contents.ownerDocument.body.appendChild(div);
4512 data.setData('text/html', div.innerHTML);
4513 data.setData('text/plain', getPlainText(div));
4514 contents.ownerDocument.body.removeChild(div);
4515 return data;
4516 };
4517
4518 e.insertData = function (data) {
4519 if (!e.insertFragmentData(data)) {
4520 e.insertTextData(data);
4521 }
4522 };
4523
4524 e.insertFragmentData = function (data) {
4525 /**
4526 * Checking copied fragment from application/x-slate-fragment or data-slate-fragment
4527 */
4528 var fragment = data.getData('application/x-slate-fragment') || getSlateFragmentAttribute(data);
4529
4530 if (fragment) {
4531 var decoded = decodeURIComponent(window.atob(fragment));
4532 var parsed = JSON.parse(decoded);
4533 e.insertFragment(parsed);
4534 return true;
4535 }
4536
4537 return false;
4538 };
4539
4540 e.insertTextData = function (data) {
4541 var text = data.getData('text/plain');
4542
4543 if (text) {
4544 var lines = text.split(/\r\n|\r|\n/);
4545 var split = false;
4546
4547 var _iterator4 = _createForOfIteratorHelper(lines),
4548 _step4;
4549
4550 try {
4551 for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
4552 var line = _step4.value;
4553
4554 if (split) {
4555 slate.Transforms.splitNodes(e, {
4556 always: true
4557 });
4558 }
4559
4560 e.insertText(line);
4561 split = true;
4562 }
4563 } catch (err) {
4564 _iterator4.e(err);
4565 } finally {
4566 _iterator4.f();
4567 }
4568
4569 return true;
4570 }
4571
4572 return false;
4573 };
4574
4575 e.onChange = function () {
4576 // COMPAT: React doesn't batch `setState` hook calls, which means that the
4577 // children and selection can get out of sync for one render pass. So we
4578 // have to use this unstable API to ensure it batches them. (2019/12/03)
4579 // https://github.com/facebook/react/issues/14259#issuecomment-439702367
4580 ReactDOM__default['default'].unstable_batchedUpdates(function () {
4581 var onContextChange = EDITOR_TO_ON_CHANGE.get(e);
4582
4583 if (onContextChange) {
4584 onContextChange();
4585 }
4586
4587 onChange();
4588 });
4589 };
4590
4591 return e;
4592};
4593
4594// Components
4595var Editable = IS_ANDROID ? AndroidEditable : Editable$1;
4596
4597exports.AndroidEditable = AndroidEditable;
4598exports.DefaultEditable = Editable$1;
4599exports.DefaultElement = DefaultElement;
4600exports.DefaultLeaf = DefaultLeaf;
4601exports.DefaultPlaceholder = DefaultPlaceholder;
4602exports.Editable = Editable;
4603exports.ReactEditor = ReactEditor;
4604exports.Slate = Slate;
4605exports.useEditor = useEditor;
4606exports.useFocused = useFocused;
4607exports.useReadOnly = useReadOnly;
4608exports.useSelected = useSelected;
4609exports.useSlate = useSlate;
4610exports.useSlateStatic = useSlateStatic;
4611exports.withReact = withReact;
4612//# sourceMappingURL=index.js.map