slate-react 0.71.0 → 0.72.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -319,7 +319,7 @@ var IS_FOCUSED = new WeakMap();
319
319
  */
320
320
 
321
321
  var EDITOR_TO_ON_CHANGE = new WeakMap();
322
- var EDITOR_TO_RESTORE_DOM = new WeakMap();
322
+ var NODE_TO_RESTORE_DOM = new WeakMap();
323
323
  /**
324
324
  * Symbols.
325
325
  */
@@ -420,7 +420,11 @@ var IS_CHROME_LEGACY = typeof navigator !== 'undefined' && /Chrome?\/(?:[0-7][0-
420
420
 
421
421
  var IS_FIREFOX_LEGACY = typeof navigator !== 'undefined' && /^(?!.*Seamonkey)(?=.*Firefox\/(?:[0-7][0-9]|[0-8][0-6])).*/i.test(navigator.userAgent); // qq browser
422
422
 
423
- var IS_QQBROWSER = typeof navigator !== 'undefined' && /.*QQBrowser/.test(navigator.userAgent); // Check if DOM is available as React does internally.
423
+ var IS_QQBROWSER = typeof navigator !== 'undefined' && /.*QQBrowser/.test(navigator.userAgent); // UC mobile browser
424
+
425
+ var IS_UC_MOBILE = typeof navigator !== 'undefined' && /.*UCBrowser/.test(navigator.userAgent); // Wechat browser
426
+
427
+ var IS_WECHATBROWSER = typeof navigator !== 'undefined' && /.*Wechat/.test(navigator.userAgent); // Check if DOM is available as React does internally.
424
428
  // https://github.com/facebook/react/blob/master/packages/shared/ExecutionEnvironment.js
425
429
 
426
430
  var 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
@@ -476,6 +480,42 @@ var isDecoratorRangeListEqual = function isDecoratorRangeListEqual(list, another
476
480
  return true;
477
481
  };
478
482
 
483
+ function useContentKey(node) {
484
+ var contentKeyRef = React.useRef(0);
485
+ var updateAnimationFrameRef = React.useRef(null);
486
+
487
+ var _useState = React.useState(0),
488
+ _useState2 = _slicedToArray(_useState, 2),
489
+ setForceRerenderCounter = _useState2[1];
490
+
491
+ React.useEffect(function () {
492
+ NODE_TO_RESTORE_DOM.set(node, function () {
493
+ // Update is already queued and node hasn't re-render yet
494
+ if (updateAnimationFrameRef.current) {
495
+ return;
496
+ }
497
+
498
+ updateAnimationFrameRef.current = requestAnimationFrame(function () {
499
+ setForceRerenderCounter(function (state) {
500
+ return state + 1;
501
+ });
502
+ updateAnimationFrameRef.current = null;
503
+ });
504
+ contentKeyRef.current++;
505
+ });
506
+ return function () {
507
+ NODE_TO_RESTORE_DOM["delete"](node);
508
+ };
509
+ }, [node]); // Node was restored => clear scheduled update
510
+
511
+ if (updateAnimationFrameRef.current) {
512
+ cancelAnimationFrame(updateAnimationFrameRef.current);
513
+ updateAnimationFrameRef.current = null;
514
+ }
515
+
516
+ return contentKeyRef.current;
517
+ }
518
+
479
519
  /**
480
520
  * Text.
481
521
  */
@@ -519,9 +559,11 @@ var Text = function Text(props) {
519
559
  NODE_TO_ELEMENT["delete"](text);
520
560
  }
521
561
  });
562
+ var contentKey = IS_ANDROID ? useContentKey(text) : undefined;
522
563
  return /*#__PURE__*/React__default['default'].createElement("span", {
523
564
  "data-slate-node": "text",
524
- ref: ref
565
+ ref: ref,
566
+ key: contentKey
525
567
  }, children);
526
568
  };
527
569
 
@@ -625,11 +667,20 @@ var Element = function Element(props) {
625
667
  NODE_TO_ELEMENT["delete"](element);
626
668
  }
627
669
  });
628
- return renderElement({
670
+ var content = renderElement({
629
671
  attributes: attributes,
630
672
  children: children,
631
673
  element: element
632
674
  });
675
+
676
+ if (IS_ANDROID) {
677
+ var contentKey = useContentKey(element);
678
+ return /*#__PURE__*/React__default['default'].createElement(React.Fragment, {
679
+ key: contentKey
680
+ }, content);
681
+ }
682
+
683
+ return content;
633
684
  };
634
685
 
635
686
  var MemoizedElement = /*#__PURE__*/React__default['default'].memo(Element, function (prev, next) {
@@ -1728,7 +1779,7 @@ var Editable$1 = function Editable(props) {
1728
1779
  // type that we need. So instead, insert whenever a composition
1729
1780
  // ends since it will already have been committed to the DOM.
1730
1781
 
1731
- if (!IS_SAFARI && !IS_FIREFOX_LEGACY && !IS_IOS && !IS_QQBROWSER && event.data) {
1782
+ if (!IS_SAFARI && !IS_FIREFOX_LEGACY && !IS_IOS && !IS_QQBROWSER && !IS_WECHATBROWSER && !IS_UC_MOBILE && event.data) {
1732
1783
  slate.Editor.insertText(editor, event.data);
1733
1784
  }
1734
1785
 
@@ -1857,7 +1908,7 @@ var Editable$1 = function Editable(props) {
1857
1908
  state.isDraggingInternally = true;
1858
1909
  ReactEditor.setFragmentData(editor, event.dataTransfer);
1859
1910
  }
1860
- }, [attributes.onDragStart]),
1911
+ }, [readOnly, attributes.onDragStart]),
1861
1912
  onDrop: React.useCallback(function (event) {
1862
1913
  if (!readOnly && hasTarget(editor, event.target) && !isEventHandled(event, attributes.onDrop)) {
1863
1914
  event.preventDefault(); // Keep a reference to the dragged range before updating selection
@@ -3268,19 +3319,6 @@ var isRemoveLeafNodes = function isRemoveLeafNodes(_, _ref7) {
3268
3319
  return removedNodes.length > 0 && addedNodes.length === 0 && characterDataMutations.length > 0;
3269
3320
  };
3270
3321
 
3271
- function restoreDOM(editor) {
3272
- try {
3273
- var onRestoreDOM = EDITOR_TO_RESTORE_DOM.get(editor);
3274
-
3275
- if (onRestoreDOM) {
3276
- onRestoreDOM();
3277
- }
3278
- } catch (err) {
3279
- // eslint-disable-next-line no-console
3280
- console.error(err);
3281
- }
3282
- }
3283
-
3284
3322
  function _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; } } }; }
3285
3323
 
3286
3324
  function _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); }
@@ -3311,15 +3349,17 @@ function _objectSpread$1(target) { for (var i = 1; i < arguments.length; i++) {
3311
3349
  * - Line breaks
3312
3350
  *
3313
3351
  * @param editor
3352
+ * @param restoreDOM
3314
3353
  */
3315
3354
 
3316
3355
 
3317
- var AndroidInputManager = function AndroidInputManager(editor) {
3356
+ var AndroidInputManager = function AndroidInputManager(editor, restoreDOM) {
3318
3357
  var _this = this;
3319
3358
 
3320
3359
  _classCallCheck(this, AndroidInputManager);
3321
3360
 
3322
3361
  this.editor = editor;
3362
+ this.restoreDOM = restoreDOM;
3323
3363
  /**
3324
3364
  * Handle MutationObserver flush
3325
3365
  *
@@ -3334,7 +3374,7 @@ var AndroidInputManager = function AndroidInputManager(editor) {
3334
3374
  // eslint-disable-next-line no-console
3335
3375
  console.error(err); // Failed to reconcile mutations, restore DOM to its previous state
3336
3376
 
3337
- restoreDOM(_this.editor);
3377
+ _this.restoreDOM();
3338
3378
  }
3339
3379
  };
3340
3380
  /**
@@ -3402,10 +3442,9 @@ var AndroidInputManager = function AndroidInputManager(editor) {
3402
3442
 
3403
3443
  this.insertBreak = function () {
3404
3444
  var selection = _this.editor.selection;
3405
- slate.Editor.insertBreak(_this.editor); // To-do: Need a more granular solution to restoring only a specific portion
3406
- // of the document. Restoring the entire document is expensive.
3445
+ slate.Editor.insertBreak(_this.editor);
3407
3446
 
3408
- restoreDOM(_this.editor);
3447
+ _this.restoreDOM();
3409
3448
 
3410
3449
  if (selection) {
3411
3450
  // Compat: Move selection to the newly inserted block if it has not moved
@@ -3430,7 +3469,7 @@ var AndroidInputManager = function AndroidInputManager(editor) {
3430
3469
  slate.Editor.insertText(_this.editor, text);
3431
3470
  }
3432
3471
 
3433
- restoreDOM(_this.editor);
3472
+ _this.restoreDOM();
3434
3473
  };
3435
3474
  /**
3436
3475
  * Handle `backspace` that merges blocks
@@ -3440,7 +3479,8 @@ var AndroidInputManager = function AndroidInputManager(editor) {
3440
3479
  this.deleteBackward = function () {
3441
3480
  slate.Editor.deleteBackward(_this.editor);
3442
3481
  ReactEditor.focus(_this.editor);
3443
- restoreDOM(_this.editor);
3482
+
3483
+ _this.restoreDOM();
3444
3484
  };
3445
3485
  /**
3446
3486
  * Handle mutations that remove specific leaves
@@ -3461,7 +3501,8 @@ var AndroidInputManager = function AndroidInputManager(editor) {
3461
3501
  slate.Transforms["delete"](_this.editor, {
3462
3502
  at: path
3463
3503
  });
3464
- restoreDOM(_this.editor);
3504
+
3505
+ _this.restoreDOM();
3465
3506
  }
3466
3507
  }
3467
3508
  } catch (err) {
@@ -3472,6 +3513,7 @@ var AndroidInputManager = function AndroidInputManager(editor) {
3472
3513
  };
3473
3514
 
3474
3515
  this.editor = editor;
3516
+ this.restoreDOM = restoreDOM;
3475
3517
  };
3476
3518
 
3477
3519
  function useMutationObserver(node, callback, options) {
@@ -3497,6 +3539,72 @@ function useMutationObserver(node, callback, options) {
3497
3539
  });
3498
3540
  }
3499
3541
 
3542
+ var MUTATION_OBSERVER_CONFIG$1 = {
3543
+ childList: true,
3544
+ characterData: true,
3545
+ subtree: true
3546
+ };
3547
+
3548
+ function findClosestKnowSlateNode(domNode) {
3549
+ var _domEl;
3550
+
3551
+ var domEl = isDOMElement(domNode) ? domNode : domNode.parentElement;
3552
+
3553
+ if (domEl && !domEl.hasAttribute('data-slate-node')) {
3554
+ domEl = domEl.closest("[data-slate-node]");
3555
+ }
3556
+
3557
+ var slateNode = domEl && ELEMENT_TO_NODE.get(domEl);
3558
+
3559
+ if (slateNode) {
3560
+ return slateNode;
3561
+ } // Unknown dom element with a slate-slate-node attribute => the IME
3562
+ // most likely duplicated the node so we have to restore the parent
3563
+
3564
+
3565
+ return (_domEl = domEl) !== null && _domEl !== void 0 && _domEl.parentElement ? findClosestKnowSlateNode(domEl.parentElement) : null;
3566
+ }
3567
+
3568
+ function useRestoreDom(node, receivedUserInput) {
3569
+ var editor = useSlateStatic();
3570
+ var mutatedNodes = React.useRef(new Set());
3571
+ var handleDOMMutation = React.useCallback(function (mutations) {
3572
+ if (!receivedUserInput.current) {
3573
+ return;
3574
+ }
3575
+
3576
+ mutations.forEach(function (_ref) {
3577
+ var target = _ref.target;
3578
+ var slateNode = findClosestKnowSlateNode(target);
3579
+
3580
+ if (!slateNode) {
3581
+ return;
3582
+ }
3583
+
3584
+ return mutatedNodes.current.add(slateNode);
3585
+ });
3586
+ }, []);
3587
+ useMutationObserver(node, handleDOMMutation, MUTATION_OBSERVER_CONFIG$1); // Clear mutated nodes on every render
3588
+
3589
+ mutatedNodes.current.clear();
3590
+ var restore = React.useCallback(function () {
3591
+ var mutated = Array.from(mutatedNodes.current.values()); // Filter out child nodes of nodes that will be restored anyway
3592
+
3593
+ var nodesToRestore = mutated.filter(function (n) {
3594
+ return !mutated.some(function (m) {
3595
+ return slate.Path.isParent(ReactEditor.findPath(editor, m), ReactEditor.findPath(editor, n));
3596
+ });
3597
+ });
3598
+ nodesToRestore.forEach(function (n) {
3599
+ var _NODE_TO_RESTORE_DOM$;
3600
+
3601
+ (_NODE_TO_RESTORE_DOM$ = NODE_TO_RESTORE_DOM.get(n)) === null || _NODE_TO_RESTORE_DOM$ === void 0 ? void 0 : _NODE_TO_RESTORE_DOM$();
3602
+ });
3603
+ mutatedNodes.current.clear();
3604
+ }, []);
3605
+ return restore;
3606
+ }
3607
+
3500
3608
  function useTrackUserInput() {
3501
3609
  var editor = useSlateStatic();
3502
3610
  var receivedUserInput = React.useRef(false);
@@ -3537,16 +3645,14 @@ var MUTATION_OBSERVER_CONFIG = {
3537
3645
  function useAndroidInputManager(node) {
3538
3646
  var editor = useSlateStatic();
3539
3647
 
3540
- var _useState = React.useState(function () {
3541
- return new AndroidInputManager(editor);
3542
- }),
3543
- _useState2 = _slicedToArray(_useState, 1),
3544
- inputManager = _useState2[0];
3545
-
3546
3648
  var _useTrackUserInput = useTrackUserInput(),
3547
3649
  receivedUserInput = _useTrackUserInput.receivedUserInput,
3548
3650
  onUserInput = _useTrackUserInput.onUserInput;
3549
3651
 
3652
+ var restoreDom = useRestoreDom(node, receivedUserInput);
3653
+ var inputManager = React.useMemo(function () {
3654
+ return new AndroidInputManager(editor, restoreDom);
3655
+ }, [restoreDom, editor]);
3550
3656
  var timeoutId = React.useRef(null);
3551
3657
  var isReconciling = React.useRef(false);
3552
3658
  var flush = React.useCallback(function (mutations) {
@@ -3614,17 +3720,7 @@ var AndroidEditable = function AndroidEditable(props) {
3614
3720
  latestElement: null
3615
3721
  };
3616
3722
  }, []);
3617
-
3618
- var _useState = React.useState(0),
3619
- _useState2 = _slicedToArray(_useState, 2),
3620
- contentKey = _useState2[0],
3621
- setContentKey = _useState2[1];
3622
-
3623
- var onRestoreDOM = React.useCallback(function () {
3624
- setContentKey(function (prev) {
3625
- return prev + 1;
3626
- });
3627
- }, [contentKey]); // Whenever the editor updates...
3723
+ var contentKey = useContentKey(editor); // Whenever the editor updates...
3628
3724
 
3629
3725
  useIsomorphicLayoutEffect(function () {
3630
3726
  // Update element-related weak maps with the DOM element ref.
@@ -3635,10 +3731,8 @@ var AndroidEditable = function AndroidEditable(props) {
3635
3731
  EDITOR_TO_ELEMENT.set(editor, ref.current);
3636
3732
  NODE_TO_ELEMENT.set(editor, ref.current);
3637
3733
  ELEMENT_TO_NODE.set(ref.current, editor);
3638
- EDITOR_TO_RESTORE_DOM.set(editor, onRestoreDOM);
3639
3734
  } else {
3640
3735
  NODE_TO_ELEMENT["delete"](editor);
3641
- EDITOR_TO_RESTORE_DOM["delete"](editor);
3642
3736
  }
3643
3737
 
3644
3738
  try {