@contentful/field-editor-rich-text 2.0.0-next.4 → 2.0.0-next.8

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.
@@ -14,11 +14,11 @@ var plateCore = require('@udecode/plate-core');
14
14
  var emotion = require('emotion');
15
15
  var deepEquals = _interopDefault(require('fast-deep-equal'));
16
16
  var noop = _interopDefault(require('lodash/noop'));
17
+ var slate = require('slate');
17
18
  var constate = _interopDefault(require('constate'));
18
19
  var plateSerializerDocx = require('@udecode/plate-serializer-docx');
19
20
  var plateBreak = require('@udecode/plate-break');
20
21
  var isHotkey = _interopDefault(require('is-hotkey'));
21
- var slate = require('slate');
22
22
  var Slate = require('slate-react');
23
23
  var f36Components = require('@contentful/f36-components');
24
24
  var mimetype = _interopDefault(require('@contentful/mimetype'));
@@ -28,6 +28,7 @@ var tokens = _interopDefault(require('@contentful/f36-tokens'));
28
28
  var find = _interopDefault(require('lodash/find'));
29
29
  var flow = _interopDefault(require('lodash/flow'));
30
30
  var plateList = require('@udecode/plate-list');
31
+ var plateResetNode = require('@udecode/plate-reset-node');
31
32
  var plateBasicMarks = require('@udecode/plate-basic-marks');
32
33
  var isPlainObject = _interopDefault(require('is-plain-obj'));
33
34
  var plateParagraph = require('@udecode/plate-paragraph');
@@ -348,8 +349,8 @@ var schema = {
348
349
  function getContentfulEditorId(sdk) {
349
350
  var entry = sdk.entry,
350
351
  field = sdk.field;
351
- var entryId = entry.getSys().id;
352
- return "rich-text-editor-" + entryId + "-" + field.id + "-" + field.locale;
352
+ var sys = entry.getSys();
353
+ return "rich-text-editor-" + sys.id + "-" + field.id + "-" + field.locale;
353
354
  }
354
355
 
355
356
  function useContentfulEditorHook(_ref) {
@@ -490,6 +491,18 @@ function getParents(el) {
490
491
  return parents;
491
492
  }
492
493
 
494
+ // "modern" Edge was released at 79.x
495
+ 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
496
+ // and older, Chrome 76+ can use `beforeInput` though.
497
+
498
+ 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
499
+ // Chrome Legacy doesn't support `beforeinput` correctly
500
+
501
+ var HAS_BEFORE_INPUT_SUPPORT = !IS_CHROME_LEGACY && !IS_EDGE_LEGACY && // globalThis is undefined in older browsers
502
+ typeof globalThis !== 'undefined' && globalThis.InputEvent && typeof globalThis.InputEvent.prototype.getTargetRanges === 'function'; // The `getTargetRanges` property isn't recognized.
503
+
504
+ var IS_SAFARI = typeof navigator !== 'undefined' && /*#__PURE__*/ /Version\/[\d.]+.*Safari/.test(navigator.userAgent);
505
+
493
506
  var LINK_TYPES = [Contentful.INLINES.HYPERLINK, Contentful.INLINES.ENTRY_HYPERLINK, Contentful.INLINES.ASSET_HYPERLINK];
494
507
  function isBlockSelected(editor, type) {
495
508
  var _Array$from = Array.from(slate.Editor.nodes(editor, {
@@ -707,16 +720,27 @@ var isInlineOrText = function isInlineOrText(node) {
707
720
  // either text or inline elements
708
721
  return slate.Text.isText(node) || slate.Element.isElement(node) && INLINE_TYPES.includes(node.type);
709
722
  };
723
+ var focus = function focus(editor) {
724
+ var x = window.scrollX;
725
+ var y = window.scrollY;
726
+ Slate.ReactEditor.focus(editor); // Safari has issues with `editor.focus({ preventScroll: true })`, it ignores the option `preventScroll`
727
+
728
+ if (IS_SAFARI) {
729
+ setTimeout(function () {
730
+ window.scrollTo(x, y); // restore position
731
+ }, 0);
732
+ }
733
+ };
710
734
 
711
- // "modern" Edge was released at 79.x
712
- 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
713
- // and older, Chrome 76+ can use `beforeInput` though.
714
-
715
- 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
716
- // Chrome Legacy doesn't support `beforeinput` correctly
717
-
718
- var HAS_BEFORE_INPUT_SUPPORT = !IS_CHROME_LEGACY && !IS_EDGE_LEGACY && // globalThis is undefined in older browsers
719
- typeof globalThis !== 'undefined' && globalThis.InputEvent && typeof globalThis.InputEvent.prototype.getTargetRanges === 'function'; // The `getTargetRanges` property isn't recognized.
735
+ function withLinkTracking(tracking, Component) {
736
+ return function ComponentWithTracking(props) {
737
+ return /*#__PURE__*/React__default.createElement(Component, Object.assign({}, props, {
738
+ onEntityFetchComplete: function onEntityFetchComplete() {
739
+ tracking.onViewportAction('linkRendered');
740
+ }
741
+ }));
742
+ };
743
+ }
720
744
 
721
745
  function useSdk(_ref) {
722
746
  var sdk = _ref.sdk;
@@ -854,10 +878,19 @@ function FetchingWrappedAssetCard(props) {
854
878
  var asset = assets[props.assetId];
855
879
  var defaultLocaleCode = props.sdk.locales["default"];
856
880
  var entityFile = asset != null && (_asset$fields = asset.fields) != null && _asset$fields.file ? asset.fields.file[props.locale] || asset.fields.file[defaultLocaleCode] : undefined;
881
+ var onEntityFetchComplete = props.onEntityFetchComplete;
857
882
  React.useEffect(function () {
858
883
  getOrLoadAsset(props.assetId);
859
884
  }, [props.assetId]); // eslint-disable-line
860
885
 
886
+ React.useEffect(function () {
887
+ if (!asset) {
888
+ return;
889
+ }
890
+
891
+ onEntityFetchComplete == null ? void 0 : onEntityFetchComplete();
892
+ }, [asset, onEntityFetchComplete]);
893
+
861
894
  function getAssetSrc() {
862
895
  if (!(entityFile != null && entityFile.url)) return '';
863
896
  return entityFile.url + "?h=300";
@@ -982,6 +1015,7 @@ function FetchingWrappedEntryCard(props) {
982
1015
  });
983
1016
  }, [props.sdk, entry]);
984
1017
  var defaultLocaleCode = props.sdk.locales["default"];
1018
+ var onEntityFetchComplete = props.onEntityFetchComplete;
985
1019
  React.useEffect(function () {
986
1020
  if (!entry || entry === 'failed') return;
987
1021
  fieldEditorShared.entityHelpers.getEntryImage({
@@ -997,6 +1031,14 @@ function FetchingWrappedEntryCard(props) {
997
1031
  getOrLoadEntry(props.entryId);
998
1032
  }, [props.entryId]); // eslint-disable-line
999
1033
 
1034
+ React.useEffect(function () {
1035
+ if (!entry) {
1036
+ return;
1037
+ }
1038
+
1039
+ onEntityFetchComplete == null ? void 0 : onEntityFetchComplete();
1040
+ }, [entry, onEntityFetchComplete]);
1041
+
1000
1042
  function renderDropdown() {
1001
1043
  if (!props.onEdit || !props.onRemove) return undefined;
1002
1044
  return [props.onEdit ? /*#__PURE__*/React.createElement(f36Components.MenuItem, {
@@ -1078,13 +1120,14 @@ function FetchingWrappedEntryCard(props) {
1078
1120
 
1079
1121
  var styles$3 = {
1080
1122
  root: /*#__PURE__*/emotion.css({
1081
- marginBottom: '1.25rem'
1123
+ marginBottom: '1.25rem !important'
1082
1124
  })
1083
1125
  };
1084
1126
  function LinkedEntityBlock(props) {
1085
1127
  var attributes = props.attributes,
1086
1128
  children = props.children,
1087
- element = props.element;
1129
+ element = props.element,
1130
+ onEntityFetchComplete = props.onEntityFetchComplete;
1088
1131
  var isSelected = Slate.useSelected();
1089
1132
  var editor = useContentfulEditor();
1090
1133
  var sdk = useSdkContext();
@@ -1126,7 +1169,8 @@ function LinkedEntityBlock(props) {
1126
1169
  isDisabled: isDisabled,
1127
1170
  isSelected: isSelected,
1128
1171
  onRemove: handleRemoveClick,
1129
- onEdit: handleEditClick
1172
+ onEdit: handleEditClick,
1173
+ onEntityFetchComplete: onEntityFetchComplete
1130
1174
  }), entityType === 'Asset' && /*#__PURE__*/React__default.createElement(FetchingWrappedAssetCard, {
1131
1175
  sdk: sdk,
1132
1176
  assetId: entityId,
@@ -1134,7 +1178,8 @@ function LinkedEntityBlock(props) {
1134
1178
  isDisabled: isDisabled,
1135
1179
  isSelected: isSelected,
1136
1180
  onRemove: handleRemoveClick,
1137
- onEdit: handleEditClick
1181
+ onEdit: handleEditClick,
1182
+ onEntityFetchComplete: onEntityFetchComplete
1138
1183
  })), children);
1139
1184
  }
1140
1185
 
@@ -2038,7 +2083,7 @@ function insertBlock(editor, nodeType, entity) {
2038
2083
  slate.Transforms.setNodes(editor, linkedEntityBlock);
2039
2084
  }
2040
2085
 
2041
- Slate.ReactEditor.focus(editor);
2086
+ focus(editor);
2042
2087
  }
2043
2088
 
2044
2089
  var styles$4 = {
@@ -2132,13 +2177,13 @@ function getWithEmbeddedEntityEvents(nodeType, sdk) {
2132
2177
  }
2133
2178
 
2134
2179
  var createEmbeddedEntityPlugin = function createEmbeddedEntityPlugin(nodeType, hotkey) {
2135
- return function (sdk) {
2180
+ return function (sdk, tracking) {
2136
2181
  return {
2137
2182
  key: nodeType,
2138
2183
  type: nodeType,
2139
2184
  isElement: true,
2140
2185
  isVoid: true,
2141
- component: LinkedEntityBlock,
2186
+ component: withLinkTracking(tracking, LinkedEntityBlock),
2142
2187
  options: {
2143
2188
  hotkey: hotkey
2144
2189
  },
@@ -2196,12 +2241,20 @@ function FetchingWrappedInlineEntryCard(props) {
2196
2241
  return entries[props.entryId];
2197
2242
  }, [entries, props.entryId]);
2198
2243
  var allContentTypes = props.sdk.space.getCachedContentTypes();
2244
+ var onEntityFetchComplete = props.onEntityFetchComplete;
2199
2245
  var contentType = React__default.useMemo(function () {
2200
2246
  if (!entry || entry === 'failed' || !allContentTypes) return undefined;
2201
2247
  return allContentTypes.find(function (contentType) {
2202
2248
  return contentType.sys.id === entry.sys.contentType.sys.id;
2203
2249
  });
2204
2250
  }, [allContentTypes, entry]);
2251
+ React__default.useEffect(function () {
2252
+ if (!entry) {
2253
+ return;
2254
+ }
2255
+
2256
+ onEntityFetchComplete == null ? void 0 : onEntityFetchComplete();
2257
+ }, [entry, onEntityFetchComplete]);
2205
2258
  var contentTypeName = contentType ? contentType.name : '';
2206
2259
  var title = React__default.useMemo(function () {
2207
2260
  return getEntryTitle({
@@ -2297,12 +2350,10 @@ var styles$6 = {
2297
2350
  marginRight: '10px'
2298
2351
  }),
2299
2352
  root: /*#__PURE__*/emotion.css({
2300
- margin: '0 1px',
2353
+ display: 'inline-block',
2354
+ margin: "0 " + tokens.spacing2Xs,
2301
2355
  fontSize: 'inherit',
2302
2356
  span: {
2303
- webkitUserSelect: 'none',
2304
- mozUserSelect: 'none',
2305
- msUserSelect: 'none',
2306
2357
  userSelect: 'none'
2307
2358
  }
2308
2359
  })
@@ -2345,7 +2396,8 @@ function EmbeddedEntityInline(props) {
2345
2396
  isSelected: isSelected,
2346
2397
  isDisabled: isDisabled,
2347
2398
  onRemove: handleRemoveClick,
2348
- onEdit: handleEditClick
2399
+ onEdit: handleEditClick,
2400
+ onEntityFetchComplete: props.onEntityFetchComplete
2349
2401
  })), props.children);
2350
2402
  }
2351
2403
 
@@ -2369,7 +2421,7 @@ function _selectEntityAndInsert$1() {
2369
2421
 
2370
2422
  case 4:
2371
2423
  entry = _context2.sent;
2372
- Slate.ReactEditor.focus(editor); // Dialog steals focus from editor, return it.
2424
+ focus(editor); // Dialog steals focus from editor, return it.
2373
2425
 
2374
2426
  if (entry) {
2375
2427
  _context2.next = 8;
@@ -2455,7 +2507,7 @@ function ToolbarEmbeddedEntityInlineButton(props) {
2455
2507
  className: "rich-text__embedded-entry-list-icon " + styles$6.icon
2456
2508
  }), /*#__PURE__*/React.createElement("span", null, "Inline entry")));
2457
2509
  }
2458
- function createEmbeddedEntityInlinePlugin(sdk) {
2510
+ function createEmbeddedEntityInlinePlugin(sdk, tracking) {
2459
2511
  var htmlAttributeName = 'data-embedded-entity-inline-id';
2460
2512
  return {
2461
2513
  key: Contentful.INLINES.EMBEDDED_ENTRY,
@@ -2463,7 +2515,7 @@ function createEmbeddedEntityInlinePlugin(sdk) {
2463
2515
  isElement: true,
2464
2516
  isInline: true,
2465
2517
  isVoid: true,
2466
- component: EmbeddedEntityInline,
2518
+ component: withLinkTracking(tracking, EmbeddedEntityInline),
2467
2519
  options: {
2468
2520
  hotkey: 'mod+shift+2'
2469
2521
  },
@@ -2577,14 +2629,25 @@ function ToolbarHeadingButton(props) {
2577
2629
  unwrapFromRoot(editor);
2578
2630
  }
2579
2631
 
2632
+ var prevOnChange = editor.onChange;
2633
+ /*
2634
+ The focus might happen at point in time when
2635
+ `toggleNodeType` changes aren't rendered yet, causing the browser
2636
+ to place the cursor at the start of the text.
2637
+ We wait for the change event before focusing
2638
+ the editor again. This ensures the cursor is back at the previous
2639
+ position.*/
2640
+
2641
+ editor.onChange = function () {
2642
+ focus(editor);
2643
+ editor.onChange = prevOnChange;
2644
+ prevOnChange.apply(void 0, arguments);
2645
+ };
2646
+
2580
2647
  plateCore.toggleNodeType(editor, {
2581
2648
  activeType: type,
2582
2649
  inactiveType: type
2583
- }); // TODO: Figure out why focus only works with timeout here.
2584
-
2585
- setTimeout(function () {
2586
- Slate.ReactEditor.focus(editor);
2587
- }, 0);
2650
+ });
2588
2651
  };
2589
2652
  }
2590
2653
 
@@ -2714,16 +2777,6 @@ var createHeadingPlugin = function createHeadingPlugin() {
2714
2777
  allow: Contentful.HEADINGS
2715
2778
  }
2716
2779
  }],
2717
- exitBreak: [// Pressing ENTER at the start or end of a heading text inserts a
2718
- // normal paragraph
2719
- {
2720
- hotkey: 'enter',
2721
- query: {
2722
- allow: Contentful.HEADINGS,
2723
- end: true,
2724
- start: true
2725
- }
2726
- }],
2727
2780
  normalizer: [{
2728
2781
  match: {
2729
2782
  type: Contentful.HEADINGS
@@ -2734,6 +2787,31 @@ var createHeadingPlugin = function createHeadingPlugin() {
2734
2787
  },
2735
2788
  transform: (_transform = {}, _transform[Contentful.BLOCKS.PARAGRAPH] = transformUnwrap, _transform["default"] = transformLift, _transform)
2736
2789
  }],
2790
+ then: function then(editor) {
2791
+ return {
2792
+ exitBreak: [// Pressing ENTER at the start or end of a heading text inserts a
2793
+ // normal paragraph.
2794
+ {
2795
+ hotkey: 'enter',
2796
+ query: {
2797
+ allow: Contentful.HEADINGS,
2798
+ end: true,
2799
+ start: true,
2800
+ // Exclude headings inside lists as it interferes with the list's
2801
+ // insertBreak implementation
2802
+ filter: function filter(_ref2) {
2803
+ var path = _ref2[1];
2804
+ return !plateCore.getAbove(editor, {
2805
+ at: path,
2806
+ match: {
2807
+ type: Contentful.BLOCKS.LIST_ITEM
2808
+ }
2809
+ });
2810
+ }
2811
+ }
2812
+ }]
2813
+ };
2814
+ },
2737
2815
  plugins: Contentful.HEADINGS.map(function (nodeType, idx) {
2738
2816
  var level = idx + 1;
2739
2817
  var tagName = "h" + level;
@@ -2856,7 +2934,7 @@ function ToolbarHrButton(props) {
2856
2934
  hasText ? slate.Transforms.insertNodes(editor, hr) : plateCore.setNodes(editor, hr); // Move focus to the next paragraph (added by TrailingParagraph plugin)
2857
2935
 
2858
2936
  moveToTheNextLine(editor);
2859
- Slate.ReactEditor.focus(editor);
2937
+ focus(editor);
2860
2938
  }
2861
2939
 
2862
2940
  if (!editor) return null;
@@ -3348,7 +3426,7 @@ function _addOrEditLink() {
3348
3426
  path: path
3349
3427
  });
3350
3428
  });
3351
- Slate.ReactEditor.focus(editor);
3429
+ focus(editor);
3352
3430
 
3353
3431
  case 15:
3354
3432
  case "end":
@@ -3410,37 +3488,11 @@ function UrlHyperlink(props) {
3410
3488
  var sdk = useSdkContext();
3411
3489
  var uri = props.element.data.uri;
3412
3490
 
3413
- function handleClick(_x) {
3414
- return _handleClick.apply(this, arguments);
3415
- }
3416
-
3417
- function _handleClick() {
3418
- _handleClick = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee(event) {
3419
- return runtime_1.wrap(function _callee$(_context) {
3420
- while (1) {
3421
- switch (_context.prev = _context.next) {
3422
- case 0:
3423
- event.preventDefault();
3424
- event.stopPropagation();
3425
-
3426
- if (editor) {
3427
- _context.next = 4;
3428
- break;
3429
- }
3430
-
3431
- return _context.abrupt("return");
3432
-
3433
- case 4:
3434
- addOrEditLink(editor, sdk);
3435
-
3436
- case 5:
3437
- case "end":
3438
- return _context.stop();
3439
- }
3440
- }
3441
- }, _callee);
3442
- }));
3443
- return _handleClick.apply(this, arguments);
3491
+ function handleClick(event) {
3492
+ event.preventDefault();
3493
+ event.stopPropagation();
3494
+ if (!editor) return;
3495
+ addOrEditLink(editor, sdk);
3444
3496
  }
3445
3497
 
3446
3498
  return /*#__PURE__*/React.createElement(f36Components.Tooltip, {
@@ -3463,39 +3515,20 @@ function EntityHyperlink(props) {
3463
3515
  var isReadOnly = Slate.useReadOnly();
3464
3516
  var sdk = useSdkContext();
3465
3517
  var target = props.element.data.target;
3518
+ var onEntityFetchComplete = props.onEntityFetchComplete;
3519
+ React.useEffect(function () {
3520
+ // The real entity loading happens in the tooltip
3521
+ // Since that is deferred the link is considered rendered as soon
3522
+ // the component mounts (link text displayed)
3523
+ onEntityFetchComplete == null ? void 0 : onEntityFetchComplete();
3524
+ }, [onEntityFetchComplete]);
3466
3525
  if (!target) return null;
3467
3526
 
3468
- function handleClick(_x2) {
3469
- return _handleClick2.apply(this, arguments);
3470
- }
3471
-
3472
- function _handleClick2() {
3473
- _handleClick2 = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(event) {
3474
- return runtime_1.wrap(function _callee2$(_context2) {
3475
- while (1) {
3476
- switch (_context2.prev = _context2.next) {
3477
- case 0:
3478
- event.preventDefault();
3479
- event.stopPropagation();
3480
-
3481
- if (editor) {
3482
- _context2.next = 4;
3483
- break;
3484
- }
3485
-
3486
- return _context2.abrupt("return");
3487
-
3488
- case 4:
3489
- addOrEditLink(editor, sdk);
3490
-
3491
- case 5:
3492
- case "end":
3493
- return _context2.stop();
3494
- }
3495
- }
3496
- }, _callee2);
3497
- }));
3498
- return _handleClick2.apply(this, arguments);
3527
+ function handleClick(event) {
3528
+ event.preventDefault();
3529
+ event.stopPropagation();
3530
+ if (!editor) return;
3531
+ addOrEditLink(editor, sdk);
3499
3532
  }
3500
3533
 
3501
3534
  return /*#__PURE__*/React.createElement(f36Components.Tooltip, {
@@ -3508,7 +3541,7 @@ function EntityHyperlink(props) {
3508
3541
  placement: "bottom",
3509
3542
  maxWidth: "auto"
3510
3543
  }, /*#__PURE__*/React.createElement(f36Components.TextLink, {
3511
- as: "button",
3544
+ as: "a",
3512
3545
  onClick: handleClick,
3513
3546
  isDisabled: isReadOnly,
3514
3547
  className: styles$c.hyperlink,
@@ -3523,21 +3556,21 @@ function ToolbarHyperlinkButton(props) {
3523
3556
  var sdk = useSdkContext();
3524
3557
 
3525
3558
  function handleClick() {
3526
- return _handleClick3.apply(this, arguments);
3559
+ return _handleClick.apply(this, arguments);
3527
3560
  }
3528
3561
 
3529
- function _handleClick3() {
3530
- _handleClick3 = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee3() {
3531
- return runtime_1.wrap(function _callee3$(_context3) {
3562
+ function _handleClick() {
3563
+ _handleClick = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee() {
3564
+ return runtime_1.wrap(function _callee$(_context) {
3532
3565
  while (1) {
3533
- switch (_context3.prev = _context3.next) {
3566
+ switch (_context.prev = _context.next) {
3534
3567
  case 0:
3535
3568
  if (editor) {
3536
- _context3.next = 2;
3569
+ _context.next = 2;
3537
3570
  break;
3538
3571
  }
3539
3572
 
3540
- return _context3.abrupt("return");
3573
+ return _context.abrupt("return");
3541
3574
 
3542
3575
  case 2:
3543
3576
  if (isActive) {
@@ -3548,12 +3581,12 @@ function ToolbarHyperlinkButton(props) {
3548
3581
 
3549
3582
  case 3:
3550
3583
  case "end":
3551
- return _context3.stop();
3584
+ return _context.stop();
3552
3585
  }
3553
3586
  }
3554
- }, _callee3);
3587
+ }, _callee);
3555
3588
  }));
3556
- return _handleClick3.apply(this, arguments);
3589
+ return _handleClick.apply(this, arguments);
3557
3590
  }
3558
3591
 
3559
3592
  if (!editor) return null;
@@ -3619,7 +3652,7 @@ var getNodeOfType = function getNodeOfType(type) {
3619
3652
  };
3620
3653
  };
3621
3654
 
3622
- var createHyperlinkPlugin = function createHyperlinkPlugin(sdk) {
3655
+ var createHyperlinkPlugin = function createHyperlinkPlugin(sdk, tracking) {
3623
3656
  var common = {
3624
3657
  isElement: true,
3625
3658
  isInline: true
@@ -3650,7 +3683,7 @@ var createHyperlinkPlugin = function createHyperlinkPlugin(sdk) {
3650
3683
  _extends({}, common, {
3651
3684
  key: Contentful.INLINES.ENTRY_HYPERLINK,
3652
3685
  type: Contentful.INLINES.ENTRY_HYPERLINK,
3653
- component: EntityHyperlink,
3686
+ component: withLinkTracking(tracking, EntityHyperlink),
3654
3687
  deserializeHtml: {
3655
3688
  rules: [{
3656
3689
  validNodeName: ['A']
@@ -3664,7 +3697,7 @@ var createHyperlinkPlugin = function createHyperlinkPlugin(sdk) {
3664
3697
  _extends({}, common, {
3665
3698
  key: Contentful.INLINES.ASSET_HYPERLINK,
3666
3699
  type: Contentful.INLINES.ASSET_HYPERLINK,
3667
- component: EntityHyperlink,
3700
+ component: withLinkTracking(tracking, EntityHyperlink),
3668
3701
  deserializeHtml: {
3669
3702
  rules: [{
3670
3703
  validNodeName: ['A']
@@ -3686,7 +3719,7 @@ var createHyperlinkPlugin = function createHyperlinkPlugin(sdk) {
3686
3719
  };
3687
3720
 
3688
3721
  var _templateObject$4, _templateObject2$3, _templateObject3$3, _styles;
3689
- var baseStyle = /*#__PURE__*/emotion.css(_templateObject$4 || (_templateObject$4 = /*#__PURE__*/_taggedTemplateLiteralLoose(["\n padding: 0;\n margin: 0 0 1.25rem 1.25rem;\n div:first-child {\n margin: 0;\n line-height: ", ";\n }\n"])), tokens.lineHeightDefault);
3722
+ var baseStyle = /*#__PURE__*/emotion.css(_templateObject$4 || (_templateObject$4 = /*#__PURE__*/_taggedTemplateLiteralLoose(["\n padding: 0;\n margin: 0 0 1.25rem 1.25rem;\n\n div:first-child {\n margin: 0;\n line-height: ", ";\n }\n"])), tokens.lineHeightDefault);
3690
3723
  var styles$d = (_styles = {}, _styles[Contentful.BLOCKS.UL_LIST] = /*#__PURE__*/emotion.css(_templateObject2$3 || (_templateObject2$3 = /*#__PURE__*/_taggedTemplateLiteralLoose(["\n list-style-type: disc;\n ul {\n list-style-type: circle;\n ul {\n list-style-type: square;\n }\n }\n "]))), _styles[Contentful.BLOCKS.OL_LIST] = /*#__PURE__*/emotion.css(_templateObject3$3 || (_templateObject3$3 = /*#__PURE__*/_taggedTemplateLiteralLoose(["\n list-style-type: decimal;\n ol {\n list-style-type: upper-alpha;\n ol {\n list-style-type: lower-roman;\n ol {\n list-style-type: lower-alpha;\n }\n }\n }\n "]))), _styles);
3691
3724
 
3692
3725
  function createList(Tag, block) {
@@ -3701,7 +3734,7 @@ var ListUL = /*#__PURE__*/createList('ul', Contentful.BLOCKS.UL_LIST);
3701
3734
  var ListOL = /*#__PURE__*/createList('ol', Contentful.BLOCKS.OL_LIST);
3702
3735
 
3703
3736
  var _templateObject$5;
3704
- var style = /*#__PURE__*/emotion.css(_templateObject$5 || (_templateObject$5 = /*#__PURE__*/_taggedTemplateLiteralLoose(["\n margin: 0;\n list-style: inherit;\n ol,\n ul {\n margin: 0 0 0 ", ";\n }\n"])), tokens.spacingL);
3737
+ var style = /*#__PURE__*/emotion.css(_templateObject$5 || (_templateObject$5 = /*#__PURE__*/_taggedTemplateLiteralLoose(["\n margin: 0;\n list-style: inherit;\n margin-top: ", ";\n\n ol,\n ul {\n margin: 0 0 0 ", ";\n }\n"])), tokens.spacingXs, tokens.spacingL);
3705
3738
  function ListItem(props) {
3706
3739
  return /*#__PURE__*/React.createElement("li", Object.assign({}, props.attributes, {
3707
3740
  className: style
@@ -3769,66 +3802,285 @@ var insertParagraphAsChild = function insertParagraphAsChild(editor, _ref5) {
3769
3802
  };
3770
3803
 
3771
3804
  /**
3772
- * A copy of Plate's list plugin with a few adjustments
3773
- * to support pasting any element
3805
+ * Build a new list item node while preserving marks
3774
3806
  */
3775
- var getListInsertFragment = function getListInsertFragment(editor) {
3776
- var insertFragment = editor.insertFragment;
3777
- var li = plateCore.getPlugin(editor, plateList.ELEMENT_LI);
3778
- var ul = plateCore.getPlugin(editor, plateList.ELEMENT_UL);
3779
- var ol = plateCore.getPlugin(editor, plateList.ELEMENT_OL);
3780
3807
 
3781
- var isListRoot = function isListRoot(node) {
3782
- return [ul.type, ol.type].includes(node.type);
3808
+ var emptyListItemNode = function emptyListItemNode(editor, withChildren) {
3809
+ if (withChildren === void 0) {
3810
+ withChildren = false;
3811
+ }
3812
+
3813
+ var children = [];
3814
+
3815
+ if (withChildren) {
3816
+ var marks = slate.Editor.marks(editor) || {};
3817
+ children = [{
3818
+ type: Contentful.BLOCKS.PARAGRAPH,
3819
+ data: {},
3820
+ children: [_extends({
3821
+ text: ''
3822
+ }, marks)]
3823
+ }];
3824
+ }
3825
+
3826
+ return {
3827
+ type: Contentful.BLOCKS.LIST_ITEM,
3828
+ data: {},
3829
+ children: children
3783
3830
  };
3831
+ };
3832
+ /**
3833
+ * Insert list item if selection is in li>p.
3834
+ */
3784
3835
 
3785
- var getFirstAncestorOfType = function getFirstAncestorOfType(root, entry, _ref) {
3786
- var type = _ref.type;
3787
- var ancestor = slate.Path.parent(entry[1]);
3788
3836
 
3789
- while (slate.Node.get(root, ancestor).type !== type) {
3790
- ancestor = slate.Path.parent(ancestor);
3837
+ var insertListItem = function insertListItem(editor) {
3838
+ if (!editor.selection) {
3839
+ return false;
3840
+ } // Naming it paragraph for simplicity but can be a heading as well
3841
+
3842
+
3843
+ var paragraph = plateCore.getAbove(editor, {
3844
+ match: {
3845
+ type: Contentful.TEXT_CONTAINERS
3791
3846
  }
3847
+ });
3792
3848
 
3793
- return [slate.Node.get(root, ancestor), ancestor];
3794
- };
3849
+ if (!paragraph) {
3850
+ return false;
3851
+ }
3852
+
3853
+ var paragraphPath = paragraph[1];
3854
+ var listItem = plateCore.getParent(editor, paragraphPath);
3855
+
3856
+ if (!listItem) {
3857
+ return false;
3858
+ }
3859
+
3860
+ var listItemNode = listItem[0],
3861
+ listItemPath = listItem[1];
3862
+
3863
+ if (listItemNode.type !== Contentful.BLOCKS.LIST_ITEM) {
3864
+ return false;
3865
+ } // We are in a li>p (or heading)
3866
+
3867
+
3868
+ slate.Editor.withoutNormalizing(editor, function () {
3869
+ if (!editor.selection) {
3870
+ return;
3871
+ } // Check the cursor position in the current paragraph
3872
+
3873
+
3874
+ var isAtStart = plateCore.isSelectionAtBlockStart(editor);
3875
+ var isAtEnd = plateCore.isSelectionAtBlockEnd(editor);
3876
+ var isAtStartOfListItem = isAtStart && plateCore.isFirstChild(paragraphPath);
3877
+ var shouldSplit = !isAtStart && !isAtEnd; // Split the current paragraph content if necessary
3878
+
3879
+ if (shouldSplit) {
3880
+ slate.Transforms.splitNodes(editor);
3881
+ } // Insert the new li
3882
+
3883
+
3884
+ var newListItemPath = isAtStartOfListItem ? listItemPath : slate.Path.next(listItemPath);
3885
+ plateCore.insertNodes(editor, // Add an empty paragraph to the new li if We will not move some
3886
+ // paragraphs over there.
3887
+ emptyListItemNode(editor, !shouldSplit), {
3888
+ at: newListItemPath
3889
+ }); // Move children *after* selection to the new li
3890
+
3891
+ var fromPath = isAtStart ? paragraphPath : slate.Path.next(paragraphPath);
3892
+ var fromStartIndex = fromPath[fromPath.length - 1] || 0; // On split we don't add paragraph to the new li so we move
3893
+ // content to the very beginning. Otherwise, account for the empty
3894
+ // paragraph at the beginning by moving the content after
3895
+
3896
+ var toPath = newListItemPath.concat([shouldSplit ? 0 : 1]);
3897
+
3898
+ if (!isAtStartOfListItem) {
3899
+ plateCore.moveChildren(editor, {
3900
+ at: listItemPath,
3901
+ to: toPath,
3902
+ fromStartIndex: fromStartIndex
3903
+ });
3904
+ } // Move cursor to the start of the new li
3905
+
3906
+
3907
+ slate.Transforms.select(editor, newListItemPath);
3908
+ slate.Transforms.collapse(editor, {
3909
+ edge: 'start'
3910
+ });
3911
+ }); // Returning True skips processing other editor.insertBreak handlers
3912
+
3913
+ return true;
3914
+ };
3915
+
3916
+ /**
3917
+ * Credit: Copied & modified version from Plate's list plugin to support
3918
+ * list items with multiple children.
3919
+ *
3920
+ * See: https://github.com/udecode/plate/blob/main/packages/nodes/list
3921
+ */
3922
+
3923
+ var listBreak = function listBreak(editor) {
3924
+ if (!editor.selection) return false;
3925
+ var res = plateList.getListItemEntry(editor, {});
3926
+ var moved; // If selection is in a li
3927
+
3928
+ if (res) {
3929
+ var list = res.list,
3930
+ listItem = res.listItem;
3931
+ var childNode = listItem[0].children[0]; // If selected li is empty, move it up.
3932
+
3933
+ if (plateCore.isBlockAboveEmpty(editor) && listItem[0].children.length === 1 && Contentful.TEXT_CONTAINERS.includes(childNode.type)) {
3934
+ moved = plateList.moveListItemUp(editor, {
3935
+ list: list,
3936
+ listItem: listItem
3937
+ });
3938
+ if (moved) return true;
3939
+ }
3940
+ }
3941
+
3942
+ var didReset = plateResetNode.onKeyDownResetNode(editor, plateCore.mockPlugin({
3943
+ options: {
3944
+ rules: [{
3945
+ types: [plateCore.getPluginType(editor, plateList.ELEMENT_LI)],
3946
+ defaultType: plateCore.getPluginType(editor, plateCore.ELEMENT_DEFAULT),
3947
+ predicate: function predicate() {
3948
+ return !moved && plateCore.isBlockAboveEmpty(editor);
3949
+ },
3950
+ onReset: function onReset(_editor) {
3951
+ return plateList.unwrapList(_editor);
3952
+ }
3953
+ }]
3954
+ }
3955
+ }))(plateResetNode.SIMULATE_BACKSPACE);
3956
+
3957
+ if (didReset) {
3958
+ return true;
3959
+ }
3795
3960
  /**
3796
- * Removes the "empty" leading lis. Empty in this context means lis only with other lis as children.
3797
- *
3798
- * @returns If argument is not a list root, returns it, otherwise returns ul[] or li[].
3961
+ * If selection is in li > p, insert li.
3799
3962
  */
3800
3963
 
3801
3964
 
3802
- var trimList = function trimList(listRoot) {
3803
- if (!isListRoot(listRoot)) {
3804
- return [listRoot];
3805
- }
3965
+ if (!moved) {
3966
+ var inserted = insertListItem(editor);
3967
+ if (inserted) return true;
3968
+ }
3969
+
3970
+ return false;
3971
+ };
3806
3972
 
3807
- var textEntries = Array.from(slate.Node.texts(listRoot));
3808
- var commonAncestorEntry = textEntries.reduce(function (commonAncestor, textEntry) {
3809
- return slate.Path.isAncestor(commonAncestor[1], textEntry[1]) ? commonAncestor : slate.Node.common(listRoot, textEntry[1], commonAncestor[1]);
3810
- }, // any list item would do, we grab the first one
3811
- getFirstAncestorOfType(listRoot, textEntries[0], li));
3812
- return isListRoot(commonAncestorEntry[0]) ? commonAncestorEntry[0].children : [commonAncestorEntry[0]];
3973
+ var insertListBreak = function insertListBreak(editor) {
3974
+ var insertBreak = editor.insertBreak;
3975
+ return function () {
3976
+ if (listBreak(editor)) return;
3977
+ insertBreak();
3813
3978
  };
3979
+ };
3980
+
3981
+ /**
3982
+ * Credit: Modified version of Plate's list plugin
3983
+ * See: https://github.com/udecode/plate/blob/main/packages/nodes/list
3984
+ */
3985
+
3986
+ var getFirstAncestorOfType = function getFirstAncestorOfType(root, entry) {
3987
+ var ancestor = slate.Path.parent(entry[1]);
3988
+
3989
+ while (slate.Node.get(root, ancestor).type !== Contentful.BLOCKS.LIST_ITEM) {
3990
+ ancestor = slate.Path.parent(ancestor);
3991
+ }
3992
+
3993
+ return [slate.Node.get(root, ancestor), ancestor];
3994
+ };
3995
+
3996
+ var isListRoot = function isListRoot(node) {
3997
+ return [Contentful.BLOCKS.UL_LIST, Contentful.BLOCKS.OL_LIST].includes(node.type);
3998
+ };
3999
+ /**
4000
+ * Removes the "empty" leading lis. Empty in this context means lis only with other lis as children.
4001
+ *
4002
+ * @returns If argument is not a list root, returns it, otherwise returns ul[] or li[].
4003
+ */
4004
+
4005
+
4006
+ var trimList = function trimList(listRoot) {
4007
+ if (!isListRoot(listRoot)) {
4008
+ return [listRoot];
4009
+ }
4010
+
4011
+ var textEntries = Array.from(slate.Node.texts(listRoot));
4012
+ var commonAncestorEntry = textEntries.reduce(function (commonAncestor, textEntry) {
4013
+ return slate.Path.isAncestor(commonAncestor[1], textEntry[1]) ? commonAncestor : slate.Node.common(listRoot, textEntry[1], commonAncestor[1]);
4014
+ }, // any list item would do, we grab the first one
4015
+ getFirstAncestorOfType(listRoot, textEntries[0]));
4016
+ return isListRoot(commonAncestorEntry[0]) ? commonAncestorEntry[0].children : [commonAncestorEntry[0]];
4017
+ };
4018
+ /**
4019
+ * Removes leading li when pasting a single li with a single child.
4020
+ */
4021
+
4022
+
4023
+ var trimLiWrapper = function trimLiWrapper(nodes) {
4024
+ if (nodes.length !== 1) {
4025
+ return nodes;
4026
+ }
4027
+
4028
+ var node = nodes[0];
4029
+
4030
+ if (node.type !== Contentful.BLOCKS.LIST_ITEM || node.children.length !== 1) {
4031
+ return nodes;
4032
+ }
3814
4033
 
4034
+ return node.children;
4035
+ };
4036
+
4037
+ var unwrapTextContainerAtStart = function unwrapTextContainerAtStart(nodes) {
4038
+ var node = nodes[0];
4039
+
4040
+ if (Contentful.TEXT_CONTAINERS.includes(node.type)) {
4041
+ return [].concat(node.children, nodes.slice(1));
4042
+ }
4043
+
4044
+ return nodes;
4045
+ };
4046
+
4047
+ var insertListFragment = function insertListFragment(editor) {
4048
+ var insertFragment = editor.insertFragment;
3815
4049
  return function (fragment) {
4050
+ if (!editor.selection) {
4051
+ return;
4052
+ }
4053
+
3816
4054
  var liEntry = plateCore.findNode(editor, {
3817
4055
  match: {
3818
- type: li.type
4056
+ type: Contentful.BLOCKS.LIST_ITEM
3819
4057
  },
3820
4058
  mode: 'lowest'
3821
4059
  });
3822
4060
 
3823
4061
  if (liEntry) {
3824
- var liPath = liEntry[1]; // FIXME: this is a temporarily workaround and needs a follow-up to properly
3825
- // non-text elements
3826
-
3827
- var nodes = fragment.flatMap(function (node) {
4062
+ var nodes = unwrapTextContainerAtStart(trimLiWrapper(fragment.flatMap(function (node) {
3828
4063
  return trimList(node);
4064
+ })));
4065
+ var firstBlockIndex = nodes.findIndex(function (node) {
4066
+ return slate.Editor.isBlock(editor, node);
4067
+ });
4068
+
4069
+ if (firstBlockIndex < 0) {
4070
+ firstBlockIndex = nodes.length;
4071
+ }
4072
+
4073
+ var inlines = nodes.slice(0, firstBlockIndex);
4074
+ var blocks = nodes.slice(firstBlockIndex); // Two calls to insertNodes are required here. Otherwise, all blocks
4075
+ // after a text or inline element occurrence will be unwrapped for
4076
+ // some reason.
4077
+
4078
+ slate.Transforms.insertNodes(editor, inlines, {
4079
+ at: editor.selection,
4080
+ select: true
3829
4081
  });
3830
- return slate.Transforms.insertNodes(editor, nodes, {
3831
- at: editor.selection || slate.Path.next(liPath),
4082
+ return slate.Transforms.insertNodes(editor, blocks, {
4083
+ at: editor.selection,
3832
4084
  select: true
3833
4085
  });
3834
4086
  }
@@ -3840,18 +4092,37 @@ var getListInsertFragment = function getListInsertFragment(editor) {
3840
4092
  };
3841
4093
  };
3842
4094
 
3843
- var options = {
3844
- validLiChildrenTypes: Contentful.LIST_ITEM_BLOCKS
3845
- };
3846
- var withList = function withList(editor, plugin) {
3847
- var insertFragment = editor.insertFragment;
3848
- plateList.withList(editor, _extends({}, plugin, {
3849
- options: options
3850
- })); // Reverts any overrides to insertFragment
4095
+ /**
4096
+ * Credit: Modified version of Plate's list plugin
4097
+ * See: https://github.com/udecode/plate/blob/main/packages/nodes/list
4098
+ */
4099
+ var validLiChildrenTypes = Contentful.LIST_ITEM_BLOCKS;
4100
+ var withList = function withList(editor) {
4101
+ var deleteBackward = editor.deleteBackward,
4102
+ deleteForward = editor.deleteForward,
4103
+ deleteFragment = editor.deleteFragment;
4104
+
4105
+ editor.deleteBackward = function (unit) {
4106
+ if (plateList.deleteBackwardList(editor, unit)) return;
4107
+ deleteBackward(unit);
4108
+ };
3851
4109
 
3852
- editor.insertFragment = insertFragment; // Use our custom getListInsertFragment
4110
+ editor.deleteForward = function (unit) {
4111
+ if (plateList.deleteForwardList(editor)) return;
4112
+ deleteForward(unit);
4113
+ };
4114
+
4115
+ editor.deleteFragment = function () {
4116
+ if (plateList.deleteFragmentList(editor)) return;
4117
+ deleteFragment();
4118
+ };
3853
4119
 
3854
- editor.insertFragment = getListInsertFragment(editor);
4120
+ editor.insertBreak = insertListBreak(editor);
4121
+ editor.insertFragment = insertListFragment(editor); // TODO: replace with Normalizer rules
4122
+
4123
+ editor.normalizeNode = plateList.normalizeList(editor, {
4124
+ validLiChildrenTypes: validLiChildrenTypes
4125
+ });
3855
4126
  return editor;
3856
4127
  };
3857
4128
 
@@ -3909,7 +4180,7 @@ function ToolbarListButton(props) {
3909
4180
  plateList.toggleList(editor, {
3910
4181
  type: type
3911
4182
  });
3912
- Slate.ReactEditor.focus(editor);
4183
+ focus(editor);
3913
4184
  };
3914
4185
  }
3915
4186
 
@@ -3937,7 +4208,7 @@ function ToolbarBoldButton(props) {
3937
4208
  plateCore.toggleMark(editor, {
3938
4209
  key: Contentful.MARKS.BOLD
3939
4210
  });
3940
- Slate.ReactEditor.focus(editor);
4211
+ focus(editor);
3941
4212
  }
3942
4213
 
3943
4214
  if (!editor) return null;
@@ -3996,7 +4267,7 @@ function ToolbarCodeButton(props) {
3996
4267
  plateCore.toggleMark(editor, {
3997
4268
  key: Contentful.MARKS.CODE
3998
4269
  });
3999
- Slate.ReactEditor.focus(editor);
4270
+ focus(editor);
4000
4271
  }
4001
4272
 
4002
4273
  if (!editor) return null;
@@ -4046,7 +4317,7 @@ function ToolbarItalicButton(props) {
4046
4317
  plateCore.toggleMark(editor, {
4047
4318
  key: Contentful.MARKS.ITALIC
4048
4319
  });
4049
- Slate.ReactEditor.focus(editor);
4320
+ focus(editor);
4050
4321
  }
4051
4322
 
4052
4323
  if (!editor) return null;
@@ -4100,7 +4371,7 @@ function ToolbarUnderlineButton(props) {
4100
4371
  plateCore.toggleMark(editor, {
4101
4372
  key: Contentful.MARKS.UNDERLINE
4102
4373
  });
4103
- Slate.ReactEditor.focus(editor);
4374
+ focus(editor);
4104
4375
  }
4105
4376
 
4106
4377
  if (!editor) return null;
@@ -4521,6 +4792,38 @@ function Quote(props) {
4521
4792
  }), props.children);
4522
4793
  }
4523
4794
 
4795
+ function toggleQuote(editor) {
4796
+ if (!editor.selection) return;
4797
+ var isActive = isBlockSelected(editor, Contentful.BLOCKS.QUOTE);
4798
+ slate.Editor.withoutNormalizing(editor, function () {
4799
+ slate.Transforms.unwrapNodes(editor, {
4800
+ match: function match(node) {
4801
+ return slate.Element.isElement(node) && node.type === Contentful.BLOCKS.QUOTE;
4802
+ },
4803
+ split: true
4804
+ });
4805
+
4806
+ if (!isActive) {
4807
+ var quote = {
4808
+ type: Contentful.BLOCKS.QUOTE,
4809
+ data: {},
4810
+ children: []
4811
+ };
4812
+ slate.Transforms.wrapNodes(editor, quote);
4813
+ }
4814
+ });
4815
+ }
4816
+ var onKeyDownToggleQuote = function onKeyDownToggleQuote(editor, plugin) {
4817
+ return function (event) {
4818
+ var hotkey = plugin.options.hotkey;
4819
+
4820
+ if (hotkey && isHotkey(hotkey, event)) {
4821
+ event.preventDefault();
4822
+ toggleQuote(editor);
4823
+ }
4824
+ };
4825
+ };
4826
+
4524
4827
  function createQuotePlugin() {
4525
4828
  var _transform;
4526
4829
 
@@ -4533,7 +4836,7 @@ function createQuotePlugin() {
4533
4836
  hotkey: 'mod+shift+1'
4534
4837
  },
4535
4838
  handlers: {
4536
- onKeyDown: plateCore.onKeyDownToggleElement
4839
+ onKeyDown: onKeyDownToggleQuote
4537
4840
  },
4538
4841
  deserializeHtml: {
4539
4842
  rules: [{
@@ -4547,38 +4850,13 @@ function createQuotePlugin() {
4547
4850
  };
4548
4851
  }
4549
4852
 
4550
- function toggleQuote(editor) {
4551
- if (!editor.selection) return;
4552
- var isActive = isBlockSelected(editor, Contentful.BLOCKS.QUOTE);
4553
- slate.Editor.withoutNormalizing(editor, function () {
4554
- slate.Transforms.unwrapNodes(editor, {
4555
- match: function match(node) {
4556
- return slate.Element.isElement(node) && node.type === Contentful.BLOCKS.QUOTE;
4557
- },
4558
- split: true
4559
- });
4560
- slate.Transforms.setNodes(editor, {
4561
- type: isActive ? Contentful.BLOCKS.PARAGRAPH : Contentful.BLOCKS.QUOTE
4562
- });
4563
-
4564
- if (!isActive) {
4565
- var quote = {
4566
- type: Contentful.BLOCKS.QUOTE,
4567
- data: {},
4568
- children: []
4569
- };
4570
- slate.Transforms.wrapNodes(editor, quote);
4571
- }
4572
- });
4573
- }
4574
-
4575
4853
  function ToolbarQuoteButton(props) {
4576
4854
  var editor = useContentfulEditor();
4577
4855
 
4578
4856
  function handleOnClick() {
4579
4857
  if (!editor) return;
4580
4858
  toggleQuote(editor);
4581
- Slate.ReactEditor.focus(editor);
4859
+ focus(editor);
4582
4860
  }
4583
4861
 
4584
4862
  if (!editor) return null;
@@ -4934,11 +5212,7 @@ var TableActions = function TableActions() {
4934
5212
 
4935
5213
  var close = React__default.useCallback(function () {
4936
5214
  setOpen(false);
4937
- if (!editor) return; // Makes sure we keep the editor in focus when clicking on/out
4938
- // the dropdown menu
4939
-
4940
- Slate.ReactEditor.focus(editor);
4941
- }, [editor]);
5215
+ }, []);
4942
5216
  React__default.useEffect(function () {
4943
5217
  setHeaderEnabled(Boolean(editor && isTableHeaderEnabled(editor)));
4944
5218
  }, [editor]);
@@ -5207,7 +5481,7 @@ function ToolbarTableButton(props) {
5207
5481
  case 2:
5208
5482
  onViewportAction('insertTable');
5209
5483
  insertTableAndFocusFirstCell(editor);
5210
- Slate.ReactEditor.focus(editor);
5484
+ focus(editor);
5211
5485
 
5212
5486
  case 5:
5213
5487
  case "end":
@@ -5234,22 +5508,52 @@ function createTextPlugin() {
5234
5508
  return {
5235
5509
  key: 'TextPlugin',
5236
5510
  withOverrides: function withOverrides(editor) {
5237
- var deleteForward = editor.deleteForward; // When pressing delete instead of backspace
5511
+ // Reverts the change made upstream that caused the cursor
5512
+ // to be trapped inside inline elements.
5513
+ //
5514
+ // Reverts https://github.com/ianstormtaylor/slate/pull/4578/
5515
+ // Related https://github.com/ianstormtaylor/slate/issues/4704
5516
+ var insertText = editor.insertText;
5517
+
5518
+ editor.insertText = function (text) {
5519
+ var selection = editor.selection; // If the cursor is at the end of an inline, move it outside
5520
+ // before inserting
5521
+
5522
+ if (selection && slate.Range.isCollapsed(selection)) {
5523
+ var _Editor$above;
5524
+
5525
+ var inlinePath = (_Editor$above = slate.Editor.above(editor, {
5526
+ match: function match(n) {
5527
+ return slate.Editor.isInline(editor, n);
5528
+ },
5529
+ mode: 'highest'
5530
+ })) == null ? void 0 : _Editor$above[1];
5531
+
5532
+ if (inlinePath && slate.Editor.isEnd(editor, selection.anchor, inlinePath)) {
5533
+ var point = slate.Editor.after(editor, inlinePath);
5534
+ slate.Transforms.setSelection(editor, {
5535
+ anchor: point,
5536
+ focus: point
5537
+ });
5538
+ }
5539
+ }
5238
5540
 
5239
- editor.deleteForward = function (unit) {
5240
- var _editor$selection;
5541
+ return insertText(text);
5542
+ }; // When pressing delete instead of backspace
5241
5543
 
5242
- var _Editor$nodes = slate.Editor.nodes(editor, {
5243
- at: (_editor$selection = editor.selection) == null ? void 0 : _editor$selection.focus.path,
5244
- match: function match(node) {
5245
- return Contentful.TEXT_CONTAINERS.includes(node.type);
5544
+
5545
+ var deleteForward = editor.deleteForward;
5546
+
5547
+ editor.deleteForward = function (unit) {
5548
+ var entry = plateCore.getAbove(editor, {
5549
+ match: {
5550
+ type: Contentful.TEXT_CONTAINERS
5246
5551
  }
5247
- }),
5248
- nodes = _Editor$nodes[0];
5552
+ });
5249
5553
 
5250
- if (nodes) {
5251
- var paragraphOrHeading = nodes[0],
5252
- path = nodes[1];
5554
+ if (entry) {
5555
+ var paragraphOrHeading = entry[0],
5556
+ path = entry[1];
5253
5557
  var isTextEmpty = plateCore.isAncestorEmpty(editor, paragraphOrHeading); // We ignore paragraphs/headings that are children of ul, ol, blockquote, tables, etc
5254
5558
 
5255
5559
  var isRootLevel = path.length === 1;
@@ -5306,8 +5610,9 @@ var transformVoid = function transformVoid(editor, _ref) {
5306
5610
  var createVoidsPlugin = function createVoidsPlugin() {
5307
5611
  return {
5308
5612
  key: 'VoidsPlugin',
5309
- exitBreak: [// Can insert before first void block
5310
- {
5613
+ exitBreak: [{
5614
+ // Inserts a new paragraph *before* a void element if it's the very first
5615
+ // node on the editor
5311
5616
  hotkey: 'enter',
5312
5617
  before: true,
5313
5618
  query: {
@@ -5317,14 +5622,17 @@ var createVoidsPlugin = function createVoidsPlugin() {
5317
5622
  return isRootLevel(path) && plateCore.isFirstChild(path) && !!node.isVoid;
5318
5623
  }
5319
5624
  }
5320
- }, // Can insert after a void block
5321
- {
5625
+ }, {
5626
+ // Inserts a new paragraph on enter when a void element is focused
5322
5627
  hotkey: 'enter',
5628
+ // exploit the internal use of Array.slice(0, level + 1) by the exitBreak plugin
5629
+ // to stay in the parent element
5630
+ level: -2,
5323
5631
  query: {
5324
5632
  filter: function filter(_ref2) {
5325
5633
  var node = _ref2[0],
5326
5634
  path = _ref2[1];
5327
- return !plateCore.isFirstChild(path) && !!node.isVoid;
5635
+ return !(isRootLevel(path) && plateCore.isFirstChild(path)) && !!node.isVoid;
5328
5636
  }
5329
5637
  }
5330
5638
  }],
@@ -5353,8 +5661,8 @@ var getPlugins = function getPlugins(sdk, tracking) {
5353
5661
  return [// AST must come after the HTML deserializer
5354
5662
  plateCore.createDeserializeHtmlPlugin(), plateCore.createDeserializeAstPlugin(), plateSerializerDocx.createDeserializeDocxPlugin(), // Global shortcuts
5355
5663
  createDragAndDropPlugin(), // Block Elements
5356
- createParagraphPlugin(), createListPlugin(), createHrPlugin(), createHeadingPlugin(), createQuotePlugin(), createTablePlugin(tracking), createEmbeddedEntryBlockPlugin(sdk), createEmbeddedAssetBlockPlugin(sdk), // Inline elements
5357
- createHyperlinkPlugin(sdk), createEmbeddedEntityInlinePlugin(sdk), // Marks
5664
+ createParagraphPlugin(), createListPlugin(), createHrPlugin(), createHeadingPlugin(), createQuotePlugin(), createTablePlugin(tracking), createEmbeddedEntryBlockPlugin(sdk, tracking), createEmbeddedAssetBlockPlugin(sdk, tracking), // Inline elements
5665
+ createHyperlinkPlugin(sdk, tracking), createEmbeddedEntityInlinePlugin(sdk, tracking), // Marks
5358
5666
  createMarksPlugin(), // Other
5359
5667
  createTrailingParagraphPlugin(), createTextPlugin(), createVoidsPlugin(), createSelectOnBackspacePlugin(), // Pasting content from other sources
5360
5668
  createPasteHTMLPlugin(), // These plugins drive their configurations from the list of plugins
@@ -5625,13 +5933,9 @@ var StickyToolbarWrapper = function StickyToolbarWrapper(_ref) {
5625
5933
  var _excluded = ["sdk", "isInitiallyDisabled", "onAction"];
5626
5934
  var ConnectedRichTextEditor = function ConnectedRichTextEditor(props) {
5627
5935
  var tracking = useTrackingContext();
5628
- var docFromAdapter = contentfulSlatejsAdapter.toSlatejsDocument({
5629
- document: props.value || Contentful.EMPTY_DOCUMENT,
5630
- schema: schema
5631
- });
5632
- var doc = sanitizeIncomingSlateDoc(docFromAdapter);
5936
+ var editor = useContentfulEditor();
5633
5937
 
5634
- var _useState = React.useState(doc),
5938
+ var _useState = React.useState([]),
5635
5939
  value = _useState[0],
5636
5940
  setValue = _useState[1];
5637
5941
 
@@ -5641,12 +5945,33 @@ var ConnectedRichTextEditor = function ConnectedRichTextEditor(props) {
5641
5945
  var plugins = React__default.useMemo(function () {
5642
5946
  return getPlugins(props.sdk, tracking);
5643
5947
  }, [props.sdk, tracking]);
5948
+ React__default.useEffect(function () {
5949
+ if (!editor) {
5950
+ return;
5951
+ }
5952
+
5953
+ var docFromAdapter = contentfulSlatejsAdapter.toSlatejsDocument({
5954
+ document: props.value || Contentful.EMPTY_DOCUMENT,
5955
+ schema: schema
5956
+ });
5957
+ var doc = sanitizeIncomingSlateDoc(docFromAdapter); // Slate throws an error if the value on the initial render is invalid
5958
+ // so we directly set the value on the editor in order
5959
+ // to be able to trigger normalization on the initial value before rendering
5960
+ // TODO: use https://plate.udecode.io/docs/Plate#normalizeinitialvalue when working
5961
+
5962
+ editor.children = doc;
5963
+ slate.Editor.normalize(editor, {
5964
+ force: true
5965
+ }); // We set the value so that the rendering can take over from here
5966
+
5967
+ setValue(editor.children);
5968
+ }, [props.value, editor]);
5644
5969
  return /*#__PURE__*/React__default.createElement("div", {
5645
5970
  className: styles$j.root,
5646
5971
  "data-test-id": "rich-text-editor"
5647
5972
  }, /*#__PURE__*/React__default.createElement(plateCore.Plate, {
5648
5973
  id: getContentfulEditorId(props.sdk),
5649
- initialValue: value,
5974
+ value: value,
5650
5975
  plugins: plugins,
5651
5976
  disableCorePlugins: disableCorePlugins,
5652
5977
  editableProps: {