@contentful/field-editor-rich-text 2.0.0-next.26 → 2.0.0-next.29

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.
@@ -1,7 +1,7 @@
1
1
  import React__default, { createContext, useContext, useMemo, createElement, useEffect, useState, memo, Fragment, useCallback } from 'react';
2
2
  import { useEntities, ScheduledIconWithTooltip, MissingEntityCard, AssetThumbnail, EntityProvider, getScheduleTooltipContent } from '@contentful/field-editor-reference';
3
3
  import { entityHelpers, shortenStorageUnit, isValidImage, ModalDialogLauncher, FieldConnector } from '@contentful/field-editor-shared';
4
- import { BLOCKS, INLINES, TABLE_BLOCKS, TEXT_CONTAINERS, HEADINGS, LIST_ITEM_BLOCKS, MARKS, CONTAINERS, TOP_LEVEL_BLOCKS, VOID_BLOCKS, EMPTY_DOCUMENT } from '@contentful/rich-text-types';
4
+ import { BLOCKS, INLINES, TEXT_CONTAINERS, HEADINGS, LIST_ITEM_BLOCKS, MARKS, CONTAINERS, TOP_LEVEL_BLOCKS, VOID_BLOCKS, EMPTY_DOCUMENT } from '@contentful/rich-text-types';
5
5
  import { usePlateEditorRef, usePlateEditorState, getNodes, toggleNodeType, getText, getAbove, setNodes, isAncestorEmpty, match, getLastChildPath, wrapNodes, getPluginType, unwrapNodes, isCollapsed, isRangeAcrossBlocks, ELEMENT_DEFAULT, findNode, getParent, getBlockAbove, isSelectionAtBlockStart, isSelectionAtBlockEnd, isFirstChild, insertNodes, moveChildren, isBlockAboveEmpty, mockPlugin, deleteFragment, isMarkActive, toggleMark, someHtmlElement, KEY_DESERIALIZE_HTML, hasSingleChild, isLastChild, someNode, getChildren as getChildren$1, createDeserializeHtmlPlugin, createDeserializeAstPlugin, createPlateEditor, getPlateSelectors, getPlateActions, Plate } from '@udecode/plate-core';
6
6
  import { css, cx } from 'emotion';
7
7
  import deepEquals from 'fast-deep-equal';
@@ -10,7 +10,7 @@ import { createDeserializeDocxPlugin } from '@udecode/plate-serializer-docx';
10
10
  import { createSoftBreakPlugin as createSoftBreakPlugin$1, createExitBreakPlugin as createExitBreakPlugin$1 } from '@udecode/plate-break';
11
11
  import { createResetNodePlugin as createResetNodePlugin$1, onKeyDownResetNode, SIMULATE_BACKSPACE } from '@udecode/plate-reset-node';
12
12
  import isHotkey from 'is-hotkey';
13
- import { Text, Element, Editor, Transforms, Range, Node, Path, Point } from 'slate';
13
+ import { Text, Element, Editor, Transforms, Range, Path, Node, Point } from 'slate';
14
14
  import { ReactEditor, useSelected, useReadOnly, useFocused } from 'slate-react';
15
15
  import constate from 'constate';
16
16
  import { AssetCard, Menu, Text as Text$1, Notification, EntryCard, MenuItem, Button, Flex, Icon, InlineEntryCard, Tooltip, ModalContent, Form, FormControl, TextInput, Select, FormLabel, TextLink, ModalControls, IconButton } from '@contentful/f36-components';
@@ -26,7 +26,7 @@ import { createBoldPlugin as createBoldPlugin$1, createCodePlugin as createCodeP
26
26
  import isPlainObject from 'is-plain-obj';
27
27
  import { createParagraphPlugin as createParagraphPlugin$1 } from '@udecode/plate-paragraph';
28
28
  import { createSelectOnBackspacePlugin as createSelectOnBackspacePlugin$1 } from '@udecode/plate-select';
29
- import { ELEMENT_TABLE, ELEMENT_TR, getEmptyRowNode, ELEMENT_TD, ELEMENT_TH, getEmptyCellNode, insertTable, deleteRow, deleteColumn, deleteTable, createTablePlugin as createTablePlugin$1, onKeyDownTable } from '@udecode/plate-table';
29
+ import { ELEMENT_TABLE, ELEMENT_TR, getEmptyRowNode, ELEMENT_TD, ELEMENT_TH, getEmptyCellNode, insertTable, deleteRow, deleteColumn, deleteTable, onKeyDownTable as onKeyDownTable$1, getTableCellEntry, createTablePlugin as createTablePlugin$1, withTable } from '@udecode/plate-table';
30
30
  import { toContentfulDocument, toSlatejsDocument } from '@contentful/contentful-slatejs-adapter';
31
31
  import { documentToPlainTextString } from '@contentful/rich-text-plain-text-renderer';
32
32
  import { createTrailingBlockPlugin } from '@udecode/plate-trailing-block';
@@ -454,7 +454,7 @@ function moveToTheNextChar(editor) {
454
454
  unit: 'character'
455
455
  });
456
456
  }
457
- function insertEmptyParagraph(editor) {
457
+ function insertEmptyParagraph(editor, options) {
458
458
  var emptyParagraph = {
459
459
  type: BLOCKS.PARAGRAPH,
460
460
  children: [{
@@ -463,7 +463,7 @@ function insertEmptyParagraph(editor) {
463
463
  data: {},
464
464
  isVoid: false
465
465
  };
466
- Transforms.insertNodes(editor, emptyParagraph);
466
+ Transforms.insertNodes(editor, emptyParagraph, options);
467
467
  }
468
468
  function getElementFromCurrentSelection(editor) {
469
469
  if (!editor.selection) return [];
@@ -583,58 +583,6 @@ function getAncestorPathFromSelection(editor) {
583
583
  return level.length === 1;
584
584
  });
585
585
  }
586
- var isAtEndOfTextSelection = function isAtEndOfTextSelection(editor) {
587
- var _editor$selection2, _editor$selection3;
588
-
589
- return ((_editor$selection2 = editor.selection) == null ? void 0 : _editor$selection2.focus.offset) === getText(editor, (_editor$selection3 = editor.selection) == null ? void 0 : _editor$selection3.focus.path).length;
590
- };
591
- function currentSelectionStartsTableCell(editor) {
592
- var _editor$selection4;
593
-
594
- var _getNodeEntryFromSele2 = getNodeEntryFromSelection(editor, [BLOCKS.TABLE_CELL, BLOCKS.TABLE_HEADER_CELL]),
595
- tableCellNode = _getNodeEntryFromSele2[0],
596
- path = _getNodeEntryFromSele2[1];
597
-
598
- return !!tableCellNode && (!getText(editor, path) || ((_editor$selection4 = editor.selection) == null ? void 0 : _editor$selection4.focus.offset) === 0);
599
- }
600
- /**
601
- * This traversal strategy is unfortunately necessary because Slate doesn't
602
- * expose something like Node.next(editor).
603
- */
604
-
605
- function getNextNode(editor) {
606
- if (!editor.selection) {
607
- return null;
608
- }
609
-
610
- var descendants = Node.descendants(editor, {
611
- from: editor.selection.focus.path
612
- }); // eslint-disable-next-line no-constant-condition
613
-
614
- while (true) {
615
- var _descendants$next = descendants.next(),
616
- done = _descendants$next.done,
617
- value = _descendants$next.value;
618
-
619
- if (done) {
620
- return null;
621
- }
622
-
623
- var node = value[0],
624
- path = value[1];
625
-
626
- if (Path.isCommon(path, editor.selection.focus.path)) {
627
- continue;
628
- }
629
-
630
- return node;
631
- }
632
- } // TODO: move to table plugin
633
-
634
- function currentSelectionPrecedesTableCell(editor) {
635
- var nextNode = getNextNode(editor);
636
- return !!nextNode && TABLE_BLOCKS.includes(nextNode.type) && isAtEndOfTextSelection(editor);
637
- }
638
586
  var INLINE_TYPES = /*#__PURE__*/Object.values(INLINES);
639
587
  var isInlineOrText = function isInlineOrText(node) {
640
588
  // either text or inline elements
@@ -5916,21 +5864,126 @@ var Row = function Row(props) {
5916
5864
  var _templateObject$a;
5917
5865
  var style$5 = /*#__PURE__*/css(_templateObject$a || (_templateObject$a = /*#__PURE__*/_taggedTemplateLiteralLoose(["\n margin-bottom: 1.5em;\n border-collapse: collapse;\n border-radius: 5px;\n border-style: hidden;\n box-shadow: 0 0 0 1px ", ";\n width: 100%;\n table-layout: fixed;\n overflow: hidden;\n"])), tokens.gray400);
5918
5866
  var Table = function Table(props) {
5919
- return /*#__PURE__*/createElement("table", Object.assign({}, props.attributes, {
5867
+ return /*#__PURE__*/createElement("div", {
5868
+ "data-block-type": BLOCKS.TABLE
5869
+ }, /*#__PURE__*/createElement("table", Object.assign({
5920
5870
  className: style$5
5921
- }), /*#__PURE__*/createElement("tbody", null, props.children));
5871
+ }, props.attributes), /*#__PURE__*/createElement("tbody", null, props.children)));
5872
+ };
5873
+
5874
+ /**
5875
+ * Removes table wrappers when pasting a single table cell
5876
+ *
5877
+ * In Plate/Slate, copying the content of a table cell wraps
5878
+ * it in a <table><tr><td>{content}</td></tr></table> even
5879
+ * when copying partial cell content.
5880
+ *
5881
+ * That's really annoying as there is no way to remove the table
5882
+ * wrappers in that case.
5883
+ */
5884
+
5885
+ var trimUnnecessaryTableWrapper = function trimUnnecessaryTableWrapper(node) {
5886
+ if (!Element.isElement(node)) {
5887
+ return [node];
5888
+ } // must be a table with a single row
5889
+
5890
+
5891
+ if (node.type !== BLOCKS.TABLE || node.children.length !== 1) {
5892
+ return [node];
5893
+ }
5894
+
5895
+ var row = node.children[0]; // the row must contain a single cell
5896
+
5897
+ if (row.children.length !== 1) {
5898
+ return [node];
5899
+ }
5900
+
5901
+ var cell = row.children[0];
5902
+ return cell.children;
5903
+ };
5904
+
5905
+ var insertTableFragment = function insertTableFragment(editor) {
5906
+ var insertFragment = editor.insertFragment;
5907
+ return function (fragments) {
5908
+ var _editor$selection;
5909
+
5910
+ if (!editor.selection) {
5911
+ return;
5912
+ }
5913
+
5914
+ fragments = fragments.flatMap(trimUnnecessaryTableWrapper); // We need to make sure we have a new, empty and clean paragraph in order to paste tables as-is due to how Slate behaves
5915
+ // More info: https://github.com/ianstormtaylor/slate/pull/4489 and https://github.com/ianstormtaylor/slate/issues/4542
5916
+
5917
+ var isInsertingTable = fragments.some(function (fragment) {
5918
+ return isTable(fragment);
5919
+ });
5920
+ var isTableFirstFragment = fragments.findIndex(function (fragment) {
5921
+ return isTable(fragment);
5922
+ }) === 0;
5923
+ var currentLineHasText = getText(editor, (_editor$selection = editor.selection) == null ? void 0 : _editor$selection.focus.path) !== '';
5924
+
5925
+ if (isInsertingTable && isTableFirstFragment && currentLineHasText) {
5926
+ insertEmptyParagraph(editor);
5927
+ }
5928
+
5929
+ return insertFragment(fragments);
5930
+ };
5922
5931
  };
5923
5932
 
5924
- var createTableOnKeyDown = function createTableOnKeyDown(editor, plugin) {
5925
- var defaultHandler = onKeyDownTable(editor, plugin);
5933
+ var onKeyDownTable = function onKeyDownTable(editor, plugin) {
5934
+ var defaultHandler = onKeyDownTable$1(editor, plugin);
5926
5935
  return function (event) {
5927
- if (event.key === 'Backspace' && currentSelectionStartsTableCell(editor) || event.key === 'Delete' && currentSelectionPrecedesTableCell(editor)) {
5928
- // The default behavior here would be to delete the preceding or forthcoming
5929
- // leaf node, in this case a cell or header cell. But we don't want to do that,
5930
- // because it would leave us with a non-standard number of table cells.
5936
+ // This fixes `Cannot resolve a Slate point from DOM point: [object HTMLDivElement]` when typing while the cursor is before table
5937
+ var windowSelection = window.getSelection();
5938
+
5939
+ if (windowSelection) {
5940
+ var _windowSelection$anch, _windowSelection$anch2;
5941
+
5942
+ // @ts-expect-error
5943
+ var blockType = (_windowSelection$anch = windowSelection.anchorNode.attributes) == null ? void 0 : (_windowSelection$anch2 = _windowSelection$anch['data-block-type']) == null ? void 0 : _windowSelection$anch2.value; // this attribute comes from `plugins/Table/components/Table.tsx`
5944
+
5945
+ var isBeforeTable = blockType === BLOCKS.TABLE;
5946
+
5947
+ if (isBeforeTable) {
5948
+ if (event.key === 'Enter') {
5949
+ var above = getAbove(editor, {
5950
+ match: {
5951
+ type: BLOCKS.TABLE
5952
+ }
5953
+ });
5954
+ if (!above) return;
5955
+ var tablePath = above[1];
5956
+ insertEmptyParagraph(editor, {
5957
+ at: tablePath,
5958
+ select: true
5959
+ });
5960
+ }
5961
+
5962
+ event.preventDefault();
5963
+ event.stopPropagation();
5964
+ return;
5965
+ }
5966
+ } // Pressing Tab on the last cell creates a new row
5967
+ // Otherwise, jumping between cells is handled in the defaultKeyDownTable
5968
+
5969
+
5970
+ if (event.key === 'Tab' && !event.shiftKey) {
5931
5971
  event.preventDefault();
5932
- event.stopPropagation();
5933
- return;
5972
+ var res = getTableCellEntry(editor, {});
5973
+
5974
+ if (res) {
5975
+ var tableElement = res.tableElement,
5976
+ tableRow = res.tableRow,
5977
+ tableCell = res.tableCell;
5978
+ var isLastCell = isLastChild(tableRow, tableCell[1]);
5979
+ var isLastRow = isLastChild(tableElement, tableRow[1]);
5980
+
5981
+ if (isLastRow && isLastCell) {
5982
+ addRowBelow(editor); // skip default handler
5983
+
5984
+ return;
5985
+ }
5986
+ }
5934
5987
  }
5935
5988
 
5936
5989
  defaultHandler(event);
@@ -5943,32 +5996,13 @@ var createTablePlugin = function createTablePlugin() {
5943
5996
  return createTablePlugin$1({
5944
5997
  type: BLOCKS.TABLE,
5945
5998
  handlers: {
5946
- onKeyDown: createTableOnKeyDown
5999
+ onKeyDown: onKeyDownTable
5947
6000
  },
5948
- withOverrides: function withOverrides(editor) {
6001
+ withOverrides: function withOverrides(editor, plugin) {
6002
+ // injects important fixes from plate's original table plugin
6003
+ withTable(editor, plugin);
5949
6004
  addTableTrackingEvents(editor);
5950
- var insertFragment = editor.insertFragment;
5951
-
5952
- editor.insertFragment = function (fragments) {
5953
- var _editor$selection;
5954
-
5955
- // We need to make sure we have a new, empty and clean paragraph in order to paste tables as-is due to how Slate behaves
5956
- // More info: https://github.com/ianstormtaylor/slate/pull/4489 and https://github.com/ianstormtaylor/slate/issues/4542
5957
- var isInsertingTable = fragments.some(function (fragment) {
5958
- return isTable(fragment);
5959
- });
5960
- var isTableFirstFragment = fragments.findIndex(function (fragment) {
5961
- return isTable(fragment);
5962
- }) === 0;
5963
- var currentLineHasText = getText(editor, (_editor$selection = editor.selection) == null ? void 0 : _editor$selection.focus.path) !== '';
5964
-
5965
- if (isInsertingTable && isTableFirstFragment && currentLineHasText) {
5966
- insertEmptyParagraph(editor);
5967
- }
5968
-
5969
- insertFragment(fragments);
5970
- };
5971
-
6005
+ editor.insertFragment = insertTableFragment(editor);
5972
6006
  return editor;
5973
6007
  },
5974
6008
  overrideByKey: (_overrideByKey = {}, _overrideByKey[ELEMENT_TABLE] = {