@contentful/field-editor-rich-text 2.0.0-next.13 → 2.0.0-next.16

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.
Files changed (56) hide show
  1. package/dist/ContentfulEditorProvider.d.ts +6 -5
  2. package/dist/RichTextEditor.d.ts +1 -1
  3. package/dist/field-editor-rich-text.cjs.development.js +559 -396
  4. package/dist/field-editor-rich-text.cjs.development.js.map +1 -1
  5. package/dist/field-editor-rich-text.cjs.production.min.js +1 -1
  6. package/dist/field-editor-rich-text.cjs.production.min.js.map +1 -1
  7. package/dist/field-editor-rich-text.esm.js +562 -399
  8. package/dist/field-editor-rich-text.esm.js.map +1 -1
  9. package/dist/helpers/editor.d.ts +14 -17
  10. package/dist/helpers/extractNodes.d.ts +2 -3
  11. package/dist/helpers/transformers.d.ts +6 -6
  12. package/dist/plugins/EmbeddedEntityBlock/ToolbarIcon.d.ts +1 -2
  13. package/dist/plugins/EmbeddedEntityBlock/Util.d.ts +2 -1
  14. package/dist/plugins/EmbeddedEntityBlock/index.d.ts +2 -3
  15. package/dist/plugins/EmbeddedEntityInline/index.d.ts +1 -2
  16. package/dist/plugins/Hr/index.d.ts +2 -3
  17. package/dist/plugins/Hyperlink/HyperlinkModal.d.ts +3 -4
  18. package/dist/plugins/Hyperlink/index.d.ts +1 -2
  19. package/dist/plugins/Hyperlink/utils.d.ts +2 -2
  20. package/dist/plugins/List/insertListBreak.d.ts +2 -2
  21. package/dist/plugins/List/insertListFragment.d.ts +3 -2
  22. package/dist/plugins/List/transforms/insertListItem.d.ts +2 -2
  23. package/dist/plugins/List/utils.d.ts +8 -7
  24. package/dist/plugins/List/withList.d.ts +2 -1
  25. package/dist/plugins/Marks/Bold.d.ts +7 -5
  26. package/dist/plugins/Marks/Code.d.ts +7 -5
  27. package/dist/plugins/Marks/Italic.d.ts +7 -5
  28. package/dist/plugins/Marks/Underline.d.ts +7 -5
  29. package/dist/plugins/Marks/components/MarkToolbarButton.d.ts +13 -0
  30. package/dist/plugins/Marks/helpers.d.ts +4 -0
  31. package/dist/plugins/Normalizer/types.d.ts +4 -3
  32. package/dist/plugins/Normalizer/utils.d.ts +2 -2
  33. package/dist/plugins/Normalizer/withNormalizer.d.ts +2 -2
  34. package/dist/plugins/PasteHTML/createPasteHTMLPlugin.d.ts +6 -0
  35. package/dist/plugins/Quote/toggleQuote.d.ts +5 -3
  36. package/dist/plugins/Table/actions/addColumn.d.ts +3 -3
  37. package/dist/plugins/Table/actions/addRow.d.ts +3 -3
  38. package/dist/plugins/Table/actions/setHeader.d.ts +2 -2
  39. package/dist/plugins/Table/addTableTrackingEvents.d.ts +2 -3
  40. package/dist/plugins/Table/createTablePlugin.d.ts +1 -2
  41. package/dist/plugins/Table/helpers.d.ts +7 -7
  42. package/dist/plugins/Tracking/createTrackingPlugin.d.ts +10 -0
  43. package/dist/plugins/Tracking/index.d.ts +1 -0
  44. package/dist/plugins/Tracking/utils.d.ts +2 -0
  45. package/dist/plugins/TrailingParagraph/index.d.ts +2 -1
  46. package/dist/plugins/Voids/transformVoid.d.ts +2 -2
  47. package/dist/plugins/index.d.ts +2 -2
  48. package/dist/plugins/links-tracking.d.ts +1 -2
  49. package/dist/test-utils/assertOutput.d.ts +2 -2
  50. package/dist/test-utils/createEditor.d.ts +5 -6
  51. package/dist/test-utils/mockPlugin.d.ts +1 -1
  52. package/dist/test-utils/setEmptyDataAttribute.d.ts +2 -2
  53. package/dist/types.d.ts +6 -2
  54. package/dist/useOnValueChanged.d.ts +7 -0
  55. package/package.json +1 -1
  56. package/dist/TrackingProvider.d.ts +0 -11
@@ -1,18 +1,17 @@
1
- import React__default, { useMemo, createElement, useEffect, useState, memo, Fragment, useCallback } from 'react';
2
- import { toSlatejsDocument, toContentfulDocument } from '@contentful/contentful-slatejs-adapter';
1
+ import React__default, { useContext, createContext, useMemo, createElement, useEffect, useState, memo, Fragment, useCallback } from 'react';
3
2
  import { useEntities, ScheduledIconWithTooltip, MissingEntityCard, AssetThumbnail, getScheduleTooltipContent, EntityProvider } from '@contentful/field-editor-reference';
4
3
  import { entityHelpers, shortenStorageUnit, isValidImage, ModalDialogLauncher, FieldConnector } from '@contentful/field-editor-shared';
5
- import { TOP_LEVEL_BLOCKS, BLOCKS, CONTAINERS, VOID_BLOCKS, INLINES, TABLE_BLOCKS, HEADINGS, TEXT_CONTAINERS, LIST_ITEM_BLOCKS, MARKS, EMPTY_DOCUMENT } from '@contentful/rich-text-types';
6
- import { usePlateEditorRef, getNodes, getText, toggleNodeType, getAbove, onKeyDownToggleElement, setNodes, isAncestorEmpty, getParent, isSelectionAtBlockStart, isSelectionAtBlockEnd, isFirstChild, insertNodes, moveChildren, isBlockAboveEmpty, mockPlugin, getPluginType, ELEMENT_DEFAULT, findNode, someHtmlElement, isMarkActive, toggleMark, match, KEY_DESERIALIZE_HTML, someNode, getChildren as getChildren$1, getBlockAbove, getLastChildPath, createDeserializeHtmlPlugin, createDeserializeAstPlugin, createPlateEditor, Plate } from '@udecode/plate-core';
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, getText, toggleNodeType, getAbove, setNodes, isAncestorEmpty, getParent, getBlockAbove, isSelectionAtBlockStart, isSelectionAtBlockEnd, isFirstChild, insertNodes, moveChildren, isBlockAboveEmpty, mockPlugin, getPluginType, ELEMENT_DEFAULT, findNode, isMarkActive, toggleMark, someHtmlElement, match, KEY_DESERIALIZE_HTML, someNode, getChildren as getChildren$1, getLastChildPath, createDeserializeHtmlPlugin, createDeserializeAstPlugin, createPlateEditor, Plate } from '@udecode/plate-core';
7
6
  import { css, cx } from 'emotion';
8
7
  import deepEquals from 'fast-deep-equal';
9
8
  import noop from 'lodash-es/noop';
10
- import constate from 'constate';
11
9
  import { createDeserializeDocxPlugin } from '@udecode/plate-serializer-docx';
12
10
  import { createSoftBreakPlugin as createSoftBreakPlugin$1, createExitBreakPlugin as createExitBreakPlugin$1 } from '@udecode/plate-break';
13
11
  import isHotkey from 'is-hotkey';
14
- import { Text, Element, Editor, Transforms, Range, Path, Node } from 'slate';
12
+ import { Text, Element, Editor, Transforms, Range, Node, Path, Point } from 'slate';
15
13
  import { ReactEditor, useSelected, useReadOnly, useFocused } from 'slate-react';
14
+ import constate from 'constate';
16
15
  import { AssetCard, Menu, Text as Text$1, Notification, EntryCard, MenuItem, Button, Flex, Icon, InlineEntryCard, Tooltip, ModalContent, Form, FormControl, TextInput, Select, FormLabel, TextLink, ModalControls, IconButton } from '@contentful/f36-components';
17
16
  import mimetype from '@contentful/mimetype';
18
17
  import get from 'lodash-es/get';
@@ -27,7 +26,10 @@ import isPlainObject from 'is-plain-obj';
27
26
  import { createParagraphPlugin as createParagraphPlugin$1 } from '@udecode/plate-paragraph';
28
27
  import { createSelectOnBackspacePlugin as createSelectOnBackspacePlugin$1 } from '@udecode/plate-select';
29
28
  import { ELEMENT_TABLE, ELEMENT_TR, getEmptyRowNode, ELEMENT_TD, ELEMENT_TH, getEmptyCellNode, insertTable, deleteRow, deleteColumn, deleteTable, createTablePlugin as createTablePlugin$1, onKeyDownTable } from '@udecode/plate-table';
29
+ import { toContentfulDocument, toSlatejsDocument } from '@contentful/contentful-slatejs-adapter';
30
+ import { documentToPlainTextString } from '@contentful/rich-text-plain-text-renderer';
30
31
  import { createTrailingBlockPlugin } from '@udecode/plate-trailing-block';
32
+ import debounce from 'lodash-es/debounce';
31
33
  import PropTypes from 'prop-types';
32
34
 
33
35
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
@@ -237,126 +239,37 @@ function _createForOfIteratorHelperLoose(o, allowArrayLike) {
237
239
  throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
238
240
  }
239
241
 
240
- var _extends2, _extends4, _inlines;
241
- var inlines = /*#__PURE__*/Object.values(INLINES).map(function (type) {
242
- return {
243
- type: type
244
- };
245
- });
246
- var schema = {
247
- document: {
248
- nodes: [{
249
- types: /*#__PURE__*/TOP_LEVEL_BLOCKS.map(function (type) {
250
- return {
251
- type: type
252
- };
253
- })
254
- }]
255
- },
256
- blocks: /*#__PURE__*/_extends((_extends2 = {}, _extends2[BLOCKS.PARAGRAPH] = {
257
- nodes: [{
258
- match: /*#__PURE__*/[].concat(inlines, [{
259
- object: 'text'
260
- }])
261
- }]
262
- }, _extends2[BLOCKS.HEADING_1] = {
263
- nodes: [{
264
- match: /*#__PURE__*/[].concat(inlines, [{
265
- object: 'text'
266
- }])
267
- }]
268
- }, _extends2[BLOCKS.HEADING_2] = {
269
- nodes: [{
270
- match: /*#__PURE__*/[].concat(inlines, [{
271
- object: 'text'
272
- }])
273
- }]
274
- }, _extends2[BLOCKS.HEADING_3] = {
275
- nodes: [{
276
- match: /*#__PURE__*/[].concat(inlines, [{
277
- object: 'text'
278
- }])
279
- }]
280
- }, _extends2[BLOCKS.HEADING_4] = {
281
- nodes: [{
282
- match: /*#__PURE__*/[].concat(inlines, [{
283
- object: 'text'
284
- }])
285
- }]
286
- }, _extends2[BLOCKS.HEADING_5] = {
287
- nodes: [{
288
- match: /*#__PURE__*/[].concat(inlines, [{
289
- object: 'text'
290
- }])
291
- }]
292
- }, _extends2[BLOCKS.HEADING_6] = {
293
- nodes: [{
294
- match: /*#__PURE__*/[].concat(inlines, [{
295
- object: 'text'
296
- }])
297
- }]
298
- }, _extends2), /*#__PURE__*/VOID_BLOCKS.reduce(function (blocks, nodeType) {
299
- var _extends3;
300
-
301
- return _extends({}, blocks, (_extends3 = {}, _extends3[nodeType] = {
302
- isVoid: true
303
- }, _extends3));
304
- }, {}), (_extends4 = {}, _extends4[BLOCKS.QUOTE] = {
305
- nodes: [{
306
- match: [/*#__PURE__*/CONTAINERS[BLOCKS.QUOTE].map(function (type) {
307
- return {
308
- type: type
309
- };
310
- })],
311
- min: 1
312
- }],
313
- normalize: function normalize(editor, error) {
314
- if (error.code === 'child_type_invalid') {
315
- return editor.unwrapBlockByKey(error.node.key, BLOCKS.QUOTE);
316
- }
317
- }
318
- }, _extends4)),
319
- inlines: (_inlines = {}, _inlines[INLINES.HYPERLINK] = {
320
- nodes: [{
321
- match: [{
322
- object: 'text'
323
- }]
324
- }]
325
- }, _inlines[INLINES.ENTRY_HYPERLINK] = {
326
- nodes: [{
327
- match: [{
328
- object: 'text'
329
- }]
330
- }]
331
- }, _inlines[INLINES.ASSET_HYPERLINK] = {
332
- nodes: [{
333
- match: [{
334
- object: 'text'
335
- }]
336
- }]
337
- }, _inlines[INLINES.EMBEDDED_ENTRY] = {
338
- isVoid: true
339
- }, _inlines)
340
- };
341
-
342
242
  function getContentfulEditorId(sdk) {
343
243
  var entry = sdk.entry,
344
244
  field = sdk.field;
345
245
  var sys = entry.getSys();
346
246
  return "rich-text-editor-" + sys.id + "-" + field.id + "-" + field.locale;
347
247
  }
248
+ var editorContext = /*#__PURE__*/createContext('');
249
+ var ContentfulEditorIdProvider = editorContext.Provider;
250
+ function useContentfulEditorId() {
251
+ var id = useContext(editorContext);
348
252
 
349
- function useContentfulEditorHook(_ref) {
350
- var sdk = _ref.sdk;
351
- var editorId = getContentfulEditorId(sdk);
253
+ if (!id) {
254
+ throw new Error('could not find editor id. Please ensure the component is wrapped in <ContentfulEditorIdProvider> ');
255
+ }
256
+
257
+ return id;
258
+ } // This hook re-renders when the value changes
259
+ // Use case: Toolbar icons, for example
260
+
261
+ function useContentfulEditor() {
262
+ var editorId = useContentfulEditorId();
263
+ var editor = usePlateEditorState(editorId);
264
+ return editor;
265
+ } // This doesn't re-render when the value changes
266
+
267
+ function useContentfulEditorRef() {
268
+ var editorId = useContentfulEditorId();
352
269
  var editor = usePlateEditorRef(editorId);
353
270
  return editor;
354
271
  }
355
272
 
356
- var _constate = /*#__PURE__*/constate(useContentfulEditorHook),
357
- ContentfulEditorProvider = _constate[0],
358
- useContentfulEditor = _constate[1];
359
-
360
273
  var createSoftBreakPlugin = function createSoftBreakPlugin() {
361
274
  return createSoftBreakPlugin$1({
362
275
  then: function then(editor) {
@@ -619,17 +532,6 @@ function getAncestorPathFromSelection(editor) {
619
532
  return level.length === 1;
620
533
  });
621
534
  }
622
- function shouldUnwrapBlockquote(editor, type) {
623
- var isQuoteSelected = isBlockSelected(editor, BLOCKS.QUOTE);
624
- var isValidType = [].concat(HEADINGS, [BLOCKS.OL_LIST, BLOCKS.UL_LIST, BLOCKS.HR]).includes(type);
625
- return isQuoteSelected && isValidType;
626
- }
627
- function unwrapFromRoot(editor) {
628
- var ancestorPath = getAncestorPathFromSelection(editor);
629
- Transforms.unwrapNodes(editor, {
630
- at: ancestorPath
631
- });
632
- }
633
535
  var isAtEndOfTextSelection = function isAtEndOfTextSelection(editor) {
634
536
  var _editor$selection, _editor$selection2;
635
537
 
@@ -699,12 +601,14 @@ var focus = function focus(editor) {
699
601
  }
700
602
  };
701
603
 
702
- function withLinkTracking(tracking, Component) {
604
+ function withLinkTracking(Component) {
703
605
  return function ComponentWithTracking(props) {
606
+ var editor = useContentfulEditorRef();
607
+ var onEntityFetchComplete = React__default.useCallback(function () {
608
+ return editor.tracking.onViewportAction('linkRendered');
609
+ }, [editor]);
704
610
  return /*#__PURE__*/React__default.createElement(Component, Object.assign({}, props, {
705
- onEntityFetchComplete: function onEntityFetchComplete() {
706
- tracking.onViewportAction('linkRendered');
707
- }
611
+ onEntityFetchComplete: onEntityFetchComplete
708
612
  }));
709
613
  };
710
614
  }
@@ -718,9 +622,9 @@ function useSdk(_ref) {
718
622
  return sdkMemo;
719
623
  }
720
624
 
721
- var _constate$1 = /*#__PURE__*/constate(useSdk),
722
- SdkProvider = _constate$1[0],
723
- useSdkContext = _constate$1[1];
625
+ var _constate = /*#__PURE__*/constate(useSdk),
626
+ SdkProvider = _constate[0],
627
+ useSdkContext = _constate[1];
724
628
 
725
629
  var styles = {
726
630
  scheduleIcon: /*#__PURE__*/css({
@@ -1970,12 +1874,11 @@ function _selectEntityAndInsert() {
1970
1874
  config = _extends({}, baseConfig, {
1971
1875
  withCreate: true
1972
1876
  });
1973
- _context.prev = 5;
1974
1877
  selection = editor.selection;
1975
- _context.next = 9;
1878
+ _context.next = 8;
1976
1879
  return selectEntity(config);
1977
1880
 
1978
- case 9:
1881
+ case 8:
1979
1882
  entity = _context.sent;
1980
1883
 
1981
1884
  if (entity) {
@@ -1983,6 +1886,9 @@ function _selectEntityAndInsert() {
1983
1886
  break;
1984
1887
  }
1985
1888
 
1889
+ logAction('cancelCreateEmbedDialog', {
1890
+ nodeType: nodeType
1891
+ });
1986
1892
  return _context.abrupt("return");
1987
1893
 
1988
1894
  case 12:
@@ -1991,31 +1897,13 @@ function _selectEntityAndInsert() {
1991
1897
  logAction('insert', {
1992
1898
  nodeType: nodeType
1993
1899
  });
1994
- _context.next = 24;
1995
- break;
1996
-
1997
- case 17:
1998
- _context.prev = 17;
1999
- _context.t0 = _context["catch"](5);
2000
1900
 
2001
- if (!_context.t0) {
2002
- _context.next = 23;
2003
- break;
2004
- }
2005
-
2006
- throw _context.t0;
2007
-
2008
- case 23:
2009
- logAction('cancelCreateEmbedDialog', {
2010
- nodeType: nodeType
2011
- });
2012
-
2013
- case 24:
1901
+ case 15:
2014
1902
  case "end":
2015
1903
  return _context.stop();
2016
1904
  }
2017
1905
  }
2018
- }, _callee, null, [[5, 17]]);
1906
+ }, _callee);
2019
1907
  }));
2020
1908
  return _selectEntityAndInsert.apply(this, arguments);
2021
1909
  }
@@ -2062,7 +1950,6 @@ var styles$4 = {
2062
1950
  function EmbeddedEntityBlockToolbarIcon(_ref) {
2063
1951
  var isButton = _ref.isButton,
2064
1952
  isDisabled = _ref.isDisabled,
2065
- logAction = _ref.logAction,
2066
1953
  nodeType = _ref.nodeType,
2067
1954
  onClose = _ref.onClose;
2068
1955
  var editor = useContentfulEditor();
@@ -2071,7 +1958,7 @@ function EmbeddedEntityBlockToolbarIcon(_ref) {
2071
1958
  var handleClick = function handleClick(event) {
2072
1959
  event.preventDefault();
2073
1960
  onClose();
2074
- selectEntityAndInsert(nodeType, sdk, editor, logAction || noop);
1961
+ selectEntityAndInsert(nodeType, sdk, editor, editor.tracking.onToolbarAction);
2075
1962
  };
2076
1963
 
2077
1964
  var type = getEntityTypeFromNodeType(nodeType);
@@ -2138,20 +2025,20 @@ function getWithEmbeddedEntityEvents(nodeType, sdk) {
2138
2025
  }
2139
2026
 
2140
2027
  if (hotkey && isHotkey(hotkey, event)) {
2141
- selectEntityAndInsert(nodeType, sdk, editor, noop);
2028
+ selectEntityAndInsert(nodeType, sdk, editor, editor.tracking.onShortcutAction);
2142
2029
  }
2143
2030
  };
2144
2031
  };
2145
2032
  }
2146
2033
 
2147
2034
  var createEmbeddedEntityPlugin = function createEmbeddedEntityPlugin(nodeType, hotkey) {
2148
- return function (sdk, tracking) {
2035
+ return function (sdk) {
2149
2036
  return {
2150
2037
  key: nodeType,
2151
2038
  type: nodeType,
2152
2039
  isElement: true,
2153
2040
  isVoid: true,
2154
- component: withLinkTracking(tracking, LinkedEntityBlock),
2041
+ component: withLinkTracking(LinkedEntityBlock),
2155
2042
  options: {
2156
2043
  hotkey: hotkey
2157
2044
  },
@@ -2369,44 +2256,53 @@ function EmbeddedEntityInline(props) {
2369
2256
  })), props.children);
2370
2257
  }
2371
2258
 
2372
- function selectEntityAndInsert$1(_x, _x2) {
2259
+ function selectEntityAndInsert$1(_x, _x2, _x3) {
2373
2260
  return _selectEntityAndInsert$1.apply(this, arguments);
2374
2261
  }
2375
2262
 
2376
2263
  function _selectEntityAndInsert$1() {
2377
- _selectEntityAndInsert$1 = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(editor, sdk) {
2264
+ _selectEntityAndInsert$1 = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(editor, sdk, logAction) {
2378
2265
  var config, selection, entry, inlineEntryNode;
2379
2266
  return runtime_1.wrap(function _callee2$(_context2) {
2380
2267
  while (1) {
2381
2268
  switch (_context2.prev = _context2.next) {
2382
2269
  case 0:
2270
+ logAction('openCreateEmbedDialog', {
2271
+ nodeType: INLINES.EMBEDDED_ENTRY
2272
+ });
2383
2273
  config = _extends({}, newEntitySelectorConfigFromRichTextField(sdk.field, INLINES.EMBEDDED_ENTRY), {
2384
2274
  withCreate: true
2385
2275
  });
2386
2276
  selection = editor.selection;
2387
- _context2.next = 4;
2277
+ _context2.next = 5;
2388
2278
  return sdk.dialogs.selectSingleEntry(config);
2389
2279
 
2390
- case 4:
2280
+ case 5:
2391
2281
  entry = _context2.sent;
2392
2282
  focus(editor); // Dialog steals focus from editor, return it.
2393
2283
 
2394
2284
  if (entry) {
2395
- _context2.next = 8;
2285
+ _context2.next = 10;
2396
2286
  break;
2397
2287
  }
2398
2288
 
2289
+ logAction('cancelCreateEmbedDialog', {
2290
+ nodeType: INLINES.EMBEDDED_ENTRY
2291
+ });
2399
2292
  return _context2.abrupt("return");
2400
2293
 
2401
- case 8:
2294
+ case 10:
2402
2295
  inlineEntryNode = createInlineEntryNode(entry.sys.id); // Got to wait until focus is really back on the editor or setSelection() won't work.
2403
2296
 
2404
2297
  setTimeout(function () {
2405
2298
  Transforms.setSelection(editor, selection);
2406
2299
  Transforms.insertNodes(editor, inlineEntryNode);
2407
2300
  }, 0);
2301
+ logAction('insert', {
2302
+ nodeType: INLINES.EMBEDDED_ENTRY
2303
+ });
2408
2304
 
2409
- case 10:
2305
+ case 13:
2410
2306
  case "end":
2411
2307
  return _context2.stop();
2412
2308
  }
@@ -2420,7 +2316,7 @@ function ToolbarEmbeddedEntityInlineButton(props) {
2420
2316
  var editor = useContentfulEditor();
2421
2317
  var sdk = useSdkContext();
2422
2318
 
2423
- function handleClick(_x3) {
2319
+ function handleClick(_x4) {
2424
2320
  return _handleClick.apply(this, arguments);
2425
2321
  }
2426
2322
 
@@ -2442,7 +2338,7 @@ function ToolbarEmbeddedEntityInlineButton(props) {
2442
2338
  case 3:
2443
2339
  props.onClose();
2444
2340
  _context.next = 6;
2445
- return selectEntityAndInsert$1(editor, sdk);
2341
+ return selectEntityAndInsert$1(editor, sdk, editor.tracking.onToolbarAction);
2446
2342
 
2447
2343
  case 6:
2448
2344
  case "end":
@@ -2475,7 +2371,7 @@ function ToolbarEmbeddedEntityInlineButton(props) {
2475
2371
  className: "rich-text__embedded-entry-list-icon " + styles$6.icon
2476
2372
  }), /*#__PURE__*/createElement("span", null, "Inline entry")));
2477
2373
  }
2478
- function createEmbeddedEntityInlinePlugin(sdk, tracking) {
2374
+ function createEmbeddedEntityInlinePlugin(sdk) {
2479
2375
  var htmlAttributeName = 'data-embedded-entity-inline-id';
2480
2376
  return {
2481
2377
  key: INLINES.EMBEDDED_ENTRY,
@@ -2483,7 +2379,7 @@ function createEmbeddedEntityInlinePlugin(sdk, tracking) {
2483
2379
  isElement: true,
2484
2380
  isInline: true,
2485
2381
  isVoid: true,
2486
- component: withLinkTracking(tracking, EmbeddedEntityInline),
2382
+ component: withLinkTracking(EmbeddedEntityInline),
2487
2383
  options: {
2488
2384
  hotkey: 'mod+shift+2'
2489
2385
  },
@@ -2509,7 +2405,7 @@ function getWithEmbeddedEntryInlineEvents(sdk) {
2509
2405
  if (!editor) return;
2510
2406
 
2511
2407
  if (hotkey && isHotkey(hotkey, event)) {
2512
- selectEntityAndInsert$1(editor, sdk);
2408
+ selectEntityAndInsert$1(editor, sdk, editor.tracking.onShortcutAction);
2513
2409
  }
2514
2410
  };
2515
2411
  };
@@ -2592,11 +2488,6 @@ function ToolbarHeadingButton(props) {
2592
2488
  if (!(editor != null && editor.selection)) return;
2593
2489
  setSelected(type);
2594
2490
  setOpen(false);
2595
-
2596
- if (shouldUnwrapBlockquote(editor, type)) {
2597
- unwrapFromRoot(editor);
2598
- }
2599
-
2600
2491
  var prevOnChange = editor.onChange;
2601
2492
  /*
2602
2493
  The focus might happen at point in time when
@@ -2612,6 +2503,10 @@ function ToolbarHeadingButton(props) {
2612
2503
  prevOnChange.apply(void 0, arguments);
2613
2504
  };
2614
2505
 
2506
+ var isActive = isBlockSelected(editor, type);
2507
+ editor.tracking.onToolbarAction(isActive ? 'remove' : 'insert', {
2508
+ nodeType: type
2509
+ });
2615
2510
  toggleNodeType(editor, {
2616
2511
  activeType: type,
2617
2512
  inactiveType: type
@@ -2733,6 +2628,24 @@ function createHeading(Tag, block) {
2733
2628
 
2734
2629
  var HeadingComponents = (_HeadingComponents = {}, _HeadingComponents[BLOCKS.HEADING_1] = /*#__PURE__*/memo( /*#__PURE__*/createHeading('h1', BLOCKS.HEADING_1)), _HeadingComponents[BLOCKS.HEADING_2] = /*#__PURE__*/memo( /*#__PURE__*/createHeading('h2', BLOCKS.HEADING_2)), _HeadingComponents[BLOCKS.HEADING_3] = /*#__PURE__*/memo( /*#__PURE__*/createHeading('h3', BLOCKS.HEADING_3)), _HeadingComponents[BLOCKS.HEADING_4] = /*#__PURE__*/memo( /*#__PURE__*/createHeading('h4', BLOCKS.HEADING_4)), _HeadingComponents[BLOCKS.HEADING_5] = /*#__PURE__*/memo( /*#__PURE__*/createHeading('h5', BLOCKS.HEADING_5)), _HeadingComponents[BLOCKS.HEADING_6] = /*#__PURE__*/memo( /*#__PURE__*/createHeading('h6', BLOCKS.HEADING_6)), _HeadingComponents);
2735
2630
 
2631
+ var buildHeadingEventHandler = function buildHeadingEventHandler(type) {
2632
+ return function (editor, _ref) {
2633
+ var hotkey = _ref.options.hotkey;
2634
+ return function (event) {
2635
+ if (editor.selection && hotkey && isHotkey(hotkey, event)) {
2636
+ var isActive = isBlockSelected(editor, type);
2637
+ editor.tracking.onShortcutAction(isActive ? 'remove' : 'insert', {
2638
+ nodeType: type
2639
+ });
2640
+ toggleNodeType(editor, {
2641
+ activeType: type,
2642
+ inactiveType: BLOCKS.PARAGRAPH
2643
+ });
2644
+ }
2645
+ };
2646
+ };
2647
+ };
2648
+
2736
2649
  var createHeadingPlugin = function createHeadingPlugin() {
2737
2650
  var _transform;
2738
2651
 
@@ -2749,8 +2662,8 @@ var createHeadingPlugin = function createHeadingPlugin() {
2749
2662
  match: {
2750
2663
  type: HEADINGS
2751
2664
  },
2752
- validChildren: function validChildren(_, _ref) {
2753
- var node = _ref[0];
2665
+ validChildren: function validChildren(_, _ref2) {
2666
+ var node = _ref2[0];
2754
2667
  return isInlineOrText(node);
2755
2668
  },
2756
2669
  transform: (_transform = {}, _transform[BLOCKS.PARAGRAPH] = transformUnwrap, _transform["default"] = transformLift, _transform)
@@ -2767,8 +2680,8 @@ var createHeadingPlugin = function createHeadingPlugin() {
2767
2680
  start: true,
2768
2681
  // Exclude headings inside lists as it interferes with the list's
2769
2682
  // insertBreak implementation
2770
- filter: function filter(_ref2) {
2771
- var path = _ref2[1];
2683
+ filter: function filter(_ref3) {
2684
+ var path = _ref3[1];
2772
2685
  return !getAbove(editor, {
2773
2686
  at: path,
2774
2687
  match: {
@@ -2792,7 +2705,7 @@ var createHeadingPlugin = function createHeadingPlugin() {
2792
2705
  hotkey: ["mod+alt+" + level]
2793
2706
  },
2794
2707
  handlers: {
2795
- onKeyDown: onKeyDownToggleElement
2708
+ onKeyDown: buildHeadingEventHandler(nodeType)
2796
2709
  },
2797
2710
  deserializeHtml: {
2798
2711
  rules: [{
@@ -2864,10 +2777,6 @@ function withHrEvents(editor) {
2864
2777
  pathToSelectedHr = _getNodeEntryFromSele[1];
2865
2778
 
2866
2779
  if (pathToSelectedHr) {
2867
- if (shouldUnwrapBlockquote(editor, BLOCKS.HR)) {
2868
- unwrapFromRoot(editor);
2869
- }
2870
-
2871
2780
  var isBackspace = event.key === 'Backspace';
2872
2781
  var isDelete = event.key === 'Delete';
2873
2782
 
@@ -2885,11 +2794,6 @@ function ToolbarHrButton(props) {
2885
2794
 
2886
2795
  function handleOnClick() {
2887
2796
  if (!(editor != null && editor.selection)) return;
2888
-
2889
- if (shouldUnwrapBlockquote(editor, BLOCKS.HR)) {
2890
- unwrapFromRoot(editor);
2891
- }
2892
-
2893
2797
  var hr = {
2894
2798
  type: BLOCKS.HR,
2895
2799
  data: {},
@@ -3322,13 +3226,15 @@ function HyperlinkModal(props) {
3322
3226
  testId: "confirm-cta"
3323
3227
  }, props.linkType ? 'Update' : 'Insert'))));
3324
3228
  }
3325
- function addOrEditLink(_x, _x2) {
3229
+ function addOrEditLink(_x, _x2, _x3) {
3326
3230
  return _addOrEditLink.apply(this, arguments);
3327
3231
  }
3328
3232
 
3329
3233
  function _addOrEditLink() {
3330
- _addOrEditLink = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee3(editor, sdk) {
3331
- var linkType, linkText, linkTarget, linkEntity, _getNodeEntryFromSele, node, path, selectionBeforeBlur, currentLinkText, data, text, url, type, target;
3234
+ _addOrEditLink = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee3(editor, sdk, logAction) {
3235
+ var _target$sys$linkType;
3236
+
3237
+ var linkType, linkText, linkTarget, linkEntity, _getNodeEntryFromSele, node, path, selectionBeforeBlur, currentLinkText, isEditing, data, text, url, type, target;
3332
3238
 
3333
3239
  return runtime_1.wrap(function _callee3$(_context3) {
3334
3240
  while (1) {
@@ -3353,9 +3259,11 @@ function _addOrEditLink() {
3353
3259
 
3354
3260
  selectionBeforeBlur = _extends({}, editor.selection);
3355
3261
  currentLinkText = linkText || Editor.string(editor, editor.selection);
3356
- _context3.next = 8;
3262
+ isEditing = Boolean(node && path);
3263
+ logAction(isEditing ? 'openEditHyperlinkDialog' : 'openCreateHyperlinkDialog');
3264
+ _context3.next = 10;
3357
3265
  return ModalDialogLauncher.openDialog({
3358
- title: linkType ? 'Edit hyperlink' : 'Insert hyperlink',
3266
+ title: isEditing ? 'Edit hyperlink' : 'Insert hyperlink',
3359
3267
  width: 'large',
3360
3268
  shouldCloseOnEscapePress: true,
3361
3269
  shouldCloseOnOverlayClick: true,
@@ -3372,17 +3280,18 @@ function _addOrEditLink() {
3372
3280
  });
3373
3281
  });
3374
3282
 
3375
- case 8:
3283
+ case 10:
3376
3284
  data = _context3.sent;
3377
3285
 
3378
3286
  if (data) {
3379
- _context3.next = 11;
3287
+ _context3.next = 14;
3380
3288
  break;
3381
3289
  }
3382
3290
 
3291
+ logAction(isEditing ? 'cancelEditHyperlinkDialog' : 'cancelCreateHyperlinkDialog');
3383
3292
  return _context3.abrupt("return");
3384
3293
 
3385
- case 11:
3294
+ case 14:
3386
3295
  text = data.linkText, url = data.linkTarget, type = data.linkType, target = data.linkEntity;
3387
3296
  Transforms.select(editor, selectionBeforeBlur);
3388
3297
  Editor.withoutNormalizing(editor, function () {
@@ -3394,9 +3303,13 @@ function _addOrEditLink() {
3394
3303
  path: path
3395
3304
  });
3396
3305
  });
3306
+ logAction(isEditing ? 'edit' : 'insert', {
3307
+ nodeType: type,
3308
+ linkType: (_target$sys$linkType = target == null ? void 0 : target.sys.linkType) != null ? _target$sys$linkType : 'uri'
3309
+ });
3397
3310
  focus(editor);
3398
3311
 
3399
- case 15:
3312
+ case 19:
3400
3313
  case "end":
3401
3314
  return _context3.stop();
3402
3315
  }
@@ -3460,7 +3373,7 @@ function UrlHyperlink(props) {
3460
3373
  event.preventDefault();
3461
3374
  event.stopPropagation();
3462
3375
  if (!editor) return;
3463
- addOrEditLink(editor, sdk);
3376
+ addOrEditLink(editor, sdk, editor.tracking.onViewportAction);
3464
3377
  }
3465
3378
 
3466
3379
  return /*#__PURE__*/createElement(Tooltip, {
@@ -3496,7 +3409,7 @@ function EntityHyperlink(props) {
3496
3409
  event.preventDefault();
3497
3410
  event.stopPropagation();
3498
3411
  if (!editor) return;
3499
- addOrEditLink(editor, sdk);
3412
+ addOrEditLink(editor, sdk, editor.tracking.onViewportAction);
3500
3413
  }
3501
3414
 
3502
3415
  return /*#__PURE__*/createElement(Tooltip, {
@@ -3543,8 +3456,9 @@ function ToolbarHyperlinkButton(props) {
3543
3456
  case 2:
3544
3457
  if (isActive) {
3545
3458
  unwrapLink(editor);
3459
+ editor.tracking.onToolbarAction('unlinkHyperlinks');
3546
3460
  } else {
3547
- addOrEditLink(editor, sdk);
3461
+ addOrEditLink(editor, sdk, editor.tracking.onToolbarAction);
3548
3462
  }
3549
3463
 
3550
3464
  case 3:
@@ -3593,8 +3507,9 @@ var buildHyperlinkEventHandler = function buildHyperlinkEventHandler(sdk) {
3593
3507
 
3594
3508
  if (isLinkActive(editor)) {
3595
3509
  unwrapLink(editor);
3510
+ editor.tracking.onShortcutAction('unlinkHyperlinks');
3596
3511
  } else {
3597
- addOrEditLink(editor, sdk);
3512
+ addOrEditLink(editor, sdk, editor.tracking.onShortcutAction);
3598
3513
  }
3599
3514
  };
3600
3515
  };
@@ -3620,7 +3535,7 @@ var getNodeOfType = function getNodeOfType(type) {
3620
3535
  };
3621
3536
  };
3622
3537
 
3623
- var createHyperlinkPlugin = function createHyperlinkPlugin(sdk, tracking) {
3538
+ var createHyperlinkPlugin = function createHyperlinkPlugin(sdk) {
3624
3539
  var common = {
3625
3540
  isElement: true,
3626
3541
  isInline: true
@@ -3651,7 +3566,7 @@ var createHyperlinkPlugin = function createHyperlinkPlugin(sdk, tracking) {
3651
3566
  _extends({}, common, {
3652
3567
  key: INLINES.ENTRY_HYPERLINK,
3653
3568
  type: INLINES.ENTRY_HYPERLINK,
3654
- component: withLinkTracking(tracking, EntityHyperlink),
3569
+ component: withLinkTracking(EntityHyperlink),
3655
3570
  deserializeHtml: {
3656
3571
  rules: [{
3657
3572
  validNodeName: ['A']
@@ -3665,7 +3580,7 @@ var createHyperlinkPlugin = function createHyperlinkPlugin(sdk, tracking) {
3665
3580
  _extends({}, common, {
3666
3581
  key: INLINES.ASSET_HYPERLINK,
3667
3582
  type: INLINES.ASSET_HYPERLINK,
3668
- component: withLinkTracking(tracking, EntityHyperlink),
3583
+ component: withLinkTracking(EntityHyperlink),
3669
3584
  deserializeHtml: {
3670
3585
  rules: [{
3671
3586
  validNodeName: ['A']
@@ -3788,6 +3703,16 @@ var replaceNodeWithListItems = function replaceNodeWithListItems(editor, entry)
3788
3703
  at: path
3789
3704
  });
3790
3705
  };
3706
+ var isListTypeActive = function isListTypeActive(editor, type) {
3707
+ // Lists can be nested. Here, we take the list type at the lowest level
3708
+ var listNode = getBlockAbove(editor, {
3709
+ match: {
3710
+ type: [BLOCKS.OL_LIST, BLOCKS.UL_LIST]
3711
+ },
3712
+ mode: 'lowest'
3713
+ });
3714
+ return (listNode == null ? void 0 : listNode[0].type) === type;
3715
+ };
3791
3716
 
3792
3717
  /**
3793
3718
  * Build a new list item node while preserving marks
@@ -4139,6 +4064,7 @@ var createListPlugin = function createListPlugin() {
4139
4064
  }, _overrideByKey[ELEMENT_LI] = {
4140
4065
  type: BLOCKS.LIST_ITEM,
4141
4066
  component: ListItem,
4067
+ // @ts-expect-error
4142
4068
  normalizer: [{
4143
4069
  validNode: hasListAsDirectParent,
4144
4070
  transform: normalizeOrphanedListItem
@@ -4163,11 +4089,6 @@ function ToolbarListButton(props) {
4163
4089
  function handleClick(type) {
4164
4090
  return function () {
4165
4091
  if (!(editor != null && editor.selection)) return;
4166
-
4167
- if (shouldUnwrapBlockquote(editor, type)) {
4168
- unwrapFromRoot(editor);
4169
- }
4170
-
4171
4092
  toggleList(editor, {
4172
4093
  type: type
4173
4094
  });
@@ -4180,37 +4101,73 @@ function ToolbarListButton(props) {
4180
4101
  title: "UL",
4181
4102
  testId: "ul-toolbar-button",
4182
4103
  onClick: handleClick(BLOCKS.UL_LIST),
4183
- isActive: isBlockSelected(editor, BLOCKS.UL_LIST),
4104
+ isActive: isListTypeActive(editor, BLOCKS.UL_LIST),
4184
4105
  isDisabled: props.isDisabled
4185
4106
  }, /*#__PURE__*/createElement(ListBulletedIcon, null)), isNodeTypeEnabled(sdk.field, BLOCKS.OL_LIST) && /*#__PURE__*/createElement(ToolbarButton, {
4186
4107
  title: "OL",
4187
4108
  testId: "ol-toolbar-button",
4188
4109
  onClick: handleClick(BLOCKS.OL_LIST),
4189
- isActive: isBlockSelected(editor, BLOCKS.OL_LIST),
4110
+ isActive: isListTypeActive(editor, BLOCKS.OL_LIST),
4190
4111
  isDisabled: props.isDisabled
4191
4112
  }, /*#__PURE__*/createElement(ListNumberedIcon, null)));
4192
4113
  }
4193
4114
 
4194
- function ToolbarBoldButton(props) {
4195
- var editor = useContentfulEditor();
4115
+ var createMarkToolbarButton = function createMarkToolbarButton(_ref) {
4116
+ var mark = _ref.mark,
4117
+ title = _ref.title,
4118
+ icon = _ref.icon;
4196
4119
 
4197
- function handleClick() {
4198
- if (!(editor != null && editor.selection)) return;
4199
- toggleMark(editor, {
4200
- key: MARKS.BOLD
4201
- });
4202
- focus(editor);
4203
- }
4120
+ var Mark = function Mark(_ref2) {
4121
+ var isDisabled = _ref2.isDisabled;
4122
+ var editor = useContentfulEditor();
4123
+ var handleClick = useCallback(function () {
4124
+ if (!(editor != null && editor.selection)) return;
4125
+ var isActive = isMarkActive(editor, mark);
4126
+ editor.tracking.onToolbarAction(isActive ? 'unmark' : 'mark', {
4127
+ markType: mark
4128
+ });
4129
+ toggleMark(editor, {
4130
+ key: mark
4131
+ });
4132
+ focus(editor);
4133
+ }, [editor]);
4134
+ if (!editor) return null;
4135
+ return /*#__PURE__*/createElement(ToolbarButton, {
4136
+ title: title,
4137
+ testId: mark + "-toolbar-button",
4138
+ onClick: handleClick,
4139
+ isActive: isMarkActive(editor, mark),
4140
+ isDisabled: isDisabled
4141
+ }, icon);
4142
+ };
4204
4143
 
4205
- if (!editor) return null;
4206
- return /*#__PURE__*/createElement(ToolbarButton, {
4207
- title: "Bold",
4208
- testId: "bold-toolbar-button",
4209
- onClick: handleClick,
4210
- isActive: isMarkActive(editor, MARKS.BOLD),
4211
- isDisabled: props.isDisabled
4212
- }, /*#__PURE__*/createElement(FormatBoldIcon, null));
4213
- }
4144
+ Mark.displayName = mark;
4145
+ return Mark;
4146
+ };
4147
+
4148
+ var buildMarkEventHandler = function buildMarkEventHandler(type) {
4149
+ return function (editor, _ref) {
4150
+ var hotkey = _ref.options.hotkey;
4151
+ return function (event) {
4152
+ if (editor.selection && hotkey && isHotkey(hotkey, event)) {
4153
+ event.preventDefault();
4154
+ var isActive = isMarkActive(editor, type);
4155
+ editor.tracking.onShortcutAction(isActive ? 'unmark' : 'mark', {
4156
+ markType: type
4157
+ });
4158
+ toggleMark(editor, {
4159
+ key: type
4160
+ });
4161
+ }
4162
+ };
4163
+ };
4164
+ };
4165
+
4166
+ var ToolbarBoldButton = /*#__PURE__*/createMarkToolbarButton({
4167
+ title: 'Bold',
4168
+ mark: MARKS.BOLD,
4169
+ icon: /*#__PURE__*/createElement(FormatBoldIcon, null)
4170
+ });
4214
4171
  var styles$e = {
4215
4172
  bold: /*#__PURE__*/css({
4216
4173
  fontWeight: 600
@@ -4233,6 +4190,9 @@ var createBoldPlugin = function createBoldPlugin() {
4233
4190
  options: {
4234
4191
  hotkey: ['mod+b']
4235
4192
  },
4193
+ handlers: {
4194
+ onKeyDown: buildMarkEventHandler(MARKS.BOLD)
4195
+ },
4236
4196
  deserializeHtml: {
4237
4197
  rules: [{
4238
4198
  validNodeName: ['STRONG', 'B']
@@ -4250,26 +4210,11 @@ var createBoldPlugin = function createBoldPlugin() {
4250
4210
  });
4251
4211
  };
4252
4212
 
4253
- function ToolbarCodeButton(props) {
4254
- var editor = useContentfulEditor();
4255
-
4256
- function handleClick() {
4257
- if (!(editor != null && editor.selection)) return;
4258
- toggleMark(editor, {
4259
- key: MARKS.CODE
4260
- });
4261
- focus(editor);
4262
- }
4263
-
4264
- if (!editor) return null;
4265
- return /*#__PURE__*/createElement(ToolbarButton, {
4266
- title: "Code",
4267
- testId: "code-toolbar-button",
4268
- onClick: handleClick,
4269
- isActive: isMarkActive(editor, MARKS.CODE),
4270
- isDisabled: props.isDisabled
4271
- }, /*#__PURE__*/createElement(CodeIcon, null));
4272
- }
4213
+ var ToolbarCodeButton = /*#__PURE__*/createMarkToolbarButton({
4214
+ title: 'Code',
4215
+ mark: MARKS.CODE,
4216
+ icon: /*#__PURE__*/createElement(CodeIcon, null)
4217
+ });
4273
4218
  var styles$f = {
4274
4219
  code: /*#__PURE__*/css({
4275
4220
  fontFamily: 'monospace',
@@ -4288,6 +4233,9 @@ var createCodePlugin = function createCodePlugin() {
4288
4233
  options: {
4289
4234
  hotkey: ['mod+/']
4290
4235
  },
4236
+ handlers: {
4237
+ onKeyDown: buildMarkEventHandler(MARKS.CODE)
4238
+ },
4291
4239
  deserializeHtml: {
4292
4240
  rules: [{
4293
4241
  validNodeName: ['CODE', 'PRE']
@@ -4300,26 +4248,11 @@ var createCodePlugin = function createCodePlugin() {
4300
4248
  });
4301
4249
  };
4302
4250
 
4303
- function ToolbarItalicButton(props) {
4304
- var editor = useContentfulEditor();
4305
-
4306
- function handleClick() {
4307
- if (!(editor != null && editor.selection)) return;
4308
- toggleMark(editor, {
4309
- key: MARKS.ITALIC
4310
- });
4311
- focus(editor);
4312
- }
4313
-
4314
- if (!editor) return null;
4315
- return /*#__PURE__*/createElement(ToolbarButton, {
4316
- title: "Italic",
4317
- testId: "italic-toolbar-button",
4318
- onClick: handleClick,
4319
- isActive: isMarkActive(editor, MARKS.ITALIC),
4320
- isDisabled: props.isDisabled
4321
- }, /*#__PURE__*/createElement(FormatItalicIcon, null));
4322
- }
4251
+ var ToolbarItalicButton = /*#__PURE__*/createMarkToolbarButton({
4252
+ title: 'Italic',
4253
+ mark: MARKS.ITALIC,
4254
+ icon: /*#__PURE__*/createElement(FormatItalicIcon, null)
4255
+ });
4323
4256
  var styles$g = {
4324
4257
  italic: /*#__PURE__*/css({
4325
4258
  fontStyle: 'italic'
@@ -4337,6 +4270,9 @@ var createItalicPlugin = function createItalicPlugin() {
4337
4270
  options: {
4338
4271
  hotkey: ['mod+i']
4339
4272
  },
4273
+ handlers: {
4274
+ onKeyDown: buildMarkEventHandler(MARKS.ITALIC)
4275
+ },
4340
4276
  deserializeHtml: {
4341
4277
  rules: [{
4342
4278
  validNodeName: ['I', 'EM']
@@ -4354,26 +4290,11 @@ var createItalicPlugin = function createItalicPlugin() {
4354
4290
  });
4355
4291
  };
4356
4292
 
4357
- function ToolbarUnderlineButton(props) {
4358
- var editor = useContentfulEditor();
4359
-
4360
- function handleClick() {
4361
- if (!(editor != null && editor.selection)) return;
4362
- toggleMark(editor, {
4363
- key: MARKS.UNDERLINE
4364
- });
4365
- focus(editor);
4366
- }
4367
-
4368
- if (!editor) return null;
4369
- return /*#__PURE__*/createElement(ToolbarButton, {
4370
- title: "Underline",
4371
- testId: "underline-toolbar-button",
4372
- onClick: handleClick,
4373
- isActive: isMarkActive(editor, MARKS.UNDERLINE),
4374
- isDisabled: props.isDisabled
4375
- }, /*#__PURE__*/createElement(FormatUnderlinedIcon, null));
4376
- }
4293
+ var ToolbarUnderlineButton = /*#__PURE__*/createMarkToolbarButton({
4294
+ title: 'Underline',
4295
+ mark: MARKS.UNDERLINE,
4296
+ icon: /*#__PURE__*/createElement(FormatUnderlinedIcon, null)
4297
+ });
4377
4298
  function Underline(props) {
4378
4299
  return /*#__PURE__*/createElement("u", Object.assign({}, props.attributes), props.children);
4379
4300
  }
@@ -4384,6 +4305,9 @@ var createUnderlinePlugin = function createUnderlinePlugin() {
4384
4305
  options: {
4385
4306
  hotkey: ['mod+u']
4386
4307
  },
4308
+ handlers: {
4309
+ onKeyDown: buildMarkEventHandler(MARKS.UNDERLINE)
4310
+ },
4387
4311
  deserializeHtml: {
4388
4312
  rules: [{
4389
4313
  validNodeName: ['U']
@@ -4606,6 +4530,7 @@ var withNormalizer = function withNormalizer(editor) {
4606
4530
  var createNormalizerPlugin = function createNormalizerPlugin() {
4607
4531
  return {
4608
4532
  key: 'NormalizerPlugin',
4533
+ // @ts-expect-error
4609
4534
  withOverrides: withNormalizer
4610
4535
  };
4611
4536
  };
@@ -4749,11 +4674,54 @@ var sanitizeHTML = function sanitizeHTML(html) {
4749
4674
  return doc.body.innerHTML.replace(/>\s+</g, '><');
4750
4675
  };
4751
4676
 
4677
+ /**
4678
+ * Get x-slate-fragment attribute from data-slate-fragment
4679
+ */
4680
+
4681
+ var catchSlateFragment = /data-slate-fragment="(.+?)"/m;
4682
+ var getSlateFragmentAttribute = function getSlateFragmentAttribute(dataTransfer) {
4683
+ var htmlData = dataTransfer.getData('text/html');
4684
+
4685
+ var _ref = htmlData.match(catchSlateFragment) || [],
4686
+ fragment = _ref[1];
4687
+
4688
+ return fragment;
4689
+ };
4690
+ /**
4691
+ * Get the x-slate-fragment attribute that exist in text/html data
4692
+ * and append it to the DataTransfer object
4693
+ */
4694
+
4695
+ var ensureXSlateFragment = function ensureXSlateFragment(dataTransfer) {
4696
+ if (!dataTransfer.getData('application/x-slate-fragment')) {
4697
+ var fragment = getSlateFragmentAttribute(dataTransfer);
4698
+
4699
+ if (fragment) {
4700
+ var clipboardData = new DataTransfer();
4701
+ dataTransfer.types.forEach(function (type) {
4702
+ clipboardData.setData(type, dataTransfer.getData(type));
4703
+ });
4704
+ clipboardData.setData('application/x-slate-fragment', fragment);
4705
+ return clipboardData;
4706
+ }
4707
+ }
4708
+
4709
+ return dataTransfer;
4710
+ };
4752
4711
  var createPasteHTMLPlugin = function createPasteHTMLPlugin() {
4753
4712
  var _pluginsByKey;
4754
4713
 
4755
4714
  return {
4756
4715
  key: 'PasteHTMLPlugin',
4716
+ withOverrides: function withOverrides(editor) {
4717
+ var insertData = editor.insertData;
4718
+
4719
+ editor.insertData = function (data) {
4720
+ return insertData(ensureXSlateFragment(data));
4721
+ };
4722
+
4723
+ return editor;
4724
+ },
4757
4725
  inject: {
4758
4726
  pluginsByKey: (_pluginsByKey = {}, _pluginsByKey[KEY_DESERIALIZE_HTML] = {
4759
4727
  editor: {
@@ -4772,10 +4740,7 @@ var style$1 = /*#__PURE__*/css({
4772
4740
  margin: '0 0 1.3125rem',
4773
4741
  borderLeft: "6px solid " + tokens.gray200,
4774
4742
  paddingLeft: '0.875rem',
4775
- fontStyle: 'normal',
4776
- '& a': {
4777
- color: 'inherit'
4778
- }
4743
+ fontStyle: 'normal'
4779
4744
  });
4780
4745
  function Quote(props) {
4781
4746
  return /*#__PURE__*/createElement("blockquote", Object.assign({}, props.attributes, {
@@ -4783,9 +4748,12 @@ function Quote(props) {
4783
4748
  }), props.children);
4784
4749
  }
4785
4750
 
4786
- function toggleQuote(editor) {
4751
+ function toggleQuote(editor, logAction) {
4787
4752
  if (!editor.selection) return;
4788
4753
  var isActive = isBlockSelected(editor, BLOCKS.QUOTE);
4754
+ logAction(isActive ? 'remove' : 'insert', {
4755
+ nodeType: BLOCKS.QUOTE
4756
+ });
4789
4757
  Editor.withoutNormalizing(editor, function () {
4790
4758
  if (!editor.selection) return;
4791
4759
  Transforms.unwrapNodes(editor, {
@@ -4817,7 +4785,7 @@ var onKeyDownToggleQuote = function onKeyDownToggleQuote(editor, plugin) {
4817
4785
 
4818
4786
  if (hotkey && isHotkey(hotkey, event)) {
4819
4787
  event.preventDefault();
4820
- toggleQuote(editor);
4788
+ toggleQuote(editor, editor.tracking.onShortcutAction);
4821
4789
  }
4822
4790
  };
4823
4791
  };
@@ -4843,8 +4811,55 @@ function createQuotePlugin() {
4843
4811
  },
4844
4812
  normalizer: [{
4845
4813
  validChildren: CONTAINERS[BLOCKS.QUOTE],
4846
- transform: (_transform = {}, _transform[BLOCKS.QUOTE] = transformUnwrap, _transform[BLOCKS.HEADING_1] = transformUnwrap, _transform[BLOCKS.HEADING_2] = transformUnwrap, _transform[BLOCKS.HEADING_3] = transformUnwrap, _transform[BLOCKS.HEADING_4] = transformUnwrap, _transform[BLOCKS.HEADING_5] = transformUnwrap, _transform[BLOCKS.HEADING_6] = transformUnwrap, _transform["default"] = transformLift, _transform)
4847
- }]
4814
+ transform: (_transform = {}, _transform[BLOCKS.QUOTE] = transformUnwrap, _transform["default"] = transformLift, _transform)
4815
+ }],
4816
+ withOverrides: function withOverrides(editor) {
4817
+ var insertFragment = editor.insertFragment;
4818
+
4819
+ editor.insertFragment = function (fragment) {
4820
+ var startingNode = fragment.length && fragment[0];
4821
+ var startsWithBlockquote = Element.isElement(startingNode) && startingNode.type === BLOCKS.QUOTE;
4822
+ var containerEntry = getAbove(editor, {
4823
+ match: {
4824
+ type: TEXT_CONTAINERS
4825
+ }
4826
+ });
4827
+ var containerIsNotEmpty = containerEntry && Node.string(containerEntry[0]) !== '';
4828
+
4829
+ if (startsWithBlockquote && containerIsNotEmpty) {
4830
+ var selection = editor.selection;
4831
+
4832
+ var isContentSelected = function isContentSelected(selection) {
4833
+ return !!selection && Point.compare(selection.anchor, selection.focus) !== 0;
4834
+ }; // if something is selected (highlighted) we replace the selection
4835
+
4836
+
4837
+ if (isContentSelected(selection)) {
4838
+ Transforms["delete"](editor, {
4839
+ at: selection
4840
+ });
4841
+ } // get the cursor entry again, it may be different after deletion
4842
+
4843
+
4844
+ var _containerEntry = getAbove(editor, {
4845
+ match: {
4846
+ type: TEXT_CONTAINERS
4847
+ }
4848
+ });
4849
+
4850
+ var _containerIsNotEmpty = _containerEntry && Node.string(_containerEntry[0]) !== '';
4851
+
4852
+ if (_containerIsNotEmpty) {
4853
+ Transforms.insertNodes(editor, fragment);
4854
+ return;
4855
+ }
4856
+ }
4857
+
4858
+ insertFragment(fragment);
4859
+ };
4860
+
4861
+ return editor;
4862
+ }
4848
4863
  };
4849
4864
  }
4850
4865
 
@@ -4853,7 +4868,7 @@ function ToolbarQuoteButton(props) {
4853
4868
 
4854
4869
  function handleOnClick() {
4855
4870
  if (!editor) return;
4856
- toggleQuote(editor);
4871
+ toggleQuote(editor, editor.tracking.onToolbarAction);
4857
4872
  focus(editor);
4858
4873
  }
4859
4874
 
@@ -4902,8 +4917,7 @@ function hasHeadersOutsideFirstRow(nodes) {
4902
4917
  });
4903
4918
  }
4904
4919
 
4905
- function addTableTrackingEvents(editor, _ref6) {
4906
- var onViewportAction = _ref6.onViewportAction;
4920
+ function addTableTrackingEvents(editor) {
4907
4921
  var insertData = editor.insertData;
4908
4922
 
4909
4923
  editor.insertData = function (data) {
@@ -4917,7 +4931,7 @@ function addTableTrackingEvents(editor, _ref6) {
4917
4931
  if (hasTables(markupBefore)) return;
4918
4932
 
4919
4933
  if (hasTables(markupAfter)) {
4920
- onViewportAction('paste', {
4934
+ editor.tracking.onViewportAction('paste', {
4921
4935
  tablePasted: true,
4922
4936
  hasHeadersOutsideFirstRow: hasHeadersOutsideFirstRow(markupAfter)
4923
4937
  });
@@ -4929,29 +4943,6 @@ function addTableTrackingEvents(editor, _ref6) {
4929
4943
  };
4930
4944
  }
4931
4945
 
4932
- function useTracking(_ref) {
4933
- var onAction = _ref.onAction;
4934
- var trackingMemo = useMemo(function () {
4935
- return {
4936
- onViewportAction: function onViewportAction(actionName, data) {
4937
- if (data === void 0) {
4938
- data = {};
4939
- }
4940
-
4941
- return onAction(actionName, _extends({
4942
- origin: 'viewport-interaction'
4943
- }, data));
4944
- }
4945
- };
4946
- }, [] // eslint-disable-line
4947
- );
4948
- return trackingMemo;
4949
- }
4950
-
4951
- var _constate$2 = /*#__PURE__*/constate(useTracking),
4952
- TrackingProvider = _constate$2[0],
4953
- useTrackingContext = _constate$2[1];
4954
-
4955
4946
  var addRow = function addRow(editor, getNextRowPath) {
4956
4947
  if (someNode(editor, {
4957
4948
  match: {
@@ -5197,9 +5188,6 @@ var TableActions = function TableActions() {
5197
5188
  var editor = useContentfulEditor();
5198
5189
  var isDisabled = useReadOnly();
5199
5190
 
5200
- var _useTrackingContext = useTrackingContext(),
5201
- onViewportAction = _useTrackingContext.onViewportAction;
5202
-
5203
5191
  var _React$useState = React__default.useState(false),
5204
5192
  isOpen = _React$useState[0],
5205
5193
  setOpen = _React$useState[1];
@@ -5249,11 +5237,11 @@ var TableActions = function TableActions() {
5249
5237
  }); // Tracking
5250
5238
 
5251
5239
  var actionName = type + "Table" + (element === 'Table' ? '' : element);
5252
- onViewportAction(actionName, {
5240
+ editor.tracking.onViewportAction(actionName, {
5253
5241
  tableSize: tableSize
5254
5242
  });
5255
5243
  };
5256
- }, [editor, isHeaderEnabled, close, onViewportAction]);
5244
+ }, [editor, isHeaderEnabled, close]);
5257
5245
 
5258
5246
  if (isDisabled) {
5259
5247
  return null;
@@ -5344,7 +5332,7 @@ var createTableOnKeyDown = function createTableOnKeyDown(editor, plugin) {
5344
5332
  };
5345
5333
  };
5346
5334
 
5347
- var createTablePlugin = function createTablePlugin(tracking) {
5335
+ var createTablePlugin = function createTablePlugin() {
5348
5336
  var _overrideByKey;
5349
5337
 
5350
5338
  return createTablePlugin$1({
@@ -5353,7 +5341,7 @@ var createTablePlugin = function createTablePlugin(tracking) {
5353
5341
  onKeyDown: createTableOnKeyDown
5354
5342
  },
5355
5343
  withOverrides: function withOverrides(editor) {
5356
- addTableTrackingEvents(editor, tracking);
5344
+ addTableTrackingEvents(editor);
5357
5345
  var insertFragment = editor.insertFragment;
5358
5346
 
5359
5347
  editor.insertFragment = function (fragments) {
@@ -5453,10 +5441,6 @@ var createTablePlugin = function createTablePlugin(tracking) {
5453
5441
 
5454
5442
  function ToolbarTableButton(props) {
5455
5443
  var editor = useContentfulEditor();
5456
-
5457
- var _useTrackingContext = useTrackingContext(),
5458
- onViewportAction = _useTrackingContext.onViewportAction;
5459
-
5460
5444
  var isActive = editor && isTableActive(editor);
5461
5445
 
5462
5446
  function handleClick() {
@@ -5477,7 +5461,7 @@ function ToolbarTableButton(props) {
5477
5461
  return _context.abrupt("return");
5478
5462
 
5479
5463
  case 2:
5480
- onViewportAction('insertTable');
5464
+ editor.tracking.onToolbarAction('insertTable');
5481
5465
  insertTableAndFocusFirstCell(editor);
5482
5466
  focus(editor);
5483
5467
 
@@ -5582,35 +5566,199 @@ function deleteEmptyParagraph(unit, editor, deleteFunction) {
5582
5566
  }
5583
5567
  }
5584
5568
 
5585
- var createTrailingParagraphPlugin = function createTrailingParagraphPlugin() {
5586
- return createTrailingBlockPlugin({
5587
- options: {
5588
- type: BLOCKS.PARAGRAPH,
5589
- level: 0
5569
+ var _extends2, _extends4, _inlines;
5570
+ var inlines = /*#__PURE__*/Object.values(INLINES).map(function (type) {
5571
+ return {
5572
+ type: type
5573
+ };
5574
+ });
5575
+ var schema = {
5576
+ document: {
5577
+ nodes: [{
5578
+ types: /*#__PURE__*/TOP_LEVEL_BLOCKS.map(function (type) {
5579
+ return {
5580
+ type: type
5581
+ };
5582
+ })
5583
+ }]
5584
+ },
5585
+ blocks: /*#__PURE__*/_extends((_extends2 = {}, _extends2[BLOCKS.PARAGRAPH] = {
5586
+ nodes: [{
5587
+ match: /*#__PURE__*/[].concat(inlines, [{
5588
+ object: 'text'
5589
+ }])
5590
+ }]
5591
+ }, _extends2[BLOCKS.HEADING_1] = {
5592
+ nodes: [{
5593
+ match: /*#__PURE__*/[].concat(inlines, [{
5594
+ object: 'text'
5595
+ }])
5596
+ }]
5597
+ }, _extends2[BLOCKS.HEADING_2] = {
5598
+ nodes: [{
5599
+ match: /*#__PURE__*/[].concat(inlines, [{
5600
+ object: 'text'
5601
+ }])
5602
+ }]
5603
+ }, _extends2[BLOCKS.HEADING_3] = {
5604
+ nodes: [{
5605
+ match: /*#__PURE__*/[].concat(inlines, [{
5606
+ object: 'text'
5607
+ }])
5608
+ }]
5609
+ }, _extends2[BLOCKS.HEADING_4] = {
5610
+ nodes: [{
5611
+ match: /*#__PURE__*/[].concat(inlines, [{
5612
+ object: 'text'
5613
+ }])
5614
+ }]
5615
+ }, _extends2[BLOCKS.HEADING_5] = {
5616
+ nodes: [{
5617
+ match: /*#__PURE__*/[].concat(inlines, [{
5618
+ object: 'text'
5619
+ }])
5620
+ }]
5621
+ }, _extends2[BLOCKS.HEADING_6] = {
5622
+ nodes: [{
5623
+ match: /*#__PURE__*/[].concat(inlines, [{
5624
+ object: 'text'
5625
+ }])
5626
+ }]
5627
+ }, _extends2), /*#__PURE__*/VOID_BLOCKS.reduce(function (blocks, nodeType) {
5628
+ var _extends3;
5629
+
5630
+ return _extends({}, blocks, (_extends3 = {}, _extends3[nodeType] = {
5631
+ isVoid: true
5632
+ }, _extends3));
5633
+ }, {}), (_extends4 = {}, _extends4[BLOCKS.QUOTE] = {
5634
+ nodes: [{
5635
+ match: [/*#__PURE__*/CONTAINERS[BLOCKS.QUOTE].map(function (type) {
5636
+ return {
5637
+ type: type
5638
+ };
5639
+ })],
5640
+ min: 1
5641
+ }],
5642
+ normalize: function normalize(editor, error) {
5643
+ if (error.code === 'child_type_invalid') {
5644
+ return editor.unwrapBlockByKey(error.node.key, BLOCKS.QUOTE);
5645
+ }
5590
5646
  }
5647
+ }, _extends4)),
5648
+ inlines: (_inlines = {}, _inlines[INLINES.HYPERLINK] = {
5649
+ nodes: [{
5650
+ match: [{
5651
+ object: 'text'
5652
+ }]
5653
+ }]
5654
+ }, _inlines[INLINES.ENTRY_HYPERLINK] = {
5655
+ nodes: [{
5656
+ match: [{
5657
+ object: 'text'
5658
+ }]
5659
+ }]
5660
+ }, _inlines[INLINES.ASSET_HYPERLINK] = {
5661
+ nodes: [{
5662
+ match: [{
5663
+ object: 'text'
5664
+ }]
5665
+ }]
5666
+ }, _inlines[INLINES.EMBEDDED_ENTRY] = {
5667
+ isVoid: true
5668
+ }, _inlines)
5669
+ };
5670
+
5671
+ function getCharacterCount(editor) {
5672
+ var document = toContentfulDocument({
5673
+ document: editor.children,
5674
+ schema: schema
5591
5675
  });
5676
+ return documentToPlainTextString(document).length;
5677
+ }
5678
+
5679
+ var actionOrigin = {
5680
+ TOOLBAR: 'toolbar-icon',
5681
+ SHORTCUT: 'shortcut',
5682
+ VIEWPORT: 'viewport-interaction',
5683
+ COMMAND_PALETTE: 'command-palette'
5592
5684
  };
5685
+ var createTrackingPlugin = function createTrackingPlugin(onAction) {
5686
+ var trackingActions = {
5687
+ onViewportAction: function onViewportAction(actionName, data) {
5688
+ if (data === void 0) {
5689
+ data = {};
5690
+ }
5593
5691
 
5594
- /**
5595
- * Re-creates a void node with valid children.
5596
- */
5692
+ return onAction(actionName, _extends({
5693
+ origin: actionOrigin.VIEWPORT
5694
+ }, data));
5695
+ },
5696
+ onShortcutAction: function onShortcutAction(actionName, data) {
5697
+ if (data === void 0) {
5698
+ data = {};
5699
+ }
5597
5700
 
5598
- var transformVoid = function transformVoid(editor, _ref) {
5599
- var node = _ref[0],
5600
- path = _ref[1];
5701
+ return onAction(actionName, _extends({
5702
+ origin: actionOrigin.SHORTCUT
5703
+ }, data));
5704
+ },
5705
+ onToolbarAction: function onToolbarAction(actionName, data) {
5706
+ if (data === void 0) {
5707
+ data = {};
5708
+ }
5601
5709
 
5602
- var validVoid = _extends({}, node, {
5603
- children: [{
5604
- text: ''
5605
- }]
5606
- }); // A workaround because Slate doesn't allow adjusting void nodes children
5710
+ return onAction(actionName, _extends({
5711
+ origin: actionOrigin.TOOLBAR
5712
+ }, data));
5713
+ },
5714
+ onCommandPaletteAction: function onCommandPaletteAction(actionName, data) {
5715
+ if (data === void 0) {
5716
+ data = {};
5717
+ }
5718
+
5719
+ return onAction(actionName, _extends({
5720
+ origin: actionOrigin.COMMAND_PALETTE
5721
+ }, data));
5722
+ }
5723
+ };
5724
+ return {
5725
+ key: 'TrackingPlugin',
5726
+ withOverrides: function withOverrides(editor) {
5727
+ var insertData = editor.insertData;
5728
+ editor.tracking = trackingActions;
5729
+
5730
+ editor.insertData = function (data) {
5731
+ var isCopyAndPaste = data.types.length !== 0;
5732
+
5733
+ if (isCopyAndPaste) {
5734
+ var _window$getSelection;
5735
+
5736
+ var characterCountSelection = (_window$getSelection = window.getSelection()) == null ? void 0 : _window$getSelection.toString().length;
5737
+ var characterCountBefore = getCharacterCount(editor);
5738
+ setTimeout(function () {
5739
+ var characterCountAfter = getCharacterCount(editor);
5740
+ trackingActions.onShortcutAction('paste', {
5741
+ characterCountAfter: characterCountAfter,
5742
+ characterCountBefore: characterCountBefore,
5743
+ characterCountSelection: characterCountSelection
5744
+ });
5745
+ });
5746
+ }
5607
5747
 
5748
+ insertData(data);
5749
+ };
5608
5750
 
5609
- Transforms.removeNodes(editor, {
5610
- at: path
5611
- });
5612
- Transforms.insertNodes(editor, [validVoid], {
5613
- at: path
5751
+ return editor;
5752
+ }
5753
+ };
5754
+ };
5755
+
5756
+ var createTrailingParagraphPlugin = function createTrailingParagraphPlugin() {
5757
+ return createTrailingBlockPlugin({
5758
+ options: {
5759
+ type: BLOCKS.PARAGRAPH,
5760
+ level: 0
5761
+ }
5614
5762
  });
5615
5763
  };
5616
5764
 
@@ -5642,34 +5790,17 @@ var createVoidsPlugin = function createVoidsPlugin() {
5642
5790
  return !(isRootLevel(path) && isFirstChild(path)) && !!node.isVoid;
5643
5791
  }
5644
5792
  }
5645
- }],
5646
- normalizer: [{
5647
- match: {
5648
- isVoid: true
5649
- },
5650
- validNode: function validNode(editor, _ref3) {
5651
- var path = _ref3[1];
5652
- var children = Array.from(Node.children(editor, path));
5653
-
5654
- if (children.length !== 1) {
5655
- return false;
5656
- }
5657
-
5658
- var _children$ = children[0],
5659
- textNode = _children$[0];
5660
- return Text.isText(textNode) && textNode.text === '';
5661
- },
5662
- transform: transformVoid
5663
5793
  }]
5664
5794
  };
5665
5795
  };
5666
5796
 
5667
- var getPlugins = function getPlugins(sdk, tracking) {
5797
+ var getPlugins = function getPlugins(sdk, onAction) {
5668
5798
  return [// AST must come after the HTML deserializer
5669
- createDeserializeHtmlPlugin(), createDeserializeAstPlugin(), createDeserializeDocxPlugin(), // Global shortcuts
5799
+ createDeserializeHtmlPlugin(), createDeserializeAstPlugin(), createDeserializeDocxPlugin(), // Tracking - This should come first so all plugins below will have access to `editor.tracking`
5800
+ createTrackingPlugin(onAction), // Global / Global shortcuts
5670
5801
  createDragAndDropPlugin(), // Block Elements
5671
- createParagraphPlugin(), createListPlugin(), createHrPlugin(), createHeadingPlugin(), createQuotePlugin(), createTablePlugin(tracking), createEmbeddedEntryBlockPlugin(sdk, tracking), createEmbeddedAssetBlockPlugin(sdk, tracking), // Inline elements
5672
- createHyperlinkPlugin(sdk, tracking), createEmbeddedEntityInlinePlugin(sdk, tracking), // Marks
5802
+ createParagraphPlugin(), createListPlugin(), createHrPlugin(), createHeadingPlugin(), createQuotePlugin(), createTablePlugin(), createEmbeddedEntryBlockPlugin(sdk), createEmbeddedAssetBlockPlugin(sdk), // Inline elements
5803
+ createHyperlinkPlugin(sdk), createEmbeddedEntityInlinePlugin(sdk), // Marks
5673
5804
  createMarksPlugin(), // Other
5674
5805
  createTrailingParagraphPlugin(), createTextPlugin(), createVoidsPlugin(), createSelectOnBackspacePlugin(), // Pasting content from other sources
5675
5806
  createPasteHTMLPlugin(), // These plugins drive their configurations from the list of plugins
@@ -5978,18 +6109,56 @@ var useNormalizedSlateValue = function useNormalizedSlateValue(_ref) {
5978
6109
  }, [id, plugins, incomingDoc]);
5979
6110
  };
5980
6111
 
6112
+ /**
6113
+ * Returns whether a given operation is relevant enough to trigger a save.
6114
+ */
6115
+
6116
+ var isRelevantOperation = function isRelevantOperation(op) {
6117
+ if (op.type === 'set_selection') {
6118
+ return false;
6119
+ }
6120
+
6121
+ return true;
6122
+ };
6123
+
6124
+ var useOnValueChanged = function useOnValueChanged(_ref) {
6125
+ var editor = _ref.editor,
6126
+ handler = _ref.handler;
6127
+ var onChange = useMemo(function () {
6128
+ return debounce(function (document) {
6129
+ handler == null ? void 0 : handler(toContentfulDocument({
6130
+ document: document,
6131
+ schema: schema
6132
+ }));
6133
+ }, 500);
6134
+ }, [handler]);
6135
+ return useCallback(function (value) {
6136
+ var operations = editor.operations.filter(isRelevantOperation);
6137
+
6138
+ if (operations.length > 0) {
6139
+ onChange(value);
6140
+ }
6141
+ }, [editor, onChange]);
6142
+ };
6143
+
5981
6144
  var _excluded = ["sdk", "isInitiallyDisabled", "onAction"];
5982
6145
  var ConnectedRichTextEditor = function ConnectedRichTextEditor(props) {
5983
- var id = getContentfulEditorId(props.sdk);
5984
- var tracking = useTrackingContext();
6146
+ var id = useContentfulEditorId();
6147
+ var editor = useContentfulEditor();
5985
6148
  var plugins = React__default.useMemo(function () {
5986
- return getPlugins(props.sdk, tracking);
5987
- }, [props.sdk, tracking]);
6149
+ var _props$onAction;
6150
+
6151
+ return getPlugins(props.sdk, (_props$onAction = props.onAction) != null ? _props$onAction : noop);
6152
+ }, [props.sdk, props.onAction]);
5988
6153
  var initialValue = useNormalizedSlateValue({
5989
6154
  id: id,
5990
6155
  incomingDoc: props.value,
5991
6156
  plugins: plugins
5992
6157
  });
6158
+ var onValueChanged = useOnValueChanged({
6159
+ editor: editor,
6160
+ handler: props.onChange
6161
+ });
5993
6162
  var classNames = cx(styles$j.editor, props.minHeight !== undefined ? css({
5994
6163
  minHeight: props.minHeight
5995
6164
  }) : undefined, props.isDisabled ? styles$j.disabled : styles$j.enabled, props.isToolbarHidden && styles$j.hiddenToolbar);
@@ -6005,12 +6174,7 @@ var ConnectedRichTextEditor = function ConnectedRichTextEditor(props) {
6005
6174
  className: classNames,
6006
6175
  readOnly: props.isDisabled
6007
6176
  },
6008
- onChange: function onChange(document) {
6009
- props.onChange == null ? void 0 : props.onChange(toContentfulDocument({
6010
- document: document,
6011
- schema: schema
6012
- }));
6013
- }
6177
+ onChange: onValueChanged
6014
6178
  }, !props.isToolbarHidden && /*#__PURE__*/React__default.createElement(StickyToolbarWrapper, {
6015
6179
  isDisabled: props.isDisabled
6016
6180
  }, /*#__PURE__*/React__default.createElement(Toolbar, {
@@ -6027,12 +6191,11 @@ var RichTextEditor = function RichTextEditor(props) {
6027
6191
  var isEmptyValue = useCallback(function (value) {
6028
6192
  return !value || deepEquals(value, EMPTY_DOCUMENT);
6029
6193
  }, []);
6194
+ var editorId = getContentfulEditorId(sdk);
6030
6195
  return /*#__PURE__*/React__default.createElement(EntityProvider, {
6031
6196
  sdk: sdk
6032
6197
  }, /*#__PURE__*/React__default.createElement(SdkProvider, {
6033
6198
  sdk: sdk
6034
- }, /*#__PURE__*/React__default.createElement(TrackingProvider, {
6035
- onAction: onAction || noop
6036
6199
  }, /*#__PURE__*/React__default.createElement(FieldConnector, {
6037
6200
  throttle: 0,
6038
6201
  field: sdk.field,
@@ -6044,17 +6207,17 @@ var RichTextEditor = function RichTextEditor(props) {
6044
6207
  disabled = _ref.disabled,
6045
6208
  setValue = _ref.setValue,
6046
6209
  externalReset = _ref.externalReset;
6047
- return /*#__PURE__*/React__default.createElement(ContentfulEditorProvider, {
6048
- sdk: sdk
6210
+ return /*#__PURE__*/React__default.createElement(ContentfulEditorIdProvider, {
6211
+ value: editorId
6049
6212
  }, /*#__PURE__*/React__default.createElement(ConnectedRichTextEditor, Object.assign({}, otherProps, {
6050
6213
  key: "rich-text-editor-" + externalReset,
6051
6214
  value: lastRemoteValue,
6052
6215
  sdk: sdk,
6053
- onAction: onAction || noop,
6216
+ onAction: onAction,
6054
6217
  isDisabled: disabled,
6055
6218
  onChange: setValue
6056
6219
  })));
6057
- }))));
6220
+ })));
6058
6221
  };
6059
6222
 
6060
6223
  var LINK_TYPES$1 = {