@contentful/field-editor-rich-text 2.0.0-next.0 → 2.0.0-next.1

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
- import React__default, { Component, createElement, useMemo, useState, useEffect, Fragment, useCallback } from 'react';
1
+ import React__default, { createElement, useMemo, useState, useEffect, Fragment, useCallback } from 'react';
2
2
  import noop from 'lodash-es/noop';
3
3
  import { toContentfulDocument, toSlatejsDocument } from '@contentful/contentful-slatejs-adapter';
4
- import { TOP_LEVEL_BLOCKS, BLOCKS, CONTAINERS, VOID_BLOCKS, INLINES, LIST_ITEM_BLOCKS, MARKS, EMPTY_DOCUMENT } from '@contentful/rich-text-types';
4
+ import { TOP_LEVEL_BLOCKS, BLOCKS, CONTAINERS, VOID_BLOCKS, INLINES, TABLE_BLOCKS, LIST_ITEM_BLOCKS, MARKS, EMPTY_DOCUMENT } from '@contentful/rich-text-types';
5
5
  import { getScheduleTooltipContent, useEntities, ScheduledIconWithTooltip, MissingEntityCard, AssetThumbnail, EntityProvider } from '@contentful/field-editor-reference';
6
6
  import { css, cx } from 'emotion';
7
7
  import tokens from '@contentful/f36-tokens';
@@ -9,18 +9,19 @@ import deepEquals from 'fast-deep-equal';
9
9
  import { Button, Tooltip, Menu, EntryCard, MenuItem, AssetCard, Text as Text$1, ModalContent, Form, FormControl, TextInput, Select, FormLabel, TextLink, ModalControls, IconButton, Flex, Icon, InlineEntryCard } from '@contentful/f36-components';
10
10
  import { useSelected, useFocused, ReactEditor, useReadOnly } from 'slate-react';
11
11
  import { HorizontalRuleIcon, ChevronDownIcon, QuoteIcon, ListBulletedIcon, ListNumberedIcon, FormatBoldIcon, CodeIcon, FormatItalicIcon, FormatUnderlinedIcon, ClockIcon, LinkIcon, TableIcon, PlusIcon, AssetIcon, EmbeddedEntryBlockIcon, EmbeddedEntryInlineIcon } from '@contentful/f36-icons';
12
- import { Editor, Transforms, Element, Text, Range, Path, Node as Node$1 } from 'slate';
13
- import { getPlatePluginOptions, useStoreEditorRef, getRenderElement, getPlatePluginTypes, getRenderLeaf, getPlatePluginType, Plate, createReactPlugin, createHistoryPlugin } from '@udecode/plate-core';
14
- import { getElementDeserializer, getLeafDeserializer, getText, setNodes, insertNodes, toggleNodeType, getToggleMarkOnKeyDown, isMarkActive, toggleMark, getAbove, getChildren, someNode, getToggleElementOnKeyDown } from '@udecode/plate-common';
12
+ import { Editor, Transforms, Element, Text, Node as Node$1, Path, Range } from 'slate';
13
+ import { getPlatePluginOptions, usePlateEditorRef, getRenderElement, getPlatePluginTypes, getRenderLeaf, getPlatePluginType, Plate, createReactPlugin, createHistoryPlugin } from '@udecode/plate-core';
14
+ import { getText, getElementDeserializer, getLeafDeserializer, setNodes, insertNodes, toggleNodeType, findNode, getToggleMarkOnKeyDown, isMarkActive, toggleMark, getAbove, getChildren, someNode, getToggleElementOnKeyDown, getNodes } from '@udecode/plate-common';
15
15
  import constate from 'constate';
16
16
  import find from 'lodash-es/find';
17
17
  import flow from 'lodash-es/flow';
18
18
  import get from 'lodash-es/get';
19
- import { ELEMENT_LIC, ELEMENT_LI, ELEMENT_UL, ELEMENT_OL, createListPlugin as createListPlugin$1, toggleList } from '@udecode/plate-list';
19
+ import { ELEMENT_LI, ELEMENT_UL, ELEMENT_OL, ELEMENT_LIC, toggleList, createListPlugin as createListPlugin$1, withList } from '@udecode/plate-list';
20
+ import { documentToPlainTextString } from '@contentful/rich-text-plain-text-renderer';
20
21
  import { entityHelpers, isValidImage, shortenStorageUnit, ModalDialogLauncher, FieldConnector } from '@contentful/field-editor-shared';
21
22
  import mimetype from '@contentful/mimetype';
22
23
  import { ELEMENT_TABLE, ELEMENT_TH, ELEMENT_TR, ELEMENT_TD, insertTable, getEmptyRowNode, getEmptyCellNode, deleteRow, deleteColumn, deleteTable, createTablePlugin as createTablePlugin$1, getTableOnKeyDown } from '@udecode/plate-table';
23
- import { documentToPlainTextString } from '@contentful/rich-text-plain-text-renderer';
24
+ import { createDeserializeAstPlugin } from '@udecode/plate-ast-serializer';
24
25
  import { createDeserializeHTMLPlugin } from '@udecode/plate-html-serializer';
25
26
  import { ELEMENT_PARAGRAPH } from '@udecode/plate-paragraph';
26
27
  import { createExitBreakPlugin } from '@udecode/plate-break';
@@ -323,57 +324,40 @@ var styles$1 = {
323
324
  zIndex: /*#__PURE__*/Number(tokens.zIndexTooltip)
324
325
  })
325
326
  };
326
- var ToolbarButton = /*#__PURE__*/function (_Component) {
327
- _inheritsLoose(ToolbarButton, _Component);
328
-
329
- function ToolbarButton() {
330
- var _this;
331
-
332
- _this = _Component.apply(this, arguments) || this;
327
+ function ToolbarButton(props) {
328
+ var title = props.title,
329
+ testId = props.testId,
330
+ isActive = props.isActive,
331
+ children = props.children,
332
+ className = props.className,
333
+ _props$isDisabled = props.isDisabled,
334
+ isDisabled = _props$isDisabled === void 0 ? false : _props$isDisabled;
333
335
 
334
- _this.handleClick = function (event) {
335
- event.preventDefault();
336
+ var handleClick = function handleClick(event) {
337
+ event.preventDefault();
338
+ props.onClick();
339
+ };
336
340
 
337
- _this.props.onClick(event);
338
- };
341
+ var button = /*#__PURE__*/React__default.createElement(Button, {
342
+ className: cx(styles$1.button, className),
343
+ isDisabled: isDisabled,
344
+ startIcon: children,
345
+ onClick: handleClick,
346
+ testId: testId,
347
+ variant: isActive ? 'secondary' : 'transparent',
348
+ size: "small"
349
+ });
339
350
 
340
- return _this;
351
+ if (title) {
352
+ return /*#__PURE__*/React__default.createElement(Tooltip, {
353
+ className: styles$1.tooltip,
354
+ placement: "bottom",
355
+ content: title
356
+ }, button);
341
357
  }
342
358
 
343
- var _proto = ToolbarButton.prototype;
344
-
345
- _proto.render = function render() {
346
- var _this$props = this.props,
347
- title = _this$props.title,
348
- testId = _this$props.testId,
349
- isActive = _this$props.isActive,
350
- children = _this$props.children,
351
- className = _this$props.className,
352
- _this$props$isDisable = _this$props.isDisabled,
353
- isDisabled = _this$props$isDisable === void 0 ? false : _this$props$isDisable;
354
- var button = /*#__PURE__*/React__default.createElement(Button, {
355
- className: cx(styles$1.button, className),
356
- isDisabled: isDisabled,
357
- startIcon: children,
358
- onClick: this.handleClick,
359
- testId: testId,
360
- variant: isActive ? 'secondary' : 'transparent',
361
- size: "small"
362
- });
363
-
364
- if (title) {
365
- return /*#__PURE__*/React__default.createElement(Tooltip, {
366
- className: styles$1.tooltip,
367
- placement: "bottom",
368
- content: title
369
- }, button);
370
- }
371
-
372
- return button;
373
- };
374
-
375
- return ToolbarButton;
376
- }(Component);
359
+ return button;
360
+ }
377
361
 
378
362
  var LINK_TYPES = [INLINES.HYPERLINK, INLINES.ENTRY_HYPERLINK, INLINES.ASSET_HYPERLINK];
379
363
  var LIST_TYPES = [BLOCKS.OL_LIST, BLOCKS.UL_LIST];
@@ -575,6 +559,57 @@ function unwrapFromRoot(editor) {
575
559
  at: ancestorPath
576
560
  });
577
561
  }
562
+ var isAtEndOfTextSelection = function isAtEndOfTextSelection(editor) {
563
+ var _editor$selection, _editor$selection2;
564
+
565
+ 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;
566
+ };
567
+ function currentSelectionStartsTableCell(editor) {
568
+ var _editor$selection3;
569
+
570
+ var _getNodeEntryFromSele2 = getNodeEntryFromSelection(editor, [BLOCKS.TABLE_CELL, BLOCKS.TABLE_HEADER_CELL]),
571
+ tableCellNode = _getNodeEntryFromSele2[0],
572
+ path = _getNodeEntryFromSele2[1];
573
+
574
+ return !!tableCellNode && (!getText(editor, path) || ((_editor$selection3 = editor.selection) == null ? void 0 : _editor$selection3.focus.offset) === 0);
575
+ }
576
+ /**
577
+ * This traversal strategy is unfortunately necessary because Slate doesn't
578
+ * expose something like Node.next(editor).
579
+ */
580
+
581
+ function getNextNode(editor) {
582
+ if (!editor.selection) {
583
+ return null;
584
+ }
585
+
586
+ var descendants = Node$1.descendants(editor, {
587
+ from: editor.selection.focus.path
588
+ }); // eslint-disable-next-line no-constant-condition
589
+
590
+ while (true) {
591
+ var _descendants$next = descendants.next(),
592
+ done = _descendants$next.done,
593
+ value = _descendants$next.value;
594
+
595
+ if (done) {
596
+ return null;
597
+ }
598
+
599
+ var node = value[0],
600
+ path = value[1];
601
+
602
+ if (Path.isCommon(path, editor.selection.focus.path)) {
603
+ continue;
604
+ }
605
+
606
+ return node;
607
+ }
608
+ }
609
+ function currentSelectionPrecedesTableCell(editor) {
610
+ var nextNode = getNextNode(editor);
611
+ return !!nextNode && TABLE_BLOCKS.includes(nextNode.type) && isAtEndOfTextSelection(editor);
612
+ }
578
613
 
579
614
  function deserializeLeaf(type, rules) {
580
615
  return function (editor) {
@@ -609,7 +644,7 @@ function getContentfulEditorId(sdk) {
609
644
  function useContentfulEditorHook(_ref) {
610
645
  var sdk = _ref.sdk;
611
646
  var editorId = getContentfulEditorId(sdk);
612
- var editor = useStoreEditorRef(editorId);
647
+ var editor = usePlateEditorRef(editorId);
613
648
  return editor;
614
649
  }
615
650
 
@@ -651,8 +686,7 @@ function withHrEvents(editor) {
651
686
  function ToolbarHrButton(props) {
652
687
  var editor = useContentfulEditor();
653
688
 
654
- function handleOnClick(event) {
655
- event.preventDefault();
689
+ function handleOnClick() {
656
690
  if (!(editor != null && editor.selection)) return;
657
691
 
658
692
  if (shouldUnwrapBlockquote(editor, BLOCKS.HR)) {
@@ -1068,8 +1102,7 @@ function withQuoteEvents(editor) {
1068
1102
  function ToolbarQuoteButton(props) {
1069
1103
  var editor = useContentfulEditor();
1070
1104
 
1071
- function handleOnClick(event) {
1072
- event.preventDefault();
1105
+ function handleOnClick() {
1073
1106
  if (!editor) return;
1074
1107
  createBlockQuote(editor);
1075
1108
  ReactEditor.focus(editor);
@@ -1104,14 +1137,97 @@ var withQuoteOptions = (_withQuoteOptions = {}, _withQuoteOptions[BLOCKS.QUOTE]
1104
1137
  component: Quote
1105
1138
  }, _withQuoteOptions);
1106
1139
 
1140
+ /**
1141
+ * A copy of Plate's list plugin with a few adjustments
1142
+ * to fix pasting text inside lists.
1143
+ */
1144
+
1145
+ var slateNodesToText = function slateNodesToText(nodes) {
1146
+ var contentfulNode = toContentfulDocument({
1147
+ document: nodes,
1148
+ schema: schema
1149
+ });
1150
+ return documentToPlainTextString(contentfulNode);
1151
+ };
1152
+
1153
+ var getListInsertFragment = function getListInsertFragment(editor) {
1154
+ var insertFragment = editor.insertFragment;
1155
+ var li = getPlatePluginOptions(editor, ELEMENT_LI);
1156
+ var ul = getPlatePluginOptions(editor, ELEMENT_UL);
1157
+ var ol = getPlatePluginOptions(editor, ELEMENT_OL);
1158
+
1159
+ var isListRoot = function isListRoot(node) {
1160
+ return [ul.type, ol.type].includes(node.type);
1161
+ };
1162
+
1163
+ var getFirstAncestorOfType = function getFirstAncestorOfType(root, entry, _ref) {
1164
+ var type = _ref.type;
1165
+ var ancestor = Path.parent(entry[1]);
1166
+
1167
+ while (Node$1.get(root, ancestor).type !== type) {
1168
+ ancestor = Path.parent(ancestor);
1169
+ }
1170
+
1171
+ return [Node$1.get(root, ancestor), ancestor];
1172
+ };
1173
+ /**
1174
+ * Removes the "empty" leading lis. Empty in this context means lis only with other lis as children.
1175
+ *
1176
+ * @returns If argument is not a list root, returns it, otherwise returns ul[] or li[].
1177
+ */
1178
+
1179
+
1180
+ var trimList = function trimList(listRoot) {
1181
+ if (!isListRoot(listRoot)) {
1182
+ return [listRoot];
1183
+ }
1184
+
1185
+ var textEntries = Array.from(Node$1.texts(listRoot));
1186
+ var commonAncestorEntry = textEntries.reduce(function (commonAncestor, textEntry) {
1187
+ return Path.isAncestor(commonAncestor[1], textEntry[1]) ? commonAncestor : Node$1.common(listRoot, textEntry[1], commonAncestor[1]);
1188
+ }, // any list item would do, we grab the first one
1189
+ getFirstAncestorOfType(listRoot, textEntries[0], li));
1190
+ return isListRoot(commonAncestorEntry[0]) ? commonAncestorEntry[0].children : [commonAncestorEntry[0]];
1191
+ };
1192
+
1193
+ return function (fragment) {
1194
+ var liEntry = findNode(editor, {
1195
+ match: {
1196
+ type: li.type
1197
+ },
1198
+ mode: 'lowest'
1199
+ });
1200
+
1201
+ if (liEntry) {
1202
+ var liPath = liEntry[1]; // FIXME: this is a temporarily workaround and needs a follow-up to properly
1203
+ // non-text elements
1204
+
1205
+ var nodes = fragment.flatMap(function (node) {
1206
+ return trimList(node);
1207
+ });
1208
+ var text = slateNodesToText(nodes);
1209
+ return Transforms.insertNodes(editor, [{
1210
+ text: text
1211
+ }], {
1212
+ at: editor.selection || Path.next(liPath),
1213
+ select: true
1214
+ });
1215
+ }
1216
+
1217
+ var filtered = isListRoot(fragment[0]) ? [{
1218
+ text: ''
1219
+ }].concat(fragment) : fragment;
1220
+ return insertFragment(filtered);
1221
+ };
1222
+ };
1223
+
1107
1224
  var _templateObject$2, _templateObject2$2, _templateObject3$2, _styles, _withListOptions;
1108
1225
  function ToolbarListButton(props) {
1109
1226
  var sdk = useSdkContext();
1110
1227
  var editor = useContentfulEditor();
1111
1228
 
1112
1229
  function handleClick(type) {
1113
- return function (event) {
1114
- event.preventDefault();
1230
+ return function () {
1115
1231
  if (!(editor != null && editor.selection)) return;
1116
1232
 
1117
1233
  if (shouldUnwrapBlockquote(editor, type)) {
@@ -1164,18 +1280,34 @@ var withListOptions = (_withListOptions = {}, _withListOptions[ELEMENT_LIC] = {
1164
1280
  type: BLOCKS.OL_LIST,
1165
1281
  component: OL
1166
1282
  }, _withListOptions);
1283
+
1284
+ var withCustomList = function withCustomList(options) {
1285
+ var withDefaultOverrides = withList(options);
1286
+ return function (editor) {
1287
+ var insertFragment = editor.insertFragment;
1288
+ withDefaultOverrides(editor); // Reverts any overrides to insertFragment
1289
+
1290
+ editor.insertFragment = insertFragment; // Use our custom getListInsertFragment
1291
+
1292
+ editor.insertFragment = getListInsertFragment(editor);
1293
+ return editor;
1294
+ };
1295
+ };
1296
+
1167
1297
  var createListPlugin = function createListPlugin() {
1168
- return createListPlugin$1({
1298
+ var options = {
1169
1299
  validLiChildrenTypes: LIST_ITEM_BLOCKS
1170
- });
1300
+ };
1301
+ var plugin = createListPlugin$1(options);
1302
+ plugin.withOverrides = withCustomList(options);
1303
+ return plugin;
1171
1304
  };
1172
1305
 
1173
1306
  var _withBoldOptions;
1174
1307
  function ToolbarBoldButton(props) {
1175
1308
  var editor = useContentfulEditor();
1176
1309
 
1177
- function handleClick(event) {
1178
- event.preventDefault();
1310
+ function handleClick() {
1179
1311
  if (!(editor != null && editor.selection)) return;
1180
1312
  toggleMark(editor, MARKS.BOLD);
1181
1313
  ReactEditor.focus(editor);
@@ -1233,8 +1365,7 @@ var _withCodeOptions;
1233
1365
  function ToolbarCodeButton(props) {
1234
1366
  var editor = useContentfulEditor();
1235
1367
 
1236
- function handleClick(event) {
1237
- event.preventDefault();
1368
+ function handleClick() {
1238
1369
  if (!(editor != null && editor.selection)) return;
1239
1370
  toggleMark(editor, MARKS.CODE);
1240
1371
  ReactEditor.focus(editor);
@@ -1285,8 +1416,7 @@ var _withItalicOptions;
1285
1416
  function ToolbarItalicButton(props) {
1286
1417
  var editor = useContentfulEditor();
1287
1418
 
1288
- function handleClick(event) {
1289
- event.preventDefault();
1419
+ function handleClick() {
1290
1420
  if (!(editor != null && editor.selection)) return;
1291
1421
  toggleMark(editor, MARKS.ITALIC);
1292
1422
  ReactEditor.focus(editor);
@@ -1336,8 +1466,7 @@ var _withUnderlineOptions;
1336
1466
  function ToolbarUnderlineButton(props) {
1337
1467
  var editor = useContentfulEditor();
1338
1468
 
1339
- function handleClick(event) {
1340
- event.preventDefault();
1469
+ function handleClick() {
1341
1470
  if (!(editor != null && editor.selection)) return;
1342
1471
  toggleMark(editor, MARKS.UNDERLINE);
1343
1472
  ReactEditor.focus(editor);
@@ -3173,33 +3302,31 @@ function ToolbarHyperlinkButton(props) {
3173
3302
  var isActive = !!(editor && isLinkActive(editor));
3174
3303
  var sdk = useSdkContext();
3175
3304
 
3176
- function handleClick(_x3) {
3305
+ function handleClick() {
3177
3306
  return _handleClick3.apply(this, arguments);
3178
3307
  }
3179
3308
 
3180
3309
  function _handleClick3() {
3181
- _handleClick3 = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee3(event) {
3310
+ _handleClick3 = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee3() {
3182
3311
  return runtime_1.wrap(function _callee3$(_context3) {
3183
3312
  while (1) {
3184
3313
  switch (_context3.prev = _context3.next) {
3185
3314
  case 0:
3186
- event.preventDefault();
3187
-
3188
3315
  if (editor) {
3189
- _context3.next = 3;
3316
+ _context3.next = 2;
3190
3317
  break;
3191
3318
  }
3192
3319
 
3193
3320
  return _context3.abrupt("return");
3194
3321
 
3195
- case 3:
3322
+ case 2:
3196
3323
  if (isActive) {
3197
3324
  unwrapLink(editor);
3198
3325
  } else {
3199
3326
  addOrEditLink(editor, sdk);
3200
3327
  }
3201
3328
 
3202
- case 4:
3329
+ case 3:
3203
3330
  case "end":
3204
3331
  return _context3.stop();
3205
3332
  }
@@ -3696,7 +3823,19 @@ function createWithTableEvents(tracking) {
3696
3823
  return function withTableEvents(editor) {
3697
3824
  addTableTrackingEvents(editor, tracking);
3698
3825
  addTableNormalization(editor);
3699
- return getTableOnKeyDown()(editor);
3826
+ var handleKeyDownFromPlateUdecode = getTableOnKeyDown()(editor);
3827
+ return function handleKeyDown(event) {
3828
+ if (event.key === 'Backspace' && currentSelectionStartsTableCell(editor) || event.key === 'Delete' && currentSelectionPrecedesTableCell(editor)) {
3829
+ // The default behavior here would be to delete the preceding or forthcoming
3830
+ // leaf node, in this case a cell or header cell. But we don't want to do that,
3831
+ // because it would leave us with a non-standard number of table cells.
3832
+ event.preventDefault();
3833
+ event.stopPropagation();
3834
+ return;
3835
+ }
3836
+
3837
+ handleKeyDownFromPlateUdecode(event);
3838
+ };
3700
3839
  };
3701
3840
  }
3702
3841
 
@@ -3740,31 +3879,29 @@ function ToolbarTableButton(props) {
3740
3879
 
3741
3880
  var isActive = editor && isTableActive(editor);
3742
3881
 
3743
- function handleClick(_x) {
3882
+ function handleClick() {
3744
3883
  return _handleClick.apply(this, arguments);
3745
3884
  }
3746
3885
 
3747
3886
  function _handleClick() {
3748
- _handleClick = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee(event) {
3887
+ _handleClick = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee() {
3749
3888
  return runtime_1.wrap(function _callee$(_context) {
3750
3889
  while (1) {
3751
3890
  switch (_context.prev = _context.next) {
3752
3891
  case 0:
3753
- event.preventDefault();
3754
-
3755
3892
  if (editor) {
3756
- _context.next = 3;
3893
+ _context.next = 2;
3757
3894
  break;
3758
3895
  }
3759
3896
 
3760
3897
  return _context.abrupt("return");
3761
3898
 
3762
- case 3:
3899
+ case 2:
3763
3900
  onViewportAction('insertTable');
3764
3901
  insertTableAndFocusFirstCell(editor);
3765
3902
  ReactEditor.focus(editor);
3766
3903
 
3767
- case 6:
3904
+ case 5:
3768
3905
  case "end":
3769
3906
  return _context.stop();
3770
3907
  }
@@ -3808,6 +3945,16 @@ function EmbeddedEntityDropdownButton(_ref) {
3808
3945
  }, children));
3809
3946
  }
3810
3947
 
3948
+ // "modern" Edge was released at 79.x
3949
+ var IS_EDGE_LEGACY = typeof navigator !== 'undefined' && /*#__PURE__*/ /Edge?\/(?:[0-6][0-9]|[0-7][0-8])/i.test(navigator.userAgent); // Native `beforeInput` events don't work well with react on Chrome 75
3950
+ // and older, Chrome 76+ can use `beforeInput` though.
3951
+
3952
+ var IS_CHROME_LEGACY = typeof navigator !== 'undefined' && /*#__PURE__*/ /Chrome?\/(?:[0-7][0-5]|[0-6][0-9])/i.test(navigator.userAgent); // COMPAT: Firefox/Edge Legacy don't support the `beforeinput` event
3953
+ // Chrome Legacy doesn't support `beforeinput` correctly
3954
+
3955
+ var HAS_BEFORE_INPUT_SUPPORT = !IS_CHROME_LEGACY && !IS_EDGE_LEGACY && // globalThis is undefined in older browsers
3956
+ typeof globalThis !== 'undefined' && globalThis.InputEvent && typeof globalThis.InputEvent.prototype.getTargetRanges === 'function'; // The `getTargetRanges` property isn't recognized.
3957
+
3811
3958
  var styles$g = {
3812
3959
  root: /*#__PURE__*/css({
3813
3960
  marginBottom: '1.25rem'
@@ -3843,9 +3990,14 @@ function LinkedEntityBlock(props) {
3843
3990
  return /*#__PURE__*/React__default.createElement("div", Object.assign({}, attributes, {
3844
3991
  className: styles$g.root,
3845
3992
  "data-entity-type": entityType,
3846
- "data-entity-id": entityId
3993
+ "data-entity-id": entityId,
3994
+ // COMPAT: This makes copy & paste work for Firefox
3995
+ contentEditable: !HAS_BEFORE_INPUT_SUPPORT ? false : undefined,
3996
+ draggable: !HAS_BEFORE_INPUT_SUPPORT ? true : undefined
3847
3997
  }), /*#__PURE__*/React__default.createElement("div", {
3848
- contentEditable: false
3998
+ // COMPAT: This makes copy & paste work for Chromium/Blink browsers and Safari
3999
+ contentEditable: HAS_BEFORE_INPUT_SUPPORT ? false : undefined,
4000
+ draggable: HAS_BEFORE_INPUT_SUPPORT ? true : undefined
3849
4001
  }, entityType === 'Entry' && /*#__PURE__*/React__default.createElement(FetchingWrappedEntryCard, {
3850
4002
  sdk: sdk,
3851
4003
  entryId: entityId,
@@ -4252,7 +4404,7 @@ function FetchingWrappedInlineEntryCard(props) {
4252
4404
  key: "edit",
4253
4405
  onClick: props.onEdit
4254
4406
  }, "Edit"), /*#__PURE__*/React__default.createElement(MenuItem, {
4255
- key: "edit",
4407
+ key: "remove",
4256
4408
  onClick: props.onRemove,
4257
4409
  disabled: props.isDisabled,
4258
4410
  testId: "card-action-remove"
@@ -4318,9 +4470,14 @@ function EmbeddedEntityInline(props) {
4318
4470
 
4319
4471
  return /*#__PURE__*/createElement("span", Object.assign({}, props.attributes, {
4320
4472
  className: styles$j.root,
4321
- "data-embedded-entity-inline-id": entryId
4473
+ "data-embedded-entity-inline-id": entryId,
4474
+ // COMPAT: This makes copy & paste work for Firefox
4475
+ contentEditable: !HAS_BEFORE_INPUT_SUPPORT ? false : undefined,
4476
+ draggable: !HAS_BEFORE_INPUT_SUPPORT ? true : undefined
4322
4477
  }), /*#__PURE__*/createElement("span", {
4323
- contentEditable: false
4478
+ // COMPAT: This makes copy & paste work for Chromium/Blink browsers and Safari
4479
+ contentEditable: HAS_BEFORE_INPUT_SUPPORT ? false : undefined,
4480
+ draggable: HAS_BEFORE_INPUT_SUPPORT ? true : undefined
4324
4481
  }, /*#__PURE__*/createElement(FetchingWrappedInlineEntryCard, {
4325
4482
  sdk: sdk,
4326
4483
  entryId: entryId,
@@ -4442,6 +4599,7 @@ function createEmbeddedEntityInlinePlugin(sdk) {
4442
4599
  renderElement: getRenderElement(INLINES.EMBEDDED_ENTRY),
4443
4600
  pluginKeys: INLINES.EMBEDDED_ENTRY,
4444
4601
  inlineTypes: getPlatePluginTypes(INLINES.EMBEDDED_ENTRY),
4602
+ voidTypes: getPlatePluginTypes(INLINES.EMBEDDED_ENTRY),
4445
4603
  onKeyDown: getWithEmbeddedEntryInlineEvents(sdk),
4446
4604
  deserialize: function deserialize(editor) {
4447
4605
  var options = getPlatePluginOptions(editor, INLINES.EMBEDDED_ENTRY);
@@ -4494,6 +4652,7 @@ var EmbedEntityWidget = function EmbedEntityWidget(_ref) {
4494
4652
  var isDisabled = _ref.isDisabled,
4495
4653
  canInsertBlocks = _ref.canInsertBlocks;
4496
4654
  var sdk = useSdkContext();
4655
+ var editor = useContentfulEditor();
4497
4656
 
4498
4657
  var _useState = useState(false),
4499
4658
  isEmbedDropdownOpen = _useState[0],
@@ -4532,7 +4691,7 @@ var EmbedEntityWidget = function EmbedEntityWidget(_ref) {
4532
4691
  onClose: onCloseEntityDropdown,
4533
4692
  isButton: !shouldDisplayDropdown
4534
4693
  }), inlineEntryEmbedEnabled && /*#__PURE__*/React__default.createElement(ToolbarEmbeddedEntityInlineButton, {
4535
- isDisabled: !!isDisabled,
4694
+ isDisabled: !!isDisabled || isLinkActive(editor),
4536
4695
  onClose: onCloseEntityDropdown,
4537
4696
  isButton: !shouldDisplayDropdown
4538
4697
  }), blockAssetEmbedEnabled && /*#__PURE__*/React__default.createElement(EmbeddedEntityBlockToolbarIcon, {
@@ -4839,6 +4998,8 @@ var createPastePlugin = function createPastePlugin() {
4839
4998
  };
4840
4999
  };
4841
5000
 
5001
+ var _excluded = ["element"];
5002
+
4842
5003
  var _templateObject$6, _styles$2, _withParagraphOptions;
4843
5004
  var styles$m = (_styles$2 = {}, _styles$2[BLOCKS.PARAGRAPH] = /*#__PURE__*/css(_templateObject$6 || (_templateObject$6 = /*#__PURE__*/_taggedTemplateLiteralLoose(["\n line-height: ", ";\n margin-bottom: 1.5em;\n "])), tokens.lineHeightDefault), _styles$2);
4844
5005
  function Paragraph(props) {
@@ -4846,15 +5007,71 @@ function Paragraph(props) {
4846
5007
  className: styles$m[BLOCKS.PARAGRAPH]
4847
5008
  }), props.children);
4848
5009
  }
5010
+
5011
+ function isEmbed(element) {
5012
+ return element.hasAttribute('data-embedded-entity-inline-id') || element.hasAttribute('data-entity-type');
5013
+ }
5014
+
5015
+ function isEmpty(element) {
5016
+ return element.textContent === '';
5017
+ }
5018
+
4849
5019
  function createParagraphPlugin() {
4850
5020
  var elementKeys = [ELEMENT_PARAGRAPH, BLOCKS.PARAGRAPH];
5021
+ var deserializer = deserializeElement(BLOCKS.PARAGRAPH, [{
5022
+ nodeNames: ['P', 'DIV']
5023
+ }]);
4851
5024
  return {
4852
5025
  renderElement: getRenderElement(elementKeys),
4853
5026
  pluginKeys: elementKeys,
4854
5027
  onKeyDown: getToggleElementOnKeyDown(BLOCKS.PARAGRAPH),
4855
- deserialize: deserializeElement(BLOCKS.PARAGRAPH, [{
4856
- nodeNames: ['P']
4857
- }])
5028
+ deserialize: function deserialize(editor) {
5029
+ var _deserializer = deserializer(editor),
5030
+ element = _deserializer.element,
5031
+ rest = _objectWithoutPropertiesLoose(_deserializer, _excluded);
5032
+
5033
+ return _extends({}, rest, {
5034
+ element: element == null ? void 0 : element.map(function (deserializeNode) {
5035
+ return _extends({}, deserializeNode, {
5036
+ deserialize: function deserialize(el) {
5037
+ if (isEmpty(el) || isEmbed(el)) {
5038
+ return;
5039
+ }
5040
+
5041
+ return deserializeNode.deserialize(el);
5042
+ }
5043
+ });
5044
+ })
5045
+ });
5046
+ },
5047
+ withOverrides: function withOverrides(editor) {
5048
+ var normalizeNode = editor.normalizeNode;
5049
+
5050
+ editor.normalizeNode = function (entry) {
5051
+ var node = entry[0],
5052
+ path = entry[1]; // If the element is a paragraph, ensure its children are valid.
5053
+
5054
+ if (Element.isElement(node) && node.type === BLOCKS.PARAGRAPH) {
5055
+ for (var _iterator = _createForOfIteratorHelperLoose(Node$1.children(editor, path)), _step; !(_step = _iterator()).done;) {
5056
+ var _step$value = _step.value,
5057
+ child = _step$value[0],
5058
+ childPath = _step$value[1];
5059
+
5060
+ if (Element.isElement(child) && !editor.isInline(child)) {
5061
+ Transforms.unwrapNodes(editor, {
5062
+ at: childPath
5063
+ });
5064
+ return;
5065
+ }
5066
+ }
5067
+ } // Fall back to the original `normalizeNode` to enforce other constraints.
5068
+
5069
+
5070
+ normalizeNode(entry);
5071
+ };
5072
+
5073
+ return editor;
5074
+ }
4858
5075
  };
4859
5076
  }
4860
5077
  var withParagraphOptions = (_withParagraphOptions = {}, _withParagraphOptions[ELEMENT_PARAGRAPH] = {
@@ -4898,6 +5115,15 @@ function createInsertBeforeFirstVoidBlockPlugin() {
4898
5115
  return isFirstChild(path) && !!node.isVoid;
4899
5116
  }
4900
5117
  }
5118
+ }, {
5119
+ hotkey: 'enter',
5120
+ query: {
5121
+ filter: function filter(_ref2) {
5122
+ var node = _ref2[0],
5123
+ path = _ref2[1];
5124
+ return !isFirstChild(path) && !!node.isVoid;
5125
+ }
5126
+ }
4901
5127
  }]
4902
5128
  };
4903
5129
  return createExitBreakPlugin(optionsExitBreakPlugin);
@@ -5003,19 +5229,108 @@ var createTrailingParagraphPlugin = function createTrailingParagraphPlugin() {
5003
5229
  });
5004
5230
  };
5005
5231
 
5006
- var _excluded = ["sdk", "isInitiallyDisabled", "onAction"];
5232
+ function createDragAndDropPlugin() {
5233
+ var _DND_BLOCKED_ELEMENTS;
5234
+
5235
+ // Elements that don't allow other elements to be dragged into them and which callback should be used
5236
+ var DND_BLOCKED_ELEMENTS = (_DND_BLOCKED_ELEMENTS = {}, _DND_BLOCKED_ELEMENTS[BLOCKS.TABLE] = Transforms.removeNodes, _DND_BLOCKED_ELEMENTS[BLOCKS.QUOTE] = Transforms.liftNodes, _DND_BLOCKED_ELEMENTS);
5237
+ var DRAGGABLE_TYPES = [BLOCKS.EMBEDDED_ENTRY, BLOCKS.EMBEDDED_ASSET, INLINES.EMBEDDED_ENTRY];
5238
+ /**
5239
+ * HTML node names where dropping should be allowed
5240
+ * Usually for elements where `Transforms.removeNodes` is needed
5241
+ * TODO: looking up for html nodes is not the best solution and it won't scale but it works fine for our current cases/elements
5242
+ */
5243
+
5244
+ var ON_DROP_ALLOWED_TYPES = {
5245
+ TABLE: [INLINES.EMBEDDED_ENTRY]
5246
+ };
5247
+ return {
5248
+ withOverrides: function withOverrides(editor) {
5249
+ var normalizeNode = editor.normalizeNode;
5250
+
5251
+ editor.normalizeNode = function (entry) {
5252
+ var node = entry[0],
5253
+ path = entry[1];
5254
+ Object.keys(DND_BLOCKED_ELEMENTS).forEach(function (blockedElementType) {
5255
+ var nodeType = node.type;
5256
+
5257
+ if (Node$1.isNode(node) && nodeType === blockedElementType) {
5258
+ for (var _iterator = _createForOfIteratorHelperLoose(Node$1.children(editor, path)), _step; !(_step = _iterator()).done;) {
5259
+ var _step$value = _step.value,
5260
+ child = _step$value[0],
5261
+ childPath = _step$value[1];
5262
+ var childType = child.type;
5263
+ if (!CONTAINERS[blockedElementType]) return;
5264
+
5265
+ if (!CONTAINERS[blockedElementType].includes(childType)) {
5266
+ var callback = DND_BLOCKED_ELEMENTS[blockedElementType];
5267
+ callback(editor, {
5268
+ at: childPath,
5269
+ match: function match(matchNode) {
5270
+ return Node$1.isNode(matchNode) && DRAGGABLE_TYPES.includes(matchNode.type);
5271
+ }
5272
+ });
5273
+ return;
5274
+ }
5275
+ }
5276
+ }
5277
+ });
5278
+ normalizeNode(entry);
5279
+ };
5280
+
5281
+ return editor;
5282
+ },
5283
+ // If true, the next handlers will be skipped.
5284
+ onDrop: function onDrop(editor) {
5285
+ return function (event) {
5286
+ var _Array$from = Array.from(getNodes(editor, {
5287
+ match: function match(node) {
5288
+ return Editor.isBlock(editor, node) && DRAGGABLE_TYPES.includes(node.type);
5289
+ }
5290
+ })),
5291
+ draggingBlock = _Array$from[0];
5292
+
5293
+ if (!draggingBlock) return false;
5294
+ var draggingNode = draggingBlock[0];
5295
+ if (!event.nativeEvent.target) return false; // TODO: looking up for html nodes is not the best solution and it won't scale, we need to find a way to know the dropping target slate element
5296
+
5297
+ return getParents(event.nativeEvent.target).some(function (node) {
5298
+ var _ON_DROP_ALLOWED_TYPE;
5299
+
5300
+ return ON_DROP_ALLOWED_TYPES[node.nodeName] ? !((_ON_DROP_ALLOWED_TYPE = ON_DROP_ALLOWED_TYPES[node.nodeName]) != null && _ON_DROP_ALLOWED_TYPE.includes(draggingNode.type)) : false;
5301
+ });
5302
+ };
5303
+ }
5304
+ };
5305
+ }
5306
+
5307
+ function getParents(el) {
5308
+ var parents = [];
5309
+ parents.push(el);
5310
+
5311
+ while (el.parentNode) {
5312
+ parents.unshift(el.parentNode);
5313
+ el = el.parentNode;
5314
+ }
5315
+
5316
+ return parents;
5317
+ }
5318
+
5319
+ var _excluded$1 = ["sdk", "isInitiallyDisabled", "onAction"];
5007
5320
 
5008
5321
  var getPlugins = function getPlugins(sdk, tracking) {
5009
5322
  var plugins = [// Core
5010
5323
  createReactPlugin(), createHistoryPlugin(), // Behavior
5011
5324
  createPastePlugin(), // Global shortcuts
5012
- createNewLinePlugin(), createInsertBeforeFirstVoidBlockPlugin(), // Block Elements
5325
+ createNewLinePlugin(), createInsertBeforeFirstVoidBlockPlugin(), createDragAndDropPlugin(), // Block Elements
5013
5326
  createParagraphPlugin(), createListPlugin(), createHrPlugin(), createHeadingPlugin(), createQuotePlugin(), createTablePlugin(tracking), createEmbeddedEntryBlockPlugin(sdk), createEmbeddedAssetBlockPlugin(sdk), // Inline elements
5014
5327
  createHyperlinkPlugin(sdk), createEmbeddedEntityInlinePlugin(sdk), // Marks
5015
5328
  createBoldPlugin(), createCodePlugin(), createItalicPlugin(), createUnderlinePlugin(), // Other
5016
5329
  createTrailingParagraphPlugin()];
5017
5330
  return plugins.concat([createDeserializeHTMLPlugin({
5018
5331
  plugins: plugins
5332
+ }), createDeserializeAstPlugin({
5333
+ plugins: plugins
5019
5334
  })]);
5020
5335
  };
5021
5336
 
@@ -5072,7 +5387,7 @@ var RichTextEditor = function RichTextEditor(props) {
5072
5387
  var sdk = props.sdk,
5073
5388
  isInitiallyDisabled = props.isInitiallyDisabled,
5074
5389
  onAction = props.onAction,
5075
- otherProps = _objectWithoutPropertiesLoose(props, _excluded);
5390
+ otherProps = _objectWithoutPropertiesLoose(props, _excluded$1);
5076
5391
 
5077
5392
  var isEmptyValue = useCallback(function (value) {
5078
5393
  return !value || deepEquals(value, EMPTY_DOCUMENT);