@contentful/field-editor-rich-text 2.0.0-next.21 → 2.0.0-next.24

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.
@@ -2,7 +2,7 @@ import React__default, { createContext, useContext, useMemo, createElement, useE
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
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';
5
- import { usePlateEditorState, usePlateEditorRef, getNodes, toggleNodeType, getText, getAbove, setNodes, isAncestorEmpty, getParent, getBlockAbove, isSelectionAtBlockStart, isSelectionAtBlockEnd, isFirstChild, insertNodes, moveChildren, isBlockAboveEmpty, mockPlugin, getPluginType, ELEMENT_DEFAULT, findNode, unwrapNodes, deleteFragment, isCollapsed, isRangeAcrossBlocks, wrapNodes, isMarkActive, toggleMark, someHtmlElement, match, KEY_DESERIALIZE_HTML, hasSingleChild, isLastChild, someNode, getChildren as getChildren$1, getLastChildPath, createDeserializeHtmlPlugin, createDeserializeAstPlugin, createPlateEditor, getPlateActions, Plate } from '@udecode/plate-core';
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';
8
8
  import noop from 'lodash-es/noop';
@@ -20,7 +20,8 @@ import { ClockIcon, AssetIcon, EmbeddedEntryBlockIcon, EmbeddedEntryInlineIcon,
20
20
  import tokens from '@contentful/f36-tokens';
21
21
  import find from 'lodash-es/find';
22
22
  import flow from 'lodash-es/flow';
23
- import { getListItemEntry, moveListItemUp, ELEMENT_LI, unwrapList as unwrapList$1, removeFirstListItem, removeListItem, isListNested, deleteForwardList, deleteFragmentList, normalizeList, createListPlugin as createListPlugin$1, ELEMENT_UL, ELEMENT_OL, ELEMENT_LIC } from '@udecode/plate-list';
23
+ import { getListTypes, ELEMENT_LIC, getListItemEntry, isListNested, moveListItemUp, ELEMENT_LI, unwrapList as unwrapList$1, removeFirstListItem, removeListItem, deleteForwardList, deleteFragmentList, normalizeList, createListPlugin as createListPlugin$1, ELEMENT_UL, ELEMENT_OL } from '@udecode/plate-list';
24
+ import castArray from 'lodash-es/castArray';
24
25
  import { createBoldPlugin as createBoldPlugin$1, createCodePlugin as createCodePlugin$1, createItalicPlugin as createItalicPlugin$1, createUnderlinePlugin as createUnderlinePlugin$1 } from '@udecode/plate-basic-marks';
25
26
  import isPlainObject from 'is-plain-obj';
26
27
  import { createParagraphPlugin as createParagraphPlugin$1 } from '@udecode/plate-paragraph';
@@ -419,10 +420,12 @@ function isBlockSelected(editor, type) {
419
420
  function isRootLevel(path) {
420
421
  return path.length === 1;
421
422
  }
422
- function getNodeEntryFromSelection(editor, nodeTypeOrTypes) {
423
- if (!editor.selection) return [];
423
+ function getNodeEntryFromSelection(editor, nodeTypeOrTypes, path) {
424
+ var _path, _editor$selection;
425
+
426
+ path = (_path = path) != null ? _path : (_editor$selection = editor.selection) == null ? void 0 : _editor$selection.focus.path;
427
+ if (!path) return [];
424
428
  var nodeTypes = Array.isArray(nodeTypeOrTypes) ? nodeTypeOrTypes : [nodeTypeOrTypes];
425
- var path = editor.selection.focus.path;
426
429
 
427
430
  for (var i = 0; i < path.length; i++) {
428
431
  var nodeEntry = Editor.node(editor, path.slice(0, i + 1));
@@ -581,18 +584,18 @@ function getAncestorPathFromSelection(editor) {
581
584
  });
582
585
  }
583
586
  var isAtEndOfTextSelection = function isAtEndOfTextSelection(editor) {
584
- var _editor$selection, _editor$selection2;
587
+ var _editor$selection2, _editor$selection3;
585
588
 
586
- return ((_editor$selection = editor.selection) == null ? void 0 : _editor$selection.focus.offset) === getText(editor, (_editor$selection2 = editor.selection) == null ? void 0 : _editor$selection2.focus.path).length;
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;
587
590
  };
588
591
  function currentSelectionStartsTableCell(editor) {
589
- var _editor$selection3;
592
+ var _editor$selection4;
590
593
 
591
594
  var _getNodeEntryFromSele2 = getNodeEntryFromSelection(editor, [BLOCKS.TABLE_CELL, BLOCKS.TABLE_HEADER_CELL]),
592
595
  tableCellNode = _getNodeEntryFromSele2[0],
593
596
  path = _getNodeEntryFromSele2[1];
594
597
 
595
- return !!tableCellNode && (!getText(editor, path) || ((_editor$selection3 = editor.selection) == null ? void 0 : _editor$selection3.focus.offset) === 0);
598
+ return !!tableCellNode && (!getText(editor, path) || ((_editor$selection4 = editor.selection) == null ? void 0 : _editor$selection4.focus.offset) === 0);
596
599
  }
597
600
  /**
598
601
  * This traversal strategy is unfortunately necessary because Slate doesn't
@@ -944,14 +947,22 @@ function FetchingWrappedEntryCard(props) {
944
947
  var onEntityFetchComplete = props.onEntityFetchComplete;
945
948
  useEffect(function () {
946
949
  if (!entry || entry === 'failed') return;
950
+ var subscribed = true;
947
951
  entityHelpers.getEntryImage({
948
952
  entry: entry,
949
953
  contentType: contentType,
950
954
  localeCode: props.locale,
951
955
  defaultLocaleCode: defaultLocaleCode
952
- }, getOrLoadAsset).then(setFile)["catch"](function () {
953
- return setFile(null);
956
+ }, getOrLoadAsset)["catch"](function () {
957
+ return null;
958
+ }).then(function (file) {
959
+ if (subscribed) {
960
+ setFile(file);
961
+ }
954
962
  });
963
+ return function () {
964
+ subscribed = false;
965
+ };
955
966
  }, [entry, contentType, props.locale, defaultLocaleCode, props.sdk, file, getOrLoadAsset]);
956
967
  useEffect(function () {
957
968
  getOrLoadEntry(props.entryId);
@@ -1046,7 +1057,14 @@ function FetchingWrappedEntryCard(props) {
1046
1057
 
1047
1058
  var styles$3 = {
1048
1059
  root: /*#__PURE__*/css({
1049
- marginBottom: '1.25rem !important'
1060
+ marginBottom: '1.25rem !important',
1061
+ display: 'block'
1062
+ }),
1063
+ container: /*#__PURE__*/css({
1064
+ // The next 2 properties ensure Entity card won't be aligned above
1065
+ // a list item marker (i.e. bullet)
1066
+ display: 'inline-block',
1067
+ verticalAlign: 'text-top'
1050
1068
  })
1051
1069
  };
1052
1070
  function LinkedEntityBlock(props) {
@@ -1087,7 +1105,8 @@ function LinkedEntityBlock(props) {
1087
1105
  }), /*#__PURE__*/React__default.createElement("div", {
1088
1106
  // COMPAT: This makes copy & paste work for Chromium/Blink browsers and Safari
1089
1107
  contentEditable: HAS_BEFORE_INPUT_SUPPORT ? false : undefined,
1090
- draggable: HAS_BEFORE_INPUT_SUPPORT ? true : undefined
1108
+ draggable: HAS_BEFORE_INPUT_SUPPORT ? true : undefined,
1109
+ className: styles$3.container
1091
1110
  }, entityType === 'Entry' && /*#__PURE__*/React__default.createElement(FetchingWrappedEntryCard, {
1092
1111
  sdk: sdk,
1093
1112
  entryId: entityId,
@@ -3190,29 +3209,31 @@ function HyperlinkModal(props) {
3190
3209
  testId: "confirm-cta"
3191
3210
  }, props.linkType ? 'Update' : 'Insert'))));
3192
3211
  }
3193
- function addOrEditLink(_x, _x2, _x3) {
3212
+ function addOrEditLink(_x, _x2, _x3, _x4) {
3194
3213
  return _addOrEditLink.apply(this, arguments);
3195
3214
  }
3196
3215
 
3197
3216
  function _addOrEditLink() {
3198
- _addOrEditLink = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee3(editor, sdk, logAction) {
3217
+ _addOrEditLink = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee3(editor, sdk, logAction, targetPath) {
3199
3218
  var _target$sys$linkType;
3200
3219
 
3201
- var linkType, linkText, linkTarget, linkEntity, _getNodeEntryFromSele, node, path, selectionBeforeBlur, currentLinkText, isEditing, data, text, url, type, target;
3220
+ var selectionBeforeBlur, linkType, linkText, linkTarget, linkEntity, _getNodeEntryFromSele, node, path, selectionAfterFocus, currentLinkText, isEditing, data, text, url, type, target;
3202
3221
 
3203
3222
  return runtime_1.wrap(function _callee3$(_context3) {
3204
3223
  while (1) {
3205
3224
  switch (_context3.prev = _context3.next) {
3206
3225
  case 0:
3207
- if (editor.selection) {
3208
- _context3.next = 2;
3226
+ selectionBeforeBlur = editor.selection ? _extends({}, editor.selection) : undefined;
3227
+
3228
+ if (!(!targetPath && !selectionBeforeBlur)) {
3229
+ _context3.next = 3;
3209
3230
  break;
3210
3231
  }
3211
3232
 
3212
3233
  return _context3.abrupt("return");
3213
3234
 
3214
- case 2:
3215
- _getNodeEntryFromSele = getNodeEntryFromSelection(editor, LINK_TYPES), node = _getNodeEntryFromSele[0], path = _getNodeEntryFromSele[1];
3235
+ case 3:
3236
+ _getNodeEntryFromSele = getNodeEntryFromSelection(editor, LINK_TYPES, targetPath), node = _getNodeEntryFromSele[0], path = _getNodeEntryFromSele[1];
3216
3237
 
3217
3238
  if (node && path) {
3218
3239
  linkType = node.type;
@@ -3221,11 +3242,11 @@ function _addOrEditLink() {
3221
3242
  linkEntity = node.data.target;
3222
3243
  }
3223
3244
 
3224
- selectionBeforeBlur = _extends({}, editor.selection);
3225
- currentLinkText = linkText || Editor.string(editor, editor.selection);
3245
+ selectionAfterFocus = targetPath != null ? targetPath : selectionBeforeBlur;
3246
+ currentLinkText = linkText || (editor.selection ? Editor.string(editor, editor.selection) : '');
3226
3247
  isEditing = Boolean(node && path);
3227
3248
  logAction(isEditing ? 'openEditHyperlinkDialog' : 'openCreateHyperlinkDialog');
3228
- _context3.next = 10;
3249
+ _context3.next = 11;
3229
3250
  return ModalDialogLauncher.openDialog({
3230
3251
  title: isEditing ? 'Edit hyperlink' : 'Insert hyperlink',
3231
3252
  width: 'large',
@@ -3244,20 +3265,21 @@ function _addOrEditLink() {
3244
3265
  });
3245
3266
  });
3246
3267
 
3247
- case 10:
3268
+ case 11:
3248
3269
  data = _context3.sent;
3270
+ Transforms.select(editor, selectionAfterFocus);
3249
3271
 
3250
3272
  if (data) {
3251
- _context3.next = 14;
3273
+ _context3.next = 17;
3252
3274
  break;
3253
3275
  }
3254
3276
 
3277
+ focus(editor);
3255
3278
  logAction(isEditing ? 'cancelEditHyperlinkDialog' : 'cancelCreateHyperlinkDialog');
3256
3279
  return _context3.abrupt("return");
3257
3280
 
3258
- case 14:
3281
+ case 17:
3259
3282
  text = data.linkText, url = data.linkTarget, type = data.linkType, target = data.linkEntity;
3260
- Transforms.select(editor, selectionBeforeBlur);
3261
3283
  Editor.withoutNormalizing(editor, function () {
3262
3284
  insertLink(editor, {
3263
3285
  text: text,
@@ -3273,7 +3295,7 @@ function _addOrEditLink() {
3273
3295
  });
3274
3296
  focus(editor);
3275
3297
 
3276
- case 19:
3298
+ case 21:
3277
3299
  case "end":
3278
3300
  return _context3.stop();
3279
3301
  }
@@ -3527,7 +3549,11 @@ function EntityHyperlink(props) {
3527
3549
  event.preventDefault();
3528
3550
  event.stopPropagation();
3529
3551
  if (!editor) return;
3530
- addOrEditLink(editor, sdk, editor.tracking.onViewportAction);
3552
+ var p = ReactEditor.toSlatePoint(editor, [event.target, 0], {
3553
+ exactMatch: false,
3554
+ suppressThrow: false
3555
+ });
3556
+ addOrEditLink(editor, sdk, editor.tracking.onViewportAction, p.path);
3531
3557
  }
3532
3558
 
3533
3559
  return /*#__PURE__*/createElement(Tooltip, {
@@ -3555,7 +3581,11 @@ function UrlHyperlink(props) {
3555
3581
  event.preventDefault();
3556
3582
  event.stopPropagation();
3557
3583
  if (!editor) return;
3558
- addOrEditLink(editor, sdk, editor.tracking.onViewportAction);
3584
+ var p = ReactEditor.toSlatePoint(editor, [event.target, 0], {
3585
+ exactMatch: false,
3586
+ suppressThrow: false
3587
+ });
3588
+ addOrEditLink(editor, sdk, editor.tracking.onViewportAction, p.path);
3559
3589
  }
3560
3590
 
3561
3591
  return /*#__PURE__*/createElement(Tooltip, {
@@ -3716,245 +3746,586 @@ function ListItem(props) {
3716
3746
  }), props.children);
3717
3747
  }
3718
3748
 
3719
- var isList = function isList(node) {
3720
- return [BLOCKS.OL_LIST, BLOCKS.UL_LIST].includes(node.type);
3721
- };
3722
-
3723
- var hasListAsDirectParent = function hasListAsDirectParent(editor, _ref) {
3724
- var path = _ref[1];
3725
-
3726
- var _ref2 = getParent(editor, path) || [],
3727
- parentNode = _ref2[0];
3728
-
3729
- return isList(parentNode);
3730
- };
3731
-
3732
- var getNearestListAncestor = function getNearestListAncestor(editor, path) {
3733
- return getAbove(editor, {
3734
- at: path,
3735
- mode: 'lowest',
3736
- match: isList
3737
- }) || [];
3738
- };
3739
3749
  /**
3740
- * Places orphaned list items in a list. If there's a list somewhere
3741
- * in the node's ancestors, defaults to that list type, else places
3742
- * the list item in an unordered list.
3750
+ * Credit: Modified version of Plate's list plugin
3751
+ * See: https://github.com/udecode/plate/blob/main/packages/nodes/list
3743
3752
  */
3753
+ var moveListItemDown = function moveListItemDown(editor, _ref) {
3754
+ var list = _ref.list,
3755
+ listItem = _ref.listItem;
3756
+ var listNode = list[0];
3757
+ var listItemPath = listItem[1];
3758
+ var previousListItemPath;
3744
3759
 
3760
+ try {
3761
+ previousListItemPath = Path.previous(listItemPath);
3762
+ } catch (e) {
3763
+ return;
3764
+ } // Previous sibling is the new parent
3745
3765
 
3746
- var normalizeOrphanedListItem = function normalizeOrphanedListItem(editor, _ref3) {
3747
- var path = _ref3[1];
3748
-
3749
- var _getNearestListAncest = getNearestListAncestor(editor, path),
3750
- parentList = _getNearestListAncest[0];
3751
-
3752
- var parentListType = parentList == null ? void 0 : parentList.type;
3753
- Transforms.wrapNodes(editor, {
3754
- type: parentListType || BLOCKS.UL_LIST,
3755
- children: [],
3756
- data: {}
3757
- }, {
3758
- at: path
3759
- });
3760
- };
3761
- var isNonEmptyListItem = function isNonEmptyListItem(editor, _ref4) {
3762
- var path = _ref4[1];
3763
- var listItemChildren = Array.from(Node.children(editor, path));
3764
- return listItemChildren.length !== 0;
3765
- };
3766
- var firstNodeIsNotList = function firstNodeIsNotList(_editor, _ref5) {
3767
- var node = _ref5[0];
3768
-
3769
- if (node.children.length === 1) {
3770
- var firstNode = node.children[0];
3771
- return !Text.isText(firstNode) && !isList(firstNode);
3772
- }
3773
-
3774
- return true;
3775
- };
3776
- var insertParagraphAsChild = function insertParagraphAsChild(editor, _ref6) {
3777
- var path = _ref6[1];
3778
- Transforms.insertNodes(editor, [{
3779
- type: BLOCKS.PARAGRAPH,
3780
- data: {},
3781
- children: [{
3782
- text: ''
3783
- }]
3784
- }], {
3785
- at: path.concat([0])
3786
- });
3787
- };
3788
- var replaceNodeWithListItems = function replaceNodeWithListItems(editor, entry) {
3789
- var node = entry[0],
3790
- path = entry[1];
3791
- Transforms.removeNodes(editor, {
3792
- at: path
3793
- });
3794
- Transforms.insertNodes(editor, node.children[0].children, {
3795
- at: path
3796
- });
3797
- };
3798
- var isListTypeActive = function isListTypeActive(editor, type) {
3799
- // Lists can be nested. Here, we take the list type at the lowest level
3800
- var listNode = getBlockAbove(editor, {
3801
- match: {
3802
- type: [BLOCKS.OL_LIST, BLOCKS.UL_LIST]
3803
- },
3804
- mode: 'lowest'
3805
- });
3806
- return (listNode == null ? void 0 : listNode[0].type) === type;
3807
- };
3808
3766
 
3809
- /**
3810
- * Build a new list item node while preserving marks
3811
- */
3767
+ var previousSiblingItem = Editor.node(editor, previousListItemPath);
3812
3768
 
3813
- var emptyListItemNode = function emptyListItemNode(editor, withChildren) {
3814
- if (withChildren === void 0) {
3815
- withChildren = false;
3816
- }
3769
+ if (previousSiblingItem) {
3770
+ var previousPath = previousSiblingItem[1];
3771
+ var subList = Array.from(Node.children(editor, previousPath)).find(function (_ref2) {
3772
+ var n = _ref2[0];
3773
+ return match(n, {
3774
+ type: getListTypes(editor)
3775
+ });
3776
+ });
3777
+ var newPath = Path.next(getLastChildPath(subList != null ? subList : previousSiblingItem));
3778
+ Editor.withoutNormalizing(editor, function () {
3779
+ if (!subList) {
3780
+ // Create new sub-list
3781
+ wrapNodes(editor, {
3782
+ type: listNode.type,
3783
+ children: [],
3784
+ data: {}
3785
+ }, {
3786
+ at: listItemPath
3787
+ });
3788
+ } // Move the current item to the sub-list
3817
3789
 
3818
- var children = [];
3819
3790
 
3820
- if (withChildren) {
3821
- var marks = Editor.marks(editor) || {};
3822
- children = [{
3823
- type: BLOCKS.PARAGRAPH,
3824
- data: {},
3825
- children: [_extends({
3826
- text: ''
3827
- }, marks)]
3828
- }];
3791
+ Transforms.moveNodes(editor, {
3792
+ at: listItemPath,
3793
+ to: newPath
3794
+ });
3795
+ });
3829
3796
  }
3830
-
3831
- return {
3832
- type: BLOCKS.LIST_ITEM,
3833
- data: {},
3834
- children: children
3835
- };
3836
3797
  };
3798
+
3837
3799
  /**
3838
- * Insert list item if selection is in li>p.
3800
+ * Credit: Modified version of Plate's list plugin
3801
+ * See: https://github.com/udecode/plate/blob/main/packages/nodes/list
3839
3802
  */
3803
+ var moveListItems = function moveListItems(editor, _temp) {
3804
+ var _editor$selection;
3840
3805
 
3806
+ var _ref = _temp === void 0 ? {} : _temp,
3807
+ _ref$increase = _ref.increase,
3808
+ increase = _ref$increase === void 0 ? true : _ref$increase,
3809
+ _ref$at = _ref.at,
3810
+ at = _ref$at === void 0 ? (_editor$selection = editor.selection) != null ? _editor$selection : undefined : _ref$at;
3841
3811
 
3842
- var insertListItem = function insertListItem(editor) {
3843
- if (!editor.selection) {
3844
- return false;
3845
- } // Naming it paragraph for simplicity but can be a heading as well
3846
-
3847
-
3848
- var paragraph = getAbove(editor, {
3812
+ var _nodes = getNodes(editor, {
3813
+ at: at,
3849
3814
  match: {
3850
- type: TEXT_CONTAINERS
3815
+ type: getPluginType(editor, ELEMENT_LIC)
3851
3816
  }
3852
- });
3853
-
3854
- if (!paragraph) {
3855
- return false;
3856
- }
3857
-
3858
- var paragraphPath = paragraph[1];
3859
- var listItem = getParent(editor, paragraphPath);
3860
-
3861
- if (!listItem) {
3862
- return false;
3863
- }
3817
+ }); // Get the selected lic
3864
3818
 
3865
- var listItemNode = listItem[0],
3866
- listItemPath = listItem[1];
3867
3819
 
3868
- if (listItemNode.type !== BLOCKS.LIST_ITEM) {
3869
- return false;
3870
- } // We are in a li>p (or heading)
3820
+ var lics = Array.from(_nodes);
3821
+ if (!lics.length) return;
3822
+ var highestLicPaths = [];
3823
+ var highestLicPathRefs = []; // Filter out the nested lic, we just need to move the highest ones
3871
3824
 
3825
+ lics.forEach(function (lic) {
3826
+ var licPath = lic[1];
3827
+ var liPath = Path.parent(licPath);
3828
+ var isAncestor = highestLicPaths.some(function (path) {
3829
+ var highestLiPath = Path.parent(path);
3830
+ return Path.isAncestor(highestLiPath, liPath);
3831
+ });
3872
3832
 
3833
+ if (!isAncestor) {
3834
+ highestLicPaths.push(licPath);
3835
+ highestLicPathRefs.push(Editor.pathRef(editor, licPath));
3836
+ }
3837
+ });
3838
+ var licPathRefsToMove = increase ? highestLicPathRefs : highestLicPathRefs.reverse();
3873
3839
  Editor.withoutNormalizing(editor, function () {
3874
- if (!editor.selection) {
3875
- return;
3876
- } // Check the cursor position in the current paragraph
3877
-
3878
-
3879
- var isAtStart = isSelectionAtBlockStart(editor);
3880
- var isAtEnd = isSelectionAtBlockEnd(editor);
3881
- var isAtStartOfListItem = isAtStart && isFirstChild(paragraphPath);
3882
- var shouldSplit = !isAtStart && !isAtEnd; // Split the current paragraph content if necessary
3883
-
3884
- if (shouldSplit) {
3885
- Transforms.splitNodes(editor);
3886
- } // Insert the new li
3887
-
3888
-
3889
- var newListItemPath = isAtStartOfListItem ? listItemPath : Path.next(listItemPath);
3890
- insertNodes(editor, // Add an empty paragraph to the new li if We will not move some
3891
- // paragraphs over there.
3892
- emptyListItemNode(editor, !shouldSplit), {
3893
- at: newListItemPath
3894
- }); // Move children *after* selection to the new li
3895
-
3896
- var fromPath = isAtStart ? paragraphPath : Path.next(paragraphPath);
3897
- var fromStartIndex = fromPath[fromPath.length - 1] || 0; // On split we don't add paragraph to the new li so we move
3898
- // content to the very beginning. Otherwise, account for the empty
3899
- // paragraph at the beginning by moving the content after
3900
-
3901
- var toPath = newListItemPath.concat([shouldSplit ? 0 : 1]);
3902
-
3903
- if (!isAtStartOfListItem) {
3904
- moveChildren(editor, {
3905
- at: listItemPath,
3906
- to: toPath,
3907
- fromStartIndex: fromStartIndex
3840
+ licPathRefsToMove.forEach(function (licPathRef) {
3841
+ var licPath = licPathRef.unref();
3842
+ if (!licPath) return;
3843
+ var liEntry = getListItemEntry(editor, {
3844
+ at: licPath
3908
3845
  });
3909
- } // Move cursor to the start of the new li
3910
3846
 
3847
+ if (!liEntry) {
3848
+ return;
3849
+ }
3911
3850
 
3912
- Transforms.select(editor, newListItemPath);
3913
- Transforms.collapse(editor, {
3914
- edge: 'start'
3851
+ if (increase) {
3852
+ moveListItemDown(editor, liEntry);
3853
+ } else if (isListNested(editor, liEntry.list[1])) {
3854
+ moveListItemUp(editor, liEntry);
3855
+ }
3915
3856
  });
3916
- }); // Returning True skips processing other editor.insertBreak handlers
3917
-
3918
- return true;
3857
+ });
3919
3858
  };
3920
3859
 
3921
3860
  /**
3922
- * Credit: Copied & modified version from Plate's list plugin to support
3923
- * list items with multiple children.
3924
- *
3861
+ * Credit: Modified version of Plate's list plugin
3925
3862
  * See: https://github.com/udecode/plate/blob/main/packages/nodes/list
3926
3863
  */
3864
+ var listTypes = [BLOCKS.UL_LIST, BLOCKS.OL_LIST];
3865
+ var unwrapList = function unwrapList(editor, _temp) {
3866
+ var _ref = _temp === void 0 ? {} : _temp,
3867
+ at = _ref.at;
3927
3868
 
3928
- var listBreak = function listBreak(editor) {
3929
- if (!editor.selection) return false;
3930
- var res = getListItemEntry(editor, {});
3931
- var moved; // If selection is in a li
3932
-
3933
- if (res) {
3934
- var list = res.list,
3935
- listItem = res.listItem;
3936
- var childNode = listItem[0].children[0]; // If selected li is empty, move it up.
3937
-
3938
- if (isBlockAboveEmpty(editor) && listItem[0].children.length === 1 && TEXT_CONTAINERS.includes(childNode.type)) {
3939
- moved = moveListItemUp(editor, {
3940
- list: list,
3941
- listItem: listItem
3942
- });
3943
- if (moved) return true;
3944
- }
3945
- }
3946
-
3947
- var didReset = onKeyDownResetNode(editor, mockPlugin({
3948
- options: {
3949
- rules: [{
3950
- types: [getPluginType(editor, ELEMENT_LI)],
3951
- defaultType: getPluginType(editor, ELEMENT_DEFAULT),
3952
- predicate: function predicate() {
3953
- return !moved && isBlockAboveEmpty(editor);
3869
+ Editor.withoutNormalizing(editor, function () {
3870
+ do {
3871
+ unwrapNodes(editor, {
3872
+ at: at,
3873
+ match: {
3874
+ type: BLOCKS.LIST_ITEM
3954
3875
  },
3955
- onReset: function onReset(_editor) {
3956
- return unwrapList$1(_editor);
3957
- }
3876
+ split: true
3877
+ });
3878
+ unwrapNodes(editor, {
3879
+ at: at,
3880
+ match: {
3881
+ type: listTypes
3882
+ },
3883
+ split: true
3884
+ });
3885
+ } while (getAbove(editor, {
3886
+ match: {
3887
+ type: listTypes,
3888
+ at: at
3889
+ }
3890
+ }));
3891
+ });
3892
+ };
3893
+
3894
+ var listTypes$1 = [BLOCKS.UL_LIST, BLOCKS.OL_LIST];
3895
+ var toggleList = function toggleList(editor, _ref) {
3896
+ var type = _ref.type;
3897
+ return Editor.withoutNormalizing(editor, function () {
3898
+ if (!editor.selection) {
3899
+ return;
3900
+ }
3901
+
3902
+ if (isCollapsed(editor.selection) || !isRangeAcrossBlocks(editor)) {
3903
+ // selection is collapsed
3904
+ var res = getListItemEntry(editor);
3905
+
3906
+ if (res) {
3907
+ var list = res.list;
3908
+
3909
+ if (list[0].type !== type) {
3910
+ setNodes(editor, {
3911
+ type: type
3912
+ }, {
3913
+ at: editor.selection,
3914
+ match: function match(n) {
3915
+ return listTypes$1.includes(n.type);
3916
+ },
3917
+ mode: 'lowest'
3918
+ });
3919
+ } else {
3920
+ unwrapList(editor);
3921
+ }
3922
+ } else {
3923
+ var _list = {
3924
+ type: type,
3925
+ children: [],
3926
+ data: {}
3927
+ };
3928
+ wrapNodes(editor, _list);
3929
+ var nodes = [].concat(getNodes(editor, {
3930
+ match: {
3931
+ type: getPluginType(editor, ELEMENT_DEFAULT)
3932
+ }
3933
+ }));
3934
+ var listItem = {
3935
+ type: BLOCKS.LIST_ITEM,
3936
+ children: [],
3937
+ data: {}
3938
+ };
3939
+
3940
+ for (var _iterator = _createForOfIteratorHelperLoose(nodes), _step; !(_step = _iterator()).done;) {
3941
+ var _step$value = _step.value,
3942
+ path = _step$value[1];
3943
+ wrapNodes(editor, listItem, {
3944
+ at: path
3945
+ });
3946
+ }
3947
+ }
3948
+ } else {
3949
+ // selection is a range
3950
+ var _Range$edges = Range.edges(editor.selection),
3951
+ startPoint = _Range$edges[0],
3952
+ endPoint = _Range$edges[1];
3953
+
3954
+ var commonEntry = Node.common(editor, startPoint.path, endPoint.path);
3955
+
3956
+ if (listTypes$1.includes(commonEntry[0].type) || commonEntry[0].type === BLOCKS.LIST_ITEM) {
3957
+ if (commonEntry[0].type !== type) {
3958
+ var startList = findNode(editor, {
3959
+ at: Range.start(editor.selection),
3960
+ match: {
3961
+ type: listTypes$1
3962
+ },
3963
+ mode: 'lowest'
3964
+ });
3965
+ var endList = findNode(editor, {
3966
+ at: Range.end(editor.selection),
3967
+ match: {
3968
+ type: listTypes$1
3969
+ },
3970
+ mode: 'lowest'
3971
+ });
3972
+
3973
+ if (!startList || !endList) {
3974
+ return;
3975
+ }
3976
+
3977
+ var rangeLength = Math.min(startList[1].length, endList[1].length);
3978
+ setNodes(editor, {
3979
+ type: type
3980
+ }, {
3981
+ at: editor.selection,
3982
+ match: function match(n, path) {
3983
+ return listTypes$1.includes(n.type) && path.length >= rangeLength;
3984
+ },
3985
+ mode: 'all'
3986
+ });
3987
+ } else {
3988
+ unwrapList(editor);
3989
+ }
3990
+ } else {
3991
+ var rootPathLength = commonEntry[1].length;
3992
+
3993
+ var _nodes = Array.from(getNodes(editor, {
3994
+ mode: 'all'
3995
+ })).filter(function (_ref2) {
3996
+ var path = _ref2[1];
3997
+ return path.length === rootPathLength + 1;
3998
+ }).reverse();
3999
+
4000
+ _nodes.forEach(function (n) {
4001
+ if (listTypes$1.includes(n[0].type)) {
4002
+ setNodes(editor, {
4003
+ type: type
4004
+ }, {
4005
+ at: n[1]
4006
+ });
4007
+ } else {
4008
+ setNodes(editor, {
4009
+ type: getPluginType(editor, ELEMENT_LIC)
4010
+ }, {
4011
+ at: n[1]
4012
+ });
4013
+ var _listItem = {
4014
+ type: BLOCKS.LIST_ITEM,
4015
+ children: [],
4016
+ data: {}
4017
+ };
4018
+ wrapNodes(editor, _listItem, {
4019
+ at: n[1]
4020
+ });
4021
+ var _list2 = {
4022
+ type: type,
4023
+ children: [],
4024
+ data: {}
4025
+ };
4026
+ wrapNodes(editor, _list2, {
4027
+ at: n[1]
4028
+ });
4029
+ }
4030
+ });
4031
+ }
4032
+ }
4033
+ });
4034
+ };
4035
+
4036
+ var onKeyDownList = function onKeyDownList(editor, _ref) {
4037
+ var type = _ref.type,
4038
+ hotkey = _ref.options.hotkey;
4039
+ return function (e) {
4040
+ if (e.key === 'Tab' && editor.selection) {
4041
+ var listSelected = getAbove(editor, {
4042
+ at: editor.selection,
4043
+ match: {
4044
+ type: type
4045
+ }
4046
+ });
4047
+
4048
+ if (listSelected) {
4049
+ e.preventDefault();
4050
+ moveListItems(editor, {
4051
+ increase: !e.shiftKey
4052
+ });
4053
+ return;
4054
+ }
4055
+ }
4056
+
4057
+ if (!hotkey) return;
4058
+ var hotkeys = castArray(hotkey);
4059
+
4060
+ for (var _iterator = _createForOfIteratorHelperLoose(hotkeys), _step; !(_step = _iterator()).done;) {
4061
+ var _hotkey = _step.value;
4062
+
4063
+ if (isHotkey(_hotkey)(e)) {
4064
+ toggleList(editor, {
4065
+ type: type
4066
+ });
4067
+ }
4068
+ }
4069
+ };
4070
+ };
4071
+
4072
+ var isList = function isList(node) {
4073
+ return [BLOCKS.OL_LIST, BLOCKS.UL_LIST].includes(node.type);
4074
+ };
4075
+
4076
+ var hasListAsDirectParent = function hasListAsDirectParent(editor, _ref) {
4077
+ var path = _ref[1];
4078
+
4079
+ var _ref2 = getParent(editor, path) || [],
4080
+ parentNode = _ref2[0];
4081
+
4082
+ return isList(parentNode);
4083
+ };
4084
+
4085
+ var getNearestListAncestor = function getNearestListAncestor(editor, path) {
4086
+ return getAbove(editor, {
4087
+ at: path,
4088
+ mode: 'lowest',
4089
+ match: isList
4090
+ }) || [];
4091
+ };
4092
+ /**
4093
+ * Places orphaned list items in a list. If there's a list somewhere
4094
+ * in the node's ancestors, defaults to that list type, else places
4095
+ * the list item in an unordered list.
4096
+ */
4097
+
4098
+
4099
+ var normalizeOrphanedListItem = function normalizeOrphanedListItem(editor, _ref3) {
4100
+ var path = _ref3[1];
4101
+
4102
+ var _getNearestListAncest = getNearestListAncestor(editor, path),
4103
+ parentList = _getNearestListAncest[0];
4104
+
4105
+ var parentListType = parentList == null ? void 0 : parentList.type;
4106
+ Transforms.wrapNodes(editor, {
4107
+ type: parentListType || BLOCKS.UL_LIST,
4108
+ children: [],
4109
+ data: {}
4110
+ }, {
4111
+ at: path
4112
+ });
4113
+ };
4114
+ var isNonEmptyListItem = function isNonEmptyListItem(editor, _ref4) {
4115
+ var path = _ref4[1];
4116
+ var listItemChildren = Array.from(Node.children(editor, path));
4117
+ return listItemChildren.length !== 0;
4118
+ };
4119
+ var firstNodeIsNotList = function firstNodeIsNotList(_editor, _ref5) {
4120
+ var node = _ref5[0];
4121
+
4122
+ if (node.children.length === 1) {
4123
+ var firstNode = node.children[0];
4124
+ return !Text.isText(firstNode) && !isList(firstNode);
4125
+ }
4126
+
4127
+ return true;
4128
+ };
4129
+ var insertParagraphAsChild = function insertParagraphAsChild(editor, _ref6) {
4130
+ var path = _ref6[1];
4131
+ Transforms.insertNodes(editor, [{
4132
+ type: BLOCKS.PARAGRAPH,
4133
+ data: {},
4134
+ children: [{
4135
+ text: ''
4136
+ }]
4137
+ }], {
4138
+ at: path.concat([0])
4139
+ });
4140
+ };
4141
+ var replaceNodeWithListItems = function replaceNodeWithListItems(editor, entry) {
4142
+ var node = entry[0],
4143
+ path = entry[1];
4144
+ Transforms.removeNodes(editor, {
4145
+ at: path
4146
+ });
4147
+ Transforms.insertNodes(editor, node.children[0].children, {
4148
+ at: path
4149
+ });
4150
+ };
4151
+ var isListTypeActive = function isListTypeActive(editor, type) {
4152
+ var selection = editor.selection;
4153
+
4154
+ if (!selection) {
4155
+ return false;
4156
+ }
4157
+
4158
+ if (Range.isExpanded(selection)) {
4159
+ var _Range$edges = Range.edges(selection),
4160
+ start = _Range$edges[0],
4161
+ end = _Range$edges[1];
4162
+
4163
+ var node = Node.common(editor, start.path, end.path);
4164
+
4165
+ if (node[0].type === type) {
4166
+ return true;
4167
+ }
4168
+ } // Lists can be nested. Here, we take the list type at the lowest level
4169
+
4170
+
4171
+ var listNode = getBlockAbove(editor, {
4172
+ match: {
4173
+ type: [BLOCKS.OL_LIST, BLOCKS.UL_LIST]
4174
+ },
4175
+ mode: 'lowest'
4176
+ });
4177
+ return (listNode == null ? void 0 : listNode[0].type) === type;
4178
+ };
4179
+
4180
+ /**
4181
+ * Build a new list item node while preserving marks
4182
+ */
4183
+
4184
+ var emptyListItemNode = function emptyListItemNode(editor, withChildren) {
4185
+ if (withChildren === void 0) {
4186
+ withChildren = false;
4187
+ }
4188
+
4189
+ var children = [];
4190
+
4191
+ if (withChildren) {
4192
+ var marks = Editor.marks(editor) || {};
4193
+ children = [{
4194
+ type: BLOCKS.PARAGRAPH,
4195
+ data: {},
4196
+ children: [_extends({
4197
+ text: ''
4198
+ }, marks)]
4199
+ }];
4200
+ }
4201
+
4202
+ return {
4203
+ type: BLOCKS.LIST_ITEM,
4204
+ data: {},
4205
+ children: children
4206
+ };
4207
+ };
4208
+ /**
4209
+ * Insert list item if selection is in li>p.
4210
+ */
4211
+
4212
+
4213
+ var insertListItem = function insertListItem(editor) {
4214
+ if (!editor.selection) {
4215
+ return false;
4216
+ } // Naming it paragraph for simplicity but can be a heading as well
4217
+
4218
+
4219
+ var paragraph = getAbove(editor, {
4220
+ match: {
4221
+ type: TEXT_CONTAINERS
4222
+ }
4223
+ });
4224
+
4225
+ if (!paragraph) {
4226
+ return false;
4227
+ }
4228
+
4229
+ var paragraphPath = paragraph[1];
4230
+ var listItem = getParent(editor, paragraphPath);
4231
+
4232
+ if (!listItem) {
4233
+ return false;
4234
+ }
4235
+
4236
+ var listItemNode = listItem[0],
4237
+ listItemPath = listItem[1];
4238
+
4239
+ if (listItemNode.type !== BLOCKS.LIST_ITEM) {
4240
+ return false;
4241
+ } // We are in a li>p (or heading)
4242
+
4243
+
4244
+ Editor.withoutNormalizing(editor, function () {
4245
+ if (!editor.selection) {
4246
+ return;
4247
+ } // Check the cursor position in the current paragraph
4248
+
4249
+
4250
+ var isAtStart = isSelectionAtBlockStart(editor);
4251
+ var isAtEnd = isSelectionAtBlockEnd(editor);
4252
+ var isAtStartOfListItem = isAtStart && isFirstChild(paragraphPath);
4253
+ var shouldSplit = !isAtStart && !isAtEnd; // Split the current paragraph content if necessary
4254
+
4255
+ if (shouldSplit) {
4256
+ Transforms.splitNodes(editor);
4257
+ } // Insert the new li
4258
+
4259
+
4260
+ var newListItemPath = isAtStartOfListItem ? listItemPath : Path.next(listItemPath);
4261
+ insertNodes(editor, // Add an empty paragraph to the new li if We will not move some
4262
+ // paragraphs over there.
4263
+ emptyListItemNode(editor, !shouldSplit), {
4264
+ at: newListItemPath
4265
+ }); // Move children *after* selection to the new li
4266
+
4267
+ var fromPath = isAtStart ? paragraphPath : Path.next(paragraphPath);
4268
+ var fromStartIndex = fromPath[fromPath.length - 1] || 0; // On split we don't add paragraph to the new li so we move
4269
+ // content to the very beginning. Otherwise, account for the empty
4270
+ // paragraph at the beginning by moving the content after
4271
+
4272
+ var toPath = newListItemPath.concat([shouldSplit ? 0 : 1]);
4273
+
4274
+ if (!isAtStartOfListItem) {
4275
+ moveChildren(editor, {
4276
+ at: listItemPath,
4277
+ to: toPath,
4278
+ fromStartIndex: fromStartIndex
4279
+ });
4280
+ } // Move cursor to the start of the new li
4281
+
4282
+
4283
+ Transforms.select(editor, newListItemPath);
4284
+ Transforms.collapse(editor, {
4285
+ edge: 'start'
4286
+ });
4287
+ }); // Returning True skips processing other editor.insertBreak handlers
4288
+
4289
+ return true;
4290
+ };
4291
+
4292
+ /**
4293
+ * Credit: Copied & modified version from Plate's list plugin to support
4294
+ * list items with multiple children.
4295
+ *
4296
+ * See: https://github.com/udecode/plate/blob/main/packages/nodes/list
4297
+ */
4298
+
4299
+ var listBreak = function listBreak(editor) {
4300
+ if (!editor.selection) return false;
4301
+ var res = getListItemEntry(editor, {});
4302
+ var moved; // If selection is in a li
4303
+
4304
+ if (res) {
4305
+ var list = res.list,
4306
+ listItem = res.listItem;
4307
+ var childNode = listItem[0].children[0]; // If selected li is empty, move it up.
4308
+
4309
+ if (isBlockAboveEmpty(editor) && listItem[0].children.length === 1 && TEXT_CONTAINERS.includes(childNode.type)) {
4310
+ moved = moveListItemUp(editor, {
4311
+ list: list,
4312
+ listItem: listItem
4313
+ });
4314
+ if (moved) return true;
4315
+ }
4316
+ }
4317
+
4318
+ var didReset = onKeyDownResetNode(editor, mockPlugin({
4319
+ options: {
4320
+ rules: [{
4321
+ types: [getPluginType(editor, ELEMENT_LI)],
4322
+ defaultType: getPluginType(editor, ELEMENT_DEFAULT),
4323
+ predicate: function predicate() {
4324
+ return !moved && isBlockAboveEmpty(editor);
4325
+ },
4326
+ onReset: function onReset(_editor) {
4327
+ return unwrapList$1(_editor);
4328
+ }
3958
4329
  }]
3959
4330
  }
3960
4331
  }))(SIMULATE_BACKSPACE);
@@ -4085,50 +4456,16 @@ var insertListFragment = function insertListFragment(editor) {
4085
4456
  select: true
4086
4457
  });
4087
4458
  return Transforms.insertNodes(editor, blocks, {
4088
- at: editor.selection,
4089
- select: true
4090
- });
4091
- }
4092
-
4093
- var filtered = isListRoot(fragment[0]) ? [{
4094
- text: ''
4095
- }].concat(fragment) : fragment;
4096
- return insertFragment(filtered);
4097
- };
4098
- };
4099
-
4100
- /**
4101
- * Credit: Modified version of Plate's list plugin
4102
- * See: https://github.com/udecode/plate/blob/main/packages/nodes/list
4103
- */
4104
- var listTypes = [BLOCKS.UL_LIST, BLOCKS.OL_LIST];
4105
- var unwrapList = function unwrapList(editor, _temp) {
4106
- var _ref = _temp === void 0 ? {} : _temp,
4107
- at = _ref.at;
4108
-
4109
- Editor.withoutNormalizing(editor, function () {
4110
- do {
4111
- unwrapNodes(editor, {
4112
- at: at,
4113
- match: {
4114
- type: BLOCKS.LIST_ITEM
4115
- },
4116
- split: true
4117
- });
4118
- unwrapNodes(editor, {
4119
- at: at,
4120
- match: {
4121
- type: listTypes
4122
- },
4123
- split: true
4124
- });
4125
- } while (getAbove(editor, {
4126
- match: {
4127
- type: listTypes,
4128
- at: at
4129
- }
4130
- }));
4131
- });
4459
+ at: editor.selection,
4460
+ select: true
4461
+ });
4462
+ }
4463
+
4464
+ var filtered = isListRoot(fragment[0]) ? [{
4465
+ text: ''
4466
+ }].concat(fragment) : fragment;
4467
+ return insertFragment(filtered);
4468
+ };
4132
4469
  };
4133
4470
 
4134
4471
  /**
@@ -4240,12 +4577,18 @@ var createListPlugin = function createListPlugin() {
4240
4577
  overrideByKey: (_overrideByKey = {}, _overrideByKey[ELEMENT_UL] = {
4241
4578
  type: BLOCKS.UL_LIST,
4242
4579
  component: ListUL,
4580
+ handlers: {
4581
+ onKeyDown: onKeyDownList
4582
+ },
4243
4583
  // The withList is added on ELEMENT_UL plugin in upstream code
4244
4584
  // so we need to override it here
4245
4585
  withOverrides: withList
4246
4586
  }, _overrideByKey[ELEMENT_OL] = {
4247
4587
  type: BLOCKS.OL_LIST,
4248
- component: ListOL
4588
+ component: ListOL,
4589
+ handlers: {
4590
+ onKeyDown: onKeyDownList
4591
+ }
4249
4592
  }, _overrideByKey[ELEMENT_LIC] = {
4250
4593
  type: BLOCKS.PARAGRAPH
4251
4594
  }, _overrideByKey[ELEMENT_LI] = {
@@ -4269,148 +4612,6 @@ var createListPlugin = function createListPlugin() {
4269
4612
  });
4270
4613
  };
4271
4614
 
4272
- var listTypes$1 = [BLOCKS.UL_LIST, BLOCKS.OL_LIST];
4273
- var toggleList = function toggleList(editor, _ref) {
4274
- var type = _ref.type;
4275
- return Editor.withoutNormalizing(editor, function () {
4276
- if (!editor.selection) {
4277
- return;
4278
- }
4279
-
4280
- if (isCollapsed(editor.selection) || !isRangeAcrossBlocks(editor)) {
4281
- // selection is collapsed
4282
- var res = getListItemEntry(editor);
4283
-
4284
- if (res) {
4285
- var list = res.list;
4286
-
4287
- if (list[0].type !== type) {
4288
- setNodes(editor, {
4289
- type: type
4290
- }, {
4291
- at: editor.selection,
4292
- match: function match(n) {
4293
- return listTypes$1.includes(n.type);
4294
- },
4295
- mode: 'lowest'
4296
- });
4297
- } else {
4298
- unwrapList(editor);
4299
- }
4300
- } else {
4301
- var _list = {
4302
- type: type,
4303
- children: [],
4304
- data: {}
4305
- };
4306
- wrapNodes(editor, _list);
4307
- var nodes = [].concat(getNodes(editor, {
4308
- match: {
4309
- type: getPluginType(editor, ELEMENT_DEFAULT)
4310
- }
4311
- }));
4312
- var listItem = {
4313
- type: BLOCKS.LIST_ITEM,
4314
- children: [],
4315
- data: {}
4316
- };
4317
-
4318
- for (var _iterator = _createForOfIteratorHelperLoose(nodes), _step; !(_step = _iterator()).done;) {
4319
- var _step$value = _step.value,
4320
- path = _step$value[1];
4321
- wrapNodes(editor, listItem, {
4322
- at: path
4323
- });
4324
- }
4325
- }
4326
- } else {
4327
- // selection is a range
4328
- var _Range$edges = Range.edges(editor.selection),
4329
- startPoint = _Range$edges[0],
4330
- endPoint = _Range$edges[1];
4331
-
4332
- var commonEntry = Node.common(editor, startPoint.path, endPoint.path);
4333
-
4334
- if (listTypes$1.includes(commonEntry[0].type) || commonEntry[0].type === BLOCKS.LIST_ITEM) {
4335
- if (commonEntry[0].type !== type) {
4336
- var startList = findNode(editor, {
4337
- at: Range.start(editor.selection),
4338
- match: {
4339
- type: listTypes$1
4340
- },
4341
- mode: 'lowest'
4342
- });
4343
- var endList = findNode(editor, {
4344
- at: Range.end(editor.selection),
4345
- match: {
4346
- type: listTypes$1
4347
- },
4348
- mode: 'lowest'
4349
- });
4350
-
4351
- if (!startList || !endList) {
4352
- return;
4353
- }
4354
-
4355
- var rangeLength = Math.min(startList[1].length, endList[1].length);
4356
- setNodes(editor, {
4357
- type: type
4358
- }, {
4359
- at: editor.selection,
4360
- match: function match(n, path) {
4361
- return listTypes$1.includes(n.type) && path.length >= rangeLength;
4362
- },
4363
- mode: 'all'
4364
- });
4365
- } else {
4366
- unwrapList(editor);
4367
- }
4368
- } else {
4369
- var rootPathLength = commonEntry[1].length;
4370
-
4371
- var _nodes = Array.from(getNodes(editor, {
4372
- mode: 'all'
4373
- })).filter(function (_ref2) {
4374
- var path = _ref2[1];
4375
- return path.length === rootPathLength + 1;
4376
- }).reverse();
4377
-
4378
- _nodes.forEach(function (n) {
4379
- if (listTypes$1.includes(n[0].type)) {
4380
- setNodes(editor, {
4381
- type: type
4382
- }, {
4383
- at: n[1]
4384
- });
4385
- } else {
4386
- setNodes(editor, {
4387
- type: getPluginType(editor, ELEMENT_LIC)
4388
- }, {
4389
- at: n[1]
4390
- });
4391
- var _listItem = {
4392
- type: BLOCKS.LIST_ITEM,
4393
- children: [],
4394
- data: {}
4395
- };
4396
- wrapNodes(editor, _listItem, {
4397
- at: n[1]
4398
- });
4399
- var _list2 = {
4400
- type: type,
4401
- children: [],
4402
- data: {}
4403
- };
4404
- wrapNodes(editor, _list2, {
4405
- at: n[1]
4406
- });
4407
- }
4408
- });
4409
- }
4410
- }
4411
- });
4412
- };
4413
-
4414
4615
  function ToolbarListButton(props) {
4415
4616
  var sdk = useSdkContext();
4416
4617
  var editor = useContentfulEditor();
@@ -6212,6 +6413,80 @@ var disableCorePlugins = {
6212
6413
  eventEditor: true
6213
6414
  };
6214
6415
 
6416
+ /**
6417
+ * For legacy reasons, a document may not have any content at all
6418
+ * e.g:
6419
+ *
6420
+ * {nodeType: document, data: {}, content: []}
6421
+ *
6422
+ * Rendering such document will break the Slate editor
6423
+ */
6424
+
6425
+ var hasContent = function hasContent(doc) {
6426
+ if (!doc) {
6427
+ return false;
6428
+ }
6429
+
6430
+ return doc.content.length > 0;
6431
+ };
6432
+ /*
6433
+ Plate api doesn't allow to modify (easily) the editor value programmatically
6434
+ after the editor instance is created
6435
+
6436
+ This function is inspired to https://github.com/udecode/plate/issues/1269#issuecomment-1057643622
6437
+ */
6438
+
6439
+ var setEditorContent = function setEditorContent(editor, nodes) {
6440
+ // Replaces editor content while keeping change history
6441
+ Editor.withoutNormalizing(editor, function () {
6442
+ var children = [].concat(editor.children);
6443
+ children.forEach(function (node) {
6444
+ return editor.apply({
6445
+ type: 'remove_node',
6446
+ path: [0],
6447
+ node: node
6448
+ });
6449
+ });
6450
+
6451
+ if (nodes) {
6452
+ var nodesArray = Node.isNode(nodes) ? [nodes] : nodes;
6453
+ nodesArray.forEach(function (node, i) {
6454
+ return editor.apply({
6455
+ type: 'insert_node',
6456
+ path: [i],
6457
+ node: node
6458
+ });
6459
+ });
6460
+ }
6461
+
6462
+ var point = Editor.end(editor, []);
6463
+
6464
+ if (point) {
6465
+ Transforms.select(editor, point);
6466
+ }
6467
+ });
6468
+ };
6469
+ /**
6470
+ * Converts a contenful rich text document to the corresponding slate editor
6471
+ * value
6472
+ */
6473
+
6474
+ var documentToEditorValue = function documentToEditorValue(doc) {
6475
+ return toSlatejsDocument({
6476
+ document: hasContent(doc) ? doc : EMPTY_DOCUMENT,
6477
+ // TODO: get rid of schema, https://github.com/contentful/field-editors/pull/1065#discussion_r826723248
6478
+ schema: schema
6479
+ });
6480
+ };
6481
+ var normalizeEditorValue = function normalizeEditorValue(value, options) {
6482
+ var editor = createPlateEditor(options);
6483
+ editor.children = value;
6484
+ Editor.normalize(editor, {
6485
+ force: true
6486
+ });
6487
+ return editor.children;
6488
+ };
6489
+
6215
6490
  var STYLE_EDITOR_BORDER = "1px solid " + tokens.gray400;
6216
6491
  var styles$j = {
6217
6492
  root: /*#__PURE__*/css({
@@ -6308,7 +6583,17 @@ var EmbedEntityWidget = function EmbedEntityWidget(_ref) {
6308
6583
  setCanAccessAssets = _useState2[1];
6309
6584
 
6310
6585
  React__default.useEffect(function () {
6311
- sdk.access.can('read', 'Asset').then(setCanAccessAssets);
6586
+ var subscribed = true;
6587
+ sdk.access.can('read', 'Asset').then(function (can) {
6588
+ if (!subscribed) {
6589
+ return;
6590
+ }
6591
+
6592
+ setCanAccessAssets(can);
6593
+ });
6594
+ return function () {
6595
+ subscribed = false;
6596
+ };
6312
6597
  }, [sdk]);
6313
6598
  var inlineEntryEmbedEnabled = isNodeTypeEnabled(sdk.field, INLINES.EMBEDDED_ENTRY);
6314
6599
  var blockEntryEmbedEnabled = isNodeTypeEnabled(sdk.field, BLOCKS.EMBEDDED_ENTRY) && canInsertBlocks;
@@ -6463,50 +6748,6 @@ var StickyToolbarWrapper = function StickyToolbarWrapper(_ref) {
6463
6748
  }, children);
6464
6749
  };
6465
6750
 
6466
- /**
6467
- * For legacy reasons, a document may not have any content at all
6468
- * e.g:
6469
- *
6470
- * {nodeType: document, data: {}, content: []}
6471
- *
6472
- * Rendering such document will break the Slate editor
6473
- */
6474
-
6475
- var hasContent = function hasContent(doc) {
6476
- if (!doc) {
6477
- return false;
6478
- }
6479
-
6480
- return doc.content.length > 0;
6481
- };
6482
-
6483
- var useNormalizedSlateValue = function useNormalizedSlateValue(_ref) {
6484
- var id = _ref.id,
6485
- incomingDoc = _ref.incomingDoc,
6486
- plugins = _ref.plugins;
6487
- return useMemo(function () {
6488
- var editor = createPlateEditor({
6489
- id: id,
6490
- plugins: plugins,
6491
- disableCorePlugins: disableCorePlugins
6492
- });
6493
- var doc = toSlatejsDocument({
6494
- document: hasContent(incomingDoc) ? incomingDoc : EMPTY_DOCUMENT,
6495
- schema: schema
6496
- }); // Sets editor value & kicks normalization
6497
-
6498
- editor.children = doc;
6499
- Editor.normalize(editor, {
6500
- force: true
6501
- }); // TODO: return the editor itself to avoid recompiling & initializing all
6502
- // of the plugins again. It's currently not possible due to a bug in Plate
6503
- // with initialValues
6504
- // See: https://slate-js.slack.com/archives/C013QHXSCG1/p1645112799942819
6505
-
6506
- return editor.children;
6507
- }, [id, plugins, incomingDoc]);
6508
- };
6509
-
6510
6751
  /**
6511
6752
  * Returns whether a given operation is relevant enough to trigger a save.
6512
6753
  */
@@ -6520,8 +6761,10 @@ var isRelevantOperation = function isRelevantOperation(op) {
6520
6761
  };
6521
6762
 
6522
6763
  var useOnValueChanged = function useOnValueChanged(_ref) {
6523
- var editor = _ref.editor,
6524
- handler = _ref.handler;
6764
+ var editorId = _ref.editorId,
6765
+ handler = _ref.handler,
6766
+ skip = _ref.skip,
6767
+ onSkip = _ref.onSkip;
6525
6768
  var onChange = useMemo(function () {
6526
6769
  return debounce(function (document) {
6527
6770
  handler == null ? void 0 : handler(toContentfulDocument({
@@ -6531,45 +6774,84 @@ var useOnValueChanged = function useOnValueChanged(_ref) {
6531
6774
  }, 500);
6532
6775
  }, [handler]);
6533
6776
  return useCallback(function (value) {
6534
- var operations = editor.operations.filter(isRelevantOperation);
6777
+ var editor = getPlateSelectors(editorId).editor();
6778
+
6779
+ if (!editor) {
6780
+ throw new Error('Editor change callback called but editor not defined. Editor id: ' + editorId);
6781
+ }
6782
+
6783
+ var operations = editor == null ? void 0 : editor.operations.filter(isRelevantOperation);
6535
6784
 
6536
6785
  if (operations.length > 0) {
6786
+ if (skip) {
6787
+ onSkip == null ? void 0 : onSkip();
6788
+ return;
6789
+ }
6790
+
6537
6791
  onChange(value);
6538
6792
  }
6539
- }, [editor, onChange]);
6793
+ }, [editorId, onChange, skip, onSkip]);
6540
6794
  };
6541
6795
 
6542
6796
  var _excluded = ["sdk", "isInitiallyDisabled", "onAction"];
6543
6797
  var ConnectedRichTextEditor = function ConnectedRichTextEditor(props) {
6544
- var id = getContentfulEditorId(props.sdk); // TODO: remove in favor of getting the editor from useNormalizedSlateValue after upgrading to Plate v10
6545
-
6546
- var editor = useContentfulEditor(id);
6798
+ var id = getContentfulEditorId(props.sdk);
6547
6799
  var plugins = React__default.useMemo(function () {
6548
6800
  var _props$onAction;
6549
6801
 
6550
6802
  return getPlugins(props.sdk, (_props$onAction = props.onAction) != null ? _props$onAction : noop);
6551
6803
  }, [props.sdk, props.onAction]);
6552
- var initialValue = useNormalizedSlateValue({
6553
- id: id,
6554
- incomingDoc: props.value,
6555
- plugins: plugins
6556
- });
6804
+
6805
+ var _useState = useState(true),
6806
+ isFirstRender = _useState[0],
6807
+ setIsFirstRender = _useState[1];
6808
+
6809
+ var _useState2 = useState(false),
6810
+ pendingExternalUpdate = _useState2[0],
6811
+ setPendingExternalUpdate = _useState2[1];
6812
+
6557
6813
  var onValueChanged = useOnValueChanged({
6558
- editor: editor,
6559
- handler: props.onChange
6814
+ editorId: id,
6815
+ handler: props.onChange,
6816
+ skip: pendingExternalUpdate || isFirstRender,
6817
+ onSkip: function onSkip() {
6818
+ return setPendingExternalUpdate(false);
6819
+ }
6560
6820
  });
6821
+ useEffect(function () {
6822
+ /*
6823
+ This effect is called when the value prop changes. Normally
6824
+ this happens when the value is changed outside of the editor,
6825
+ like in snapshots restoration or remote updates
6826
+ Plate won't update the displayed value on its own, see:
6827
+ - https://github.com/ianstormtaylor/slate/pull/4540
6828
+ - https://github.com/udecode/plate/issues/1169
6829
+ The content is forcely set to the new value and it's ensured
6830
+ the change listener isn't invoked
6831
+ */
6832
+ setIsFirstRender(false);
6833
+ var editor = getPlateSelectors(id).editor();
6834
+
6835
+ if (!editor) {
6836
+ return;
6837
+ }
6838
+
6839
+ setPendingExternalUpdate(true);
6840
+ setEditorContent(editor, documentToEditorValue(props.value));
6841
+ }, [props.value, id]);
6561
6842
  var classNames = cx(styles$j.editor, props.minHeight !== undefined ? css({
6562
6843
  minHeight: props.minHeight
6563
6844
  }) : undefined, props.isDisabled ? styles$j.disabled : styles$j.enabled, props.isToolbarHidden && styles$j.hiddenToolbar);
6564
6845
  useEffect(function () {
6565
- // Ensure the plate state is cleared after the component unmounts
6566
- // This prevent new editors for the same field to display old outdated values
6567
- // Typical scenario: coming back to the entry editor after restoring a previous entry version
6568
- getPlateActions(id).enabled(true);
6569
- return function () {
6570
- return getPlateActions(id).enabled(false);
6571
- };
6572
- }, [id]);
6846
+ if (!isFirstRender) {
6847
+ return;
6848
+ }
6849
+
6850
+ getPlateActions(id).value(normalizeEditorValue(documentToEditorValue(props.value), {
6851
+ plugins: plugins,
6852
+ disableCorePlugins: disableCorePlugins
6853
+ }));
6854
+ }, [isFirstRender, plugins, id, props.value]);
6573
6855
  return /*#__PURE__*/React__default.createElement(SdkProvider, {
6574
6856
  sdk: props.sdk
6575
6857
  }, /*#__PURE__*/React__default.createElement(ContentfulEditorIdProvider, {
@@ -6579,7 +6861,6 @@ var ConnectedRichTextEditor = function ConnectedRichTextEditor(props) {
6579
6861
  "data-test-id": "rich-text-editor"
6580
6862
  }, /*#__PURE__*/React__default.createElement(Plate, {
6581
6863
  id: id,
6582
- initialValue: initialValue,
6583
6864
  plugins: plugins,
6584
6865
  disableCorePlugins: disableCorePlugins,
6585
6866
  editableProps: {
@@ -6603,6 +6884,7 @@ var RichTextEditor = function RichTextEditor(props) {
6603
6884
  var isEmptyValue = useCallback(function (value) {
6604
6885
  return !value || deepEquals(value, EMPTY_DOCUMENT);
6605
6886
  }, []);
6887
+ var id = getContentfulEditorId(props.sdk);
6606
6888
  return /*#__PURE__*/React__default.createElement(EntityProvider, {
6607
6889
  sdk: sdk
6608
6890
  }, /*#__PURE__*/React__default.createElement(FieldConnector, {
@@ -6614,10 +6896,9 @@ var RichTextEditor = function RichTextEditor(props) {
6614
6896
  }, function (_ref) {
6615
6897
  var lastRemoteValue = _ref.lastRemoteValue,
6616
6898
  disabled = _ref.disabled,
6617
- setValue = _ref.setValue,
6618
- externalReset = _ref.externalReset;
6899
+ setValue = _ref.setValue;
6619
6900
  return /*#__PURE__*/React__default.createElement(ConnectedRichTextEditor, Object.assign({}, otherProps, {
6620
- key: "rich-text-editor-" + externalReset,
6901
+ key: "rich-text-editor-" + id,
6621
6902
  value: lastRemoteValue,
6622
6903
  sdk: sdk,
6623
6904
  onAction: onAction,