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.
@@ -973,7 +973,7 @@
973
973
  */
974
974
 
975
975
  var EDITOR_TO_ON_CHANGE = new WeakMap();
976
- var EDITOR_TO_RESTORE_DOM = new WeakMap();
976
+ var NODE_TO_RESTORE_DOM = new WeakMap();
977
977
  /**
978
978
  * Symbols.
979
979
  */
@@ -1074,7 +1074,11 @@
1074
1074
 
1075
1075
  var IS_FIREFOX_LEGACY = typeof navigator !== 'undefined' && /^(?!.*Seamonkey)(?=.*Firefox\/(?:[0-7][0-9]|[0-8][0-6])).*/i.test(navigator.userAgent); // qq browser
1076
1076
 
1077
- var IS_QQBROWSER = typeof navigator !== 'undefined' && /.*QQBrowser/.test(navigator.userAgent); // Check if DOM is available as React does internally.
1077
+ var IS_QQBROWSER = typeof navigator !== 'undefined' && /.*QQBrowser/.test(navigator.userAgent); // UC mobile browser
1078
+
1079
+ var IS_UC_MOBILE = typeof navigator !== 'undefined' && /.*UCBrowser/.test(navigator.userAgent); // Wechat browser
1080
+
1081
+ var IS_WECHATBROWSER = typeof navigator !== 'undefined' && /.*Wechat/.test(navigator.userAgent); // Check if DOM is available as React does internally.
1078
1082
  // https://github.com/facebook/react/blob/master/packages/shared/ExecutionEnvironment.js
1079
1083
 
1080
1084
  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
@@ -1130,6 +1134,42 @@
1130
1134
  return true;
1131
1135
  };
1132
1136
 
1137
+ function useContentKey(node) {
1138
+ var contentKeyRef = React.useRef(0);
1139
+ var updateAnimationFrameRef = React.useRef(null);
1140
+
1141
+ var _useState = React.useState(0),
1142
+ _useState2 = _slicedToArray(_useState, 2),
1143
+ setForceRerenderCounter = _useState2[1];
1144
+
1145
+ React.useEffect(function () {
1146
+ NODE_TO_RESTORE_DOM.set(node, function () {
1147
+ // Update is already queued and node hasn't re-render yet
1148
+ if (updateAnimationFrameRef.current) {
1149
+ return;
1150
+ }
1151
+
1152
+ updateAnimationFrameRef.current = requestAnimationFrame(function () {
1153
+ setForceRerenderCounter(function (state) {
1154
+ return state + 1;
1155
+ });
1156
+ updateAnimationFrameRef.current = null;
1157
+ });
1158
+ contentKeyRef.current++;
1159
+ });
1160
+ return function () {
1161
+ NODE_TO_RESTORE_DOM["delete"](node);
1162
+ };
1163
+ }, [node]); // Node was restored => clear scheduled update
1164
+
1165
+ if (updateAnimationFrameRef.current) {
1166
+ cancelAnimationFrame(updateAnimationFrameRef.current);
1167
+ updateAnimationFrameRef.current = null;
1168
+ }
1169
+
1170
+ return contentKeyRef.current;
1171
+ }
1172
+
1133
1173
  /**
1134
1174
  * Text.
1135
1175
  */
@@ -1173,9 +1213,11 @@
1173
1213
  NODE_TO_ELEMENT["delete"](text);
1174
1214
  }
1175
1215
  });
1216
+ var contentKey = IS_ANDROID ? useContentKey(text) : undefined;
1176
1217
  return /*#__PURE__*/React__default['default'].createElement("span", {
1177
1218
  "data-slate-node": "text",
1178
- ref: ref
1219
+ ref: ref,
1220
+ key: contentKey
1179
1221
  }, children);
1180
1222
  };
1181
1223
 
@@ -1279,11 +1321,20 @@
1279
1321
  NODE_TO_ELEMENT["delete"](element);
1280
1322
  }
1281
1323
  });
1282
- return renderElement({
1324
+ var content = renderElement({
1283
1325
  attributes: attributes,
1284
1326
  children: children,
1285
1327
  element: element
1286
1328
  });
1329
+
1330
+ if (IS_ANDROID) {
1331
+ var contentKey = useContentKey(element);
1332
+ return /*#__PURE__*/React__default['default'].createElement(React.Fragment, {
1333
+ key: contentKey
1334
+ }, content);
1335
+ }
1336
+
1337
+ return content;
1287
1338
  };
1288
1339
 
1289
1340
  var MemoizedElement = /*#__PURE__*/React__default['default'].memo(Element, function (prev, next) {
@@ -2638,7 +2689,7 @@
2638
2689
  // type that we need. So instead, insert whenever a composition
2639
2690
  // ends since it will already have been committed to the DOM.
2640
2691
 
2641
- if (!IS_SAFARI && !IS_FIREFOX_LEGACY && !IS_IOS && !IS_QQBROWSER && event.data) {
2692
+ if (!IS_SAFARI && !IS_FIREFOX_LEGACY && !IS_IOS && !IS_QQBROWSER && !IS_WECHATBROWSER && !IS_UC_MOBILE && event.data) {
2642
2693
  slate.Editor.insertText(editor, event.data);
2643
2694
  }
2644
2695
 
@@ -2767,7 +2818,7 @@
2767
2818
  state.isDraggingInternally = true;
2768
2819
  ReactEditor.setFragmentData(editor, event.dataTransfer);
2769
2820
  }
2770
- }, [attributes.onDragStart]),
2821
+ }, [readOnly, attributes.onDragStart]),
2771
2822
  onDrop: React.useCallback(function (event) {
2772
2823
  if (!readOnly && hasTarget(editor, event.target) && !isEventHandled(event, attributes.onDrop)) {
2773
2824
  event.preventDefault(); // Keep a reference to the dragged range before updating selection
@@ -4178,19 +4229,6 @@
4178
4229
  return removedNodes.length > 0 && addedNodes.length === 0 && characterDataMutations.length > 0;
4179
4230
  };
4180
4231
 
4181
- function restoreDOM(editor) {
4182
- try {
4183
- var onRestoreDOM = EDITOR_TO_RESTORE_DOM.get(editor);
4184
-
4185
- if (onRestoreDOM) {
4186
- onRestoreDOM();
4187
- }
4188
- } catch (err) {
4189
- // eslint-disable-next-line no-console
4190
- console.error(err);
4191
- }
4192
- }
4193
-
4194
4232
  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; } } }; }
4195
4233
 
4196
4234
  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); }
@@ -4221,15 +4259,17 @@
4221
4259
  * - Line breaks
4222
4260
  *
4223
4261
  * @param editor
4262
+ * @param restoreDOM
4224
4263
  */
4225
4264
 
4226
4265
 
4227
- var AndroidInputManager = function AndroidInputManager(editor) {
4266
+ var AndroidInputManager = function AndroidInputManager(editor, restoreDOM) {
4228
4267
  var _this = this;
4229
4268
 
4230
4269
  _classCallCheck(this, AndroidInputManager);
4231
4270
 
4232
4271
  this.editor = editor;
4272
+ this.restoreDOM = restoreDOM;
4233
4273
  /**
4234
4274
  * Handle MutationObserver flush
4235
4275
  *
@@ -4244,7 +4284,7 @@
4244
4284
  // eslint-disable-next-line no-console
4245
4285
  console.error(err); // Failed to reconcile mutations, restore DOM to its previous state
4246
4286
 
4247
- restoreDOM(_this.editor);
4287
+ _this.restoreDOM();
4248
4288
  }
4249
4289
  };
4250
4290
  /**
@@ -4312,10 +4352,9 @@
4312
4352
 
4313
4353
  this.insertBreak = function () {
4314
4354
  var selection = _this.editor.selection;
4315
- slate.Editor.insertBreak(_this.editor); // To-do: Need a more granular solution to restoring only a specific portion
4316
- // of the document. Restoring the entire document is expensive.
4355
+ slate.Editor.insertBreak(_this.editor);
4317
4356
 
4318
- restoreDOM(_this.editor);
4357
+ _this.restoreDOM();
4319
4358
 
4320
4359
  if (selection) {
4321
4360
  // Compat: Move selection to the newly inserted block if it has not moved
@@ -4340,7 +4379,7 @@
4340
4379
  slate.Editor.insertText(_this.editor, text);
4341
4380
  }
4342
4381
 
4343
- restoreDOM(_this.editor);
4382
+ _this.restoreDOM();
4344
4383
  };
4345
4384
  /**
4346
4385
  * Handle `backspace` that merges blocks
@@ -4350,7 +4389,8 @@
4350
4389
  this.deleteBackward = function () {
4351
4390
  slate.Editor.deleteBackward(_this.editor);
4352
4391
  ReactEditor.focus(_this.editor);
4353
- restoreDOM(_this.editor);
4392
+
4393
+ _this.restoreDOM();
4354
4394
  };
4355
4395
  /**
4356
4396
  * Handle mutations that remove specific leaves
@@ -4371,7 +4411,8 @@
4371
4411
  slate.Transforms["delete"](_this.editor, {
4372
4412
  at: path
4373
4413
  });
4374
- restoreDOM(_this.editor);
4414
+
4415
+ _this.restoreDOM();
4375
4416
  }
4376
4417
  }
4377
4418
  } catch (err) {
@@ -4382,6 +4423,7 @@
4382
4423
  };
4383
4424
 
4384
4425
  this.editor = editor;
4426
+ this.restoreDOM = restoreDOM;
4385
4427
  };
4386
4428
 
4387
4429
  function useMutationObserver(node, callback, options) {
@@ -4407,6 +4449,72 @@
4407
4449
  });
4408
4450
  }
4409
4451
 
4452
+ var MUTATION_OBSERVER_CONFIG$1 = {
4453
+ childList: true,
4454
+ characterData: true,
4455
+ subtree: true
4456
+ };
4457
+
4458
+ function findClosestKnowSlateNode(domNode) {
4459
+ var _domEl;
4460
+
4461
+ var domEl = isDOMElement(domNode) ? domNode : domNode.parentElement;
4462
+
4463
+ if (domEl && !domEl.hasAttribute('data-slate-node')) {
4464
+ domEl = domEl.closest("[data-slate-node]");
4465
+ }
4466
+
4467
+ var slateNode = domEl && ELEMENT_TO_NODE.get(domEl);
4468
+
4469
+ if (slateNode) {
4470
+ return slateNode;
4471
+ } // Unknown dom element with a slate-slate-node attribute => the IME
4472
+ // most likely duplicated the node so we have to restore the parent
4473
+
4474
+
4475
+ return (_domEl = domEl) !== null && _domEl !== void 0 && _domEl.parentElement ? findClosestKnowSlateNode(domEl.parentElement) : null;
4476
+ }
4477
+
4478
+ function useRestoreDom(node, receivedUserInput) {
4479
+ var editor = useSlateStatic();
4480
+ var mutatedNodes = React.useRef(new Set());
4481
+ var handleDOMMutation = React.useCallback(function (mutations) {
4482
+ if (!receivedUserInput.current) {
4483
+ return;
4484
+ }
4485
+
4486
+ mutations.forEach(function (_ref) {
4487
+ var target = _ref.target;
4488
+ var slateNode = findClosestKnowSlateNode(target);
4489
+
4490
+ if (!slateNode) {
4491
+ return;
4492
+ }
4493
+
4494
+ return mutatedNodes.current.add(slateNode);
4495
+ });
4496
+ }, []);
4497
+ useMutationObserver(node, handleDOMMutation, MUTATION_OBSERVER_CONFIG$1); // Clear mutated nodes on every render
4498
+
4499
+ mutatedNodes.current.clear();
4500
+ var restore = React.useCallback(function () {
4501
+ var mutated = Array.from(mutatedNodes.current.values()); // Filter out child nodes of nodes that will be restored anyway
4502
+
4503
+ var nodesToRestore = mutated.filter(function (n) {
4504
+ return !mutated.some(function (m) {
4505
+ return slate.Path.isParent(ReactEditor.findPath(editor, m), ReactEditor.findPath(editor, n));
4506
+ });
4507
+ });
4508
+ nodesToRestore.forEach(function (n) {
4509
+ var _NODE_TO_RESTORE_DOM$;
4510
+
4511
+ (_NODE_TO_RESTORE_DOM$ = NODE_TO_RESTORE_DOM.get(n)) === null || _NODE_TO_RESTORE_DOM$ === void 0 ? void 0 : _NODE_TO_RESTORE_DOM$();
4512
+ });
4513
+ mutatedNodes.current.clear();
4514
+ }, []);
4515
+ return restore;
4516
+ }
4517
+
4410
4518
  function useTrackUserInput() {
4411
4519
  var editor = useSlateStatic();
4412
4520
  var receivedUserInput = React.useRef(false);
@@ -4447,16 +4555,14 @@
4447
4555
  function useAndroidInputManager(node) {
4448
4556
  var editor = useSlateStatic();
4449
4557
 
4450
- var _useState = React.useState(function () {
4451
- return new AndroidInputManager(editor);
4452
- }),
4453
- _useState2 = _slicedToArray(_useState, 1),
4454
- inputManager = _useState2[0];
4455
-
4456
4558
  var _useTrackUserInput = useTrackUserInput(),
4457
4559
  receivedUserInput = _useTrackUserInput.receivedUserInput,
4458
4560
  onUserInput = _useTrackUserInput.onUserInput;
4459
4561
 
4562
+ var restoreDom = useRestoreDom(node, receivedUserInput);
4563
+ var inputManager = React.useMemo(function () {
4564
+ return new AndroidInputManager(editor, restoreDom);
4565
+ }, [restoreDom, editor]);
4460
4566
  var timeoutId = React.useRef(null);
4461
4567
  var isReconciling = React.useRef(false);
4462
4568
  var flush = React.useCallback(function (mutations) {
@@ -4524,17 +4630,7 @@
4524
4630
  latestElement: null
4525
4631
  };
4526
4632
  }, []);
4527
-
4528
- var _useState = React.useState(0),
4529
- _useState2 = _slicedToArray(_useState, 2),
4530
- contentKey = _useState2[0],
4531
- setContentKey = _useState2[1];
4532
-
4533
- var onRestoreDOM = React.useCallback(function () {
4534
- setContentKey(function (prev) {
4535
- return prev + 1;
4536
- });
4537
- }, [contentKey]); // Whenever the editor updates...
4633
+ var contentKey = useContentKey(editor); // Whenever the editor updates...
4538
4634
 
4539
4635
  useIsomorphicLayoutEffect(function () {
4540
4636
  // Update element-related weak maps with the DOM element ref.
@@ -4545,10 +4641,8 @@
4545
4641
  EDITOR_TO_ELEMENT.set(editor, ref.current);
4546
4642
  NODE_TO_ELEMENT.set(editor, ref.current);
4547
4643
  ELEMENT_TO_NODE.set(ref.current, editor);
4548
- EDITOR_TO_RESTORE_DOM.set(editor, onRestoreDOM);
4549
4644
  } else {
4550
4645
  NODE_TO_ELEMENT["delete"](editor);
4551
- EDITOR_TO_RESTORE_DOM["delete"](editor);
4552
4646
  }
4553
4647
 
4554
4648
  try {