slate-react 0.57.2 → 0.57.3

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
@@ -216,6 +216,34 @@ var getEditableChild = (parent, index, direction) => {
216
216
 
217
217
  return child;
218
218
  };
219
+ /**
220
+ * Get a plaintext representation of the content of a node, accounting for block
221
+ * elements which get a newline appended.
222
+ *
223
+ * The domNode must be attached to the DOM.
224
+ */
225
+
226
+ var getPlainText = domNode => {
227
+ var text = '';
228
+
229
+ if (isDOMText(domNode) && domNode.nodeValue) {
230
+ return domNode.nodeValue;
231
+ }
232
+
233
+ if (isDOMElement(domNode)) {
234
+ for (var childNode of Array.from(domNode.childNodes)) {
235
+ text += getPlainText(childNode);
236
+ }
237
+
238
+ var display = getComputedStyle(domNode).getPropertyValue('display');
239
+
240
+ if (display === 'block' || display === 'list' || domNode.tagName === 'BR') {
241
+ text += '\n';
242
+ }
243
+ }
244
+
245
+ return text;
246
+ };
219
247
 
220
248
  var ReactEditor = {
221
249
  /**
@@ -357,6 +385,13 @@ var ReactEditor = {
357
385
  editor.insertData(data);
358
386
  },
359
387
 
388
+ /**
389
+ * Sets data from the currently selected fragment on a `DataTransfer`.
390
+ */
391
+ setFragmentData(editor, data) {
392
+ editor.setFragmentData(data);
393
+ },
394
+
360
395
  /**
361
396
  * Find the native DOM element from a Slate node.
362
397
  */
@@ -433,13 +468,21 @@ var ReactEditor = {
433
468
  anchor,
434
469
  focus
435
470
  } = range;
471
+ var isBackward = slate.Range.isBackward(range);
436
472
  var domAnchor = ReactEditor.toDOMPoint(editor, anchor);
437
473
  var domFocus = slate.Range.isCollapsed(range) ? domAnchor : ReactEditor.toDOMPoint(editor, focus);
438
474
  var domRange = window.document.createRange();
439
- var start = slate.Range.isBackward(range) ? domFocus : domAnchor;
440
- var end = slate.Range.isBackward(range) ? domAnchor : domFocus;
441
- domRange.setStart(start[0], start[1]);
442
- domRange.setEnd(end[0], end[1]);
475
+ var [startNode, startOffset] = isBackward ? domFocus : domAnchor;
476
+ var [endNode, endOffset] = isBackward ? domAnchor : domFocus; // A slate Point at zero-width Leaf always has an offset of 0 but a native DOM selection at
477
+ // zero-width node has an offset of 1 so we have to check if we are in a zero-width node and
478
+ // adjust the offset accordingly.
479
+
480
+ var startEl = isDOMElement(startNode) ? startNode : startNode.parentElement;
481
+ var isStartAtZeroWidth = !!startEl.getAttribute('data-slate-zero-width');
482
+ var endEl = isDOMElement(endNode) ? endNode : endNode.parentElement;
483
+ var isEndAtZeroWidth = !!endEl.getAttribute('data-slate-zero-width');
484
+ domRange.setStart(startNode, isStartAtZeroWidth ? 1 : startOffset);
485
+ domRange.setEnd(endNode, isEndAtZeroWidth ? 1 : endOffset);
443
486
  return domRange;
444
487
  },
445
488
 
@@ -712,6 +755,11 @@ var Slate = props => {
712
755
  setKey(key + 1);
713
756
  }, [key, onChange]);
714
757
  EDITOR_TO_ON_CHANGE.set(editor, onContextChange);
758
+ React.useEffect(() => {
759
+ return () => {
760
+ EDITOR_TO_ON_CHANGE.set(editor, () => {});
761
+ };
762
+ }, []);
715
763
  return React__default.createElement(SlateContext.Provider, {
716
764
  value: context
717
765
  }, React__default.createElement(EditorContext.Provider, {
@@ -801,6 +849,91 @@ var withReact = editor => {
801
849
  }
802
850
  };
803
851
 
852
+ e.setFragmentData = data => {
853
+ var {
854
+ selection
855
+ } = e;
856
+
857
+ if (!selection) {
858
+ return;
859
+ }
860
+
861
+ var [start, end] = slate.Range.edges(selection);
862
+ var startVoid = slate.Editor.void(e, {
863
+ at: start.path
864
+ });
865
+ var endVoid = slate.Editor.void(e, {
866
+ at: end.path
867
+ });
868
+
869
+ if (slate.Range.isCollapsed(selection) && !startVoid) {
870
+ return;
871
+ } // Create a fake selection so that we can add a Base64-encoded copy of the
872
+ // fragment to the HTML, to decode on future pastes.
873
+
874
+
875
+ var domRange = ReactEditor.toDOMRange(e, selection);
876
+ var contents = domRange.cloneContents();
877
+ var attach = contents.childNodes[0]; // Make sure attach is non-empty, since empty nodes will not get copied.
878
+
879
+ contents.childNodes.forEach(node => {
880
+ if (node.textContent && node.textContent.trim() !== '') {
881
+ attach = node;
882
+ }
883
+ }); // COMPAT: If the end node is a void node, we need to move the end of the
884
+ // range from the void node's spacer span, to the end of the void node's
885
+ // content, since the spacer is before void's content in the DOM.
886
+
887
+ if (endVoid) {
888
+ var [voidNode] = endVoid;
889
+ var r = domRange.cloneRange();
890
+ var domNode = ReactEditor.toDOMNode(e, voidNode);
891
+ r.setEndAfter(domNode);
892
+ contents = r.cloneContents();
893
+ } // COMPAT: If the start node is a void node, we need to attach the encoded
894
+ // fragment to the void node's content node instead of the spacer, because
895
+ // attaching it to empty `<div>/<span>` nodes will end up having it erased by
896
+ // most browsers. (2018/04/27)
897
+
898
+
899
+ if (startVoid) {
900
+ attach = contents.querySelector('[data-slate-spacer]');
901
+ } // Remove any zero-width space spans from the cloned DOM so that they don't
902
+ // show up elsewhere when pasted.
903
+
904
+
905
+ Array.from(contents.querySelectorAll('[data-slate-zero-width]')).forEach(zw => {
906
+ var isNewline = zw.getAttribute('data-slate-zero-width') === 'n';
907
+ zw.textContent = isNewline ? '\n' : '';
908
+ }); // Set a `data-slate-fragment` attribute on a non-empty node, so it shows up
909
+ // in the HTML, and can be used for intra-Slate pasting. If it's a text
910
+ // node, wrap it in a `<span>` so we have something to set an attribute on.
911
+
912
+ if (isDOMText(attach)) {
913
+ var span = document.createElement('span'); // COMPAT: In Chrome and Safari, if we don't add the `white-space` style
914
+ // then leading and trailing spaces will be ignored. (2017/09/21)
915
+
916
+ span.style.whiteSpace = 'pre';
917
+ span.appendChild(attach);
918
+ contents.appendChild(span);
919
+ attach = span;
920
+ }
921
+
922
+ var fragment = e.getFragment();
923
+ var string = JSON.stringify(fragment);
924
+ var encoded = window.btoa(encodeURIComponent(string));
925
+ attach.setAttribute('data-slate-fragment', encoded);
926
+ data.setData('application/x-slate-fragment', encoded); // Add the content to a <div> so that we can get its inner HTML.
927
+
928
+ var div = document.createElement('div');
929
+ div.appendChild(contents);
930
+ div.setAttribute('hidden', 'true');
931
+ document.body.appendChild(div);
932
+ data.setData('text/html', div.innerHTML);
933
+ data.setData('text/plain', getPlainText(div));
934
+ document.body.removeChild(div);
935
+ };
936
+
804
937
  e.insertData = data => {
805
938
  var fragment = data.getData('application/x-slate-fragment');
806
939
 
@@ -1408,11 +1541,10 @@ var Editable = props => {
1408
1541
 
1409
1542
  if (!selection && !hasDomSelection) {
1410
1543
  return;
1411
- }
1544
+ } // If the DOM selection is already correct, we're done.
1412
1545
 
1413
- var newDomRange = selection && ReactEditor.toDOMRange(editor, selection); // If the DOM selection is already correct, we're done.
1414
1546
 
1415
- if (hasDomSelection && newDomRange && isRangeEqual(domSelection.getRangeAt(0), newDomRange)) {
1547
+ if (hasDomSelection && selection && slate.Range.equals(ReactEditor.toSlateRange(editor, domSelection), selection)) {
1416
1548
  return;
1417
1549
  } // Otherwise the DOM selection is out of sync, so update it.
1418
1550
 
@@ -1420,6 +1552,7 @@ var Editable = props => {
1420
1552
  var el = ReactEditor.toDOMNode(editor, editor);
1421
1553
  state.isUpdatingSelection = true;
1422
1554
  domSelection.removeAllRanges();
1555
+ var newDomRange = selection && ReactEditor.toDOMRange(editor, selection);
1423
1556
 
1424
1557
  if (newDomRange) {
1425
1558
  domSelection.addRange(newDomRange);
@@ -1623,7 +1756,6 @@ var Editable = props => {
1623
1756
  } = window.document;
1624
1757
  var el = ReactEditor.toDOMNode(editor, editor);
1625
1758
  var domSelection = window.getSelection();
1626
- var domRange = domSelection && domSelection.rangeCount > 0 && domSelection.getRangeAt(0);
1627
1759
 
1628
1760
  if (activeElement === el) {
1629
1761
  state.latestElement = activeElement;
@@ -1632,8 +1764,8 @@ var Editable = props => {
1632
1764
  IS_FOCUSED.delete(editor);
1633
1765
  }
1634
1766
 
1635
- if (domRange && hasEditableTarget(editor, domRange.startContainer) && hasEditableTarget(editor, domRange.endContainer)) {
1636
- var range = ReactEditor.toSlateRange(editor, domRange);
1767
+ if (domSelection && hasEditableTarget(editor, domSelection.anchorNode) && hasEditableTarget(editor, domSelection.focusNode)) {
1768
+ var range = ReactEditor.toSlateRange(editor, domSelection);
1637
1769
  slate.Transforms.select(editor, range);
1638
1770
  } else {
1639
1771
  slate.Transforms.deselect(editor);
@@ -1778,13 +1910,13 @@ var Editable = props => {
1778
1910
  onCopy: React.useCallback(event => {
1779
1911
  if (hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onCopy)) {
1780
1912
  event.preventDefault();
1781
- setFragmentData(event.clipboardData, editor);
1913
+ ReactEditor.setFragmentData(editor, event.clipboardData);
1782
1914
  }
1783
1915
  }, [attributes.onCopy]),
1784
1916
  onCut: React.useCallback(event => {
1785
1917
  if (!readOnly && hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onCut)) {
1786
1918
  event.preventDefault();
1787
- setFragmentData(event.clipboardData, editor);
1919
+ ReactEditor.setFragmentData(editor, event.clipboardData);
1788
1920
  var {
1789
1921
  selection
1790
1922
  } = editor;
@@ -1820,7 +1952,7 @@ var Editable = props => {
1820
1952
  slate.Transforms.select(editor, range);
1821
1953
  }
1822
1954
 
1823
- setFragmentData(event.dataTransfer, editor);
1955
+ ReactEditor.setFragmentData(editor, event.dataTransfer);
1824
1956
  }
1825
1957
  }, [attributes.onDragStart]),
1826
1958
  onDrop: React.useCallback(event => {
@@ -2101,14 +2233,6 @@ var Editable = props => {
2101
2233
  */
2102
2234
 
2103
2235
  var defaultDecorate = () => [];
2104
- /**
2105
- * Check if two DOM range objects are equal.
2106
- */
2107
-
2108
-
2109
- var isRangeEqual = (a, b) => {
2110
- return a.startContainer === b.startContainer && a.startOffset === b.startOffset && a.endContainer === b.endContainer && a.endOffset === b.endOffset || a.startContainer === b.endContainer && a.startOffset === b.endOffset && a.endContainer === b.startContainer && a.endOffset === b.startOffset;
2111
- };
2112
2236
  /**
2113
2237
  * Check if the target is in the editor.
2114
2238
  */
@@ -2153,124 +2277,6 @@ var isDOMEventHandled = (event, handler) => {
2153
2277
  handler(event);
2154
2278
  return event.defaultPrevented;
2155
2279
  };
2156
- /**
2157
- * Set the currently selected fragment to the clipboard.
2158
- */
2159
-
2160
-
2161
- var setFragmentData = (dataTransfer, editor) => {
2162
- var {
2163
- selection
2164
- } = editor;
2165
-
2166
- if (!selection) {
2167
- return;
2168
- }
2169
-
2170
- var [start, end] = slate.Range.edges(selection);
2171
- var startVoid = slate.Editor.void(editor, {
2172
- at: start.path
2173
- });
2174
- var endVoid = slate.Editor.void(editor, {
2175
- at: end.path
2176
- });
2177
-
2178
- if (slate.Range.isCollapsed(selection) && !startVoid) {
2179
- return;
2180
- } // Create a fake selection so that we can add a Base64-encoded copy of the
2181
- // fragment to the HTML, to decode on future pastes.
2182
-
2183
-
2184
- var domRange = ReactEditor.toDOMRange(editor, selection);
2185
- var contents = domRange.cloneContents();
2186
- var attach = contents.childNodes[0]; // Make sure attach is non-empty, since empty nodes will not get copied.
2187
-
2188
- contents.childNodes.forEach(node => {
2189
- if (node.textContent && node.textContent.trim() !== '') {
2190
- attach = node;
2191
- }
2192
- }); // COMPAT: If the end node is a void node, we need to move the end of the
2193
- // range from the void node's spacer span, to the end of the void node's
2194
- // content, since the spacer is before void's content in the DOM.
2195
-
2196
- if (endVoid) {
2197
- var [voidNode] = endVoid;
2198
- var r = domRange.cloneRange();
2199
- var domNode = ReactEditor.toDOMNode(editor, voidNode);
2200
- r.setEndAfter(domNode);
2201
- contents = r.cloneContents();
2202
- } // COMPAT: If the start node is a void node, we need to attach the encoded
2203
- // fragment to the void node's content node instead of the spacer, because
2204
- // attaching it to empty `<div>/<span>` nodes will end up having it erased by
2205
- // most browsers. (2018/04/27)
2206
-
2207
-
2208
- if (startVoid) {
2209
- attach = contents.querySelector('[data-slate-spacer]');
2210
- } // Remove any zero-width space spans from the cloned DOM so that they don't
2211
- // show up elsewhere when pasted.
2212
-
2213
-
2214
- Array.from(contents.querySelectorAll('[data-slate-zero-width]')).forEach(zw => {
2215
- var isNewline = zw.getAttribute('data-slate-zero-width') === 'n';
2216
- zw.textContent = isNewline ? '\n' : '';
2217
- }); // Set a `data-slate-fragment` attribute on a non-empty node, so it shows up
2218
- // in the HTML, and can be used for intra-Slate pasting. If it's a text
2219
- // node, wrap it in a `<span>` so we have something to set an attribute on.
2220
-
2221
- if (isDOMText(attach)) {
2222
- var span = document.createElement('span'); // COMPAT: In Chrome and Safari, if we don't add the `white-space` style
2223
- // then leading and trailing spaces will be ignored. (2017/09/21)
2224
-
2225
- span.style.whiteSpace = 'pre';
2226
- span.appendChild(attach);
2227
- contents.appendChild(span);
2228
- attach = span;
2229
- }
2230
-
2231
- var fragment = slate.Node.fragment(editor, selection);
2232
- var string = JSON.stringify(fragment);
2233
- var encoded = window.btoa(encodeURIComponent(string));
2234
- attach.setAttribute('data-slate-fragment', encoded);
2235
- dataTransfer.setData('application/x-slate-fragment', encoded); // Add the content to a <div> so that we can get its inner HTML.
2236
-
2237
- var div = document.createElement('div');
2238
- div.appendChild(contents);
2239
- div.setAttribute('hidden', 'true');
2240
- document.body.appendChild(div);
2241
- dataTransfer.setData('text/html', div.innerHTML);
2242
- dataTransfer.setData('text/plain', getPlainText(div));
2243
- document.body.removeChild(div);
2244
- };
2245
- /**
2246
- * Get a plaintext representation of the content of a node, accounting for block
2247
- * elements which get a newline appended.
2248
- *
2249
- * The domNode must be attached to the DOM.
2250
- */
2251
-
2252
-
2253
- var getPlainText = domNode => {
2254
- var text = '';
2255
-
2256
- if (isDOMText(domNode) && domNode.nodeValue) {
2257
- return domNode.nodeValue;
2258
- }
2259
-
2260
- if (isDOMElement(domNode)) {
2261
- for (var childNode of Array.from(domNode.childNodes)) {
2262
- text += getPlainText(childNode);
2263
- }
2264
-
2265
- var display = getComputedStyle(domNode).getPropertyValue('display');
2266
-
2267
- if (display === 'block' || display === 'list' || domNode.tagName === 'BR') {
2268
- text += '\n';
2269
- }
2270
- }
2271
-
2272
- return text;
2273
- };
2274
2280
 
2275
2281
  exports.DefaultElement = DefaultElement;
2276
2282
  exports.DefaultLeaf = DefaultLeaf;