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

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 (55) 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 +502 -359
  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 +505 -362
  8. package/dist/field-editor-rich-text.esm.js.map +1 -1
  9. package/dist/helpers/editor.d.ts +16 -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 +6 -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/Quote/toggleQuote.d.ts +5 -3
  35. package/dist/plugins/Table/actions/addColumn.d.ts +3 -3
  36. package/dist/plugins/Table/actions/addRow.d.ts +3 -3
  37. package/dist/plugins/Table/actions/setHeader.d.ts +2 -2
  38. package/dist/plugins/Table/addTableTrackingEvents.d.ts +2 -3
  39. package/dist/plugins/Table/createTablePlugin.d.ts +1 -2
  40. package/dist/plugins/Table/helpers.d.ts +7 -7
  41. package/dist/plugins/Tracking/createTrackingPlugin.d.ts +10 -0
  42. package/dist/plugins/Tracking/index.d.ts +1 -0
  43. package/dist/plugins/Tracking/utils.d.ts +2 -0
  44. package/dist/plugins/TrailingParagraph/index.d.ts +2 -1
  45. package/dist/plugins/Voids/transformVoid.d.ts +2 -2
  46. package/dist/plugins/index.d.ts +2 -2
  47. package/dist/plugins/links-tracking.d.ts +1 -2
  48. package/dist/test-utils/assertOutput.d.ts +2 -2
  49. package/dist/test-utils/createEditor.d.ts +5 -6
  50. package/dist/test-utils/mockPlugin.d.ts +1 -1
  51. package/dist/test-utils/setEmptyDataAttribute.d.ts +2 -2
  52. package/dist/types.d.ts +6 -2
  53. package/dist/useOnValueChanged.d.ts +7 -0
  54. package/package.json +1 -1
  55. 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, HEADINGS, TEXT_CONTAINERS, 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, isSelectionAtBlockStart, isSelectionAtBlockEnd, isFirstChild, insertNodes, moveChildren, isBlockAboveEmpty, mockPlugin, getPluginType, ELEMENT_DEFAULT, findNode, isMarkActive, toggleMark, someHtmlElement, match, KEY_DESERIALIZE_HTML, someNode, getChildren as getChildren$1, getBlockAbove, 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, Path, Node, 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) {
@@ -699,12 +612,14 @@ var focus = function focus(editor) {
699
612
  }
700
613
  };
701
614
 
702
- function withLinkTracking(tracking, Component) {
615
+ function withLinkTracking(Component) {
703
616
  return function ComponentWithTracking(props) {
617
+ var editor = useContentfulEditorRef();
618
+ var onEntityFetchComplete = React__default.useCallback(function () {
619
+ return editor.tracking.onViewportAction('linkRendered');
620
+ }, [editor]);
704
621
  return /*#__PURE__*/React__default.createElement(Component, Object.assign({}, props, {
705
- onEntityFetchComplete: function onEntityFetchComplete() {
706
- tracking.onViewportAction('linkRendered');
707
- }
622
+ onEntityFetchComplete: onEntityFetchComplete
708
623
  }));
709
624
  };
710
625
  }
@@ -718,9 +633,9 @@ function useSdk(_ref) {
718
633
  return sdkMemo;
719
634
  }
720
635
 
721
- var _constate$1 = /*#__PURE__*/constate(useSdk),
722
- SdkProvider = _constate$1[0],
723
- useSdkContext = _constate$1[1];
636
+ var _constate = /*#__PURE__*/constate(useSdk),
637
+ SdkProvider = _constate[0],
638
+ useSdkContext = _constate[1];
724
639
 
725
640
  var styles = {
726
641
  scheduleIcon: /*#__PURE__*/css({
@@ -1970,12 +1885,11 @@ function _selectEntityAndInsert() {
1970
1885
  config = _extends({}, baseConfig, {
1971
1886
  withCreate: true
1972
1887
  });
1973
- _context.prev = 5;
1974
1888
  selection = editor.selection;
1975
- _context.next = 9;
1889
+ _context.next = 8;
1976
1890
  return selectEntity(config);
1977
1891
 
1978
- case 9:
1892
+ case 8:
1979
1893
  entity = _context.sent;
1980
1894
 
1981
1895
  if (entity) {
@@ -1983,6 +1897,9 @@ function _selectEntityAndInsert() {
1983
1897
  break;
1984
1898
  }
1985
1899
 
1900
+ logAction('cancelCreateEmbedDialog', {
1901
+ nodeType: nodeType
1902
+ });
1986
1903
  return _context.abrupt("return");
1987
1904
 
1988
1905
  case 12:
@@ -1991,31 +1908,13 @@ function _selectEntityAndInsert() {
1991
1908
  logAction('insert', {
1992
1909
  nodeType: nodeType
1993
1910
  });
1994
- _context.next = 24;
1995
- break;
1996
-
1997
- case 17:
1998
- _context.prev = 17;
1999
- _context.t0 = _context["catch"](5);
2000
1911
 
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:
1912
+ case 15:
2014
1913
  case "end":
2015
1914
  return _context.stop();
2016
1915
  }
2017
1916
  }
2018
- }, _callee, null, [[5, 17]]);
1917
+ }, _callee);
2019
1918
  }));
2020
1919
  return _selectEntityAndInsert.apply(this, arguments);
2021
1920
  }
@@ -2062,7 +1961,6 @@ var styles$4 = {
2062
1961
  function EmbeddedEntityBlockToolbarIcon(_ref) {
2063
1962
  var isButton = _ref.isButton,
2064
1963
  isDisabled = _ref.isDisabled,
2065
- logAction = _ref.logAction,
2066
1964
  nodeType = _ref.nodeType,
2067
1965
  onClose = _ref.onClose;
2068
1966
  var editor = useContentfulEditor();
@@ -2071,7 +1969,7 @@ function EmbeddedEntityBlockToolbarIcon(_ref) {
2071
1969
  var handleClick = function handleClick(event) {
2072
1970
  event.preventDefault();
2073
1971
  onClose();
2074
- selectEntityAndInsert(nodeType, sdk, editor, logAction || noop);
1972
+ selectEntityAndInsert(nodeType, sdk, editor, editor.tracking.onToolbarAction);
2075
1973
  };
2076
1974
 
2077
1975
  var type = getEntityTypeFromNodeType(nodeType);
@@ -2138,20 +2036,20 @@ function getWithEmbeddedEntityEvents(nodeType, sdk) {
2138
2036
  }
2139
2037
 
2140
2038
  if (hotkey && isHotkey(hotkey, event)) {
2141
- selectEntityAndInsert(nodeType, sdk, editor, noop);
2039
+ selectEntityAndInsert(nodeType, sdk, editor, editor.tracking.onShortcutAction);
2142
2040
  }
2143
2041
  };
2144
2042
  };
2145
2043
  }
2146
2044
 
2147
2045
  var createEmbeddedEntityPlugin = function createEmbeddedEntityPlugin(nodeType, hotkey) {
2148
- return function (sdk, tracking) {
2046
+ return function (sdk) {
2149
2047
  return {
2150
2048
  key: nodeType,
2151
2049
  type: nodeType,
2152
2050
  isElement: true,
2153
2051
  isVoid: true,
2154
- component: withLinkTracking(tracking, LinkedEntityBlock),
2052
+ component: withLinkTracking(LinkedEntityBlock),
2155
2053
  options: {
2156
2054
  hotkey: hotkey
2157
2055
  },
@@ -2369,44 +2267,53 @@ function EmbeddedEntityInline(props) {
2369
2267
  })), props.children);
2370
2268
  }
2371
2269
 
2372
- function selectEntityAndInsert$1(_x, _x2) {
2270
+ function selectEntityAndInsert$1(_x, _x2, _x3) {
2373
2271
  return _selectEntityAndInsert$1.apply(this, arguments);
2374
2272
  }
2375
2273
 
2376
2274
  function _selectEntityAndInsert$1() {
2377
- _selectEntityAndInsert$1 = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(editor, sdk) {
2275
+ _selectEntityAndInsert$1 = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(editor, sdk, logAction) {
2378
2276
  var config, selection, entry, inlineEntryNode;
2379
2277
  return runtime_1.wrap(function _callee2$(_context2) {
2380
2278
  while (1) {
2381
2279
  switch (_context2.prev = _context2.next) {
2382
2280
  case 0:
2281
+ logAction('openCreateEmbedDialog', {
2282
+ nodeType: INLINES.EMBEDDED_ENTRY
2283
+ });
2383
2284
  config = _extends({}, newEntitySelectorConfigFromRichTextField(sdk.field, INLINES.EMBEDDED_ENTRY), {
2384
2285
  withCreate: true
2385
2286
  });
2386
2287
  selection = editor.selection;
2387
- _context2.next = 4;
2288
+ _context2.next = 5;
2388
2289
  return sdk.dialogs.selectSingleEntry(config);
2389
2290
 
2390
- case 4:
2291
+ case 5:
2391
2292
  entry = _context2.sent;
2392
2293
  focus(editor); // Dialog steals focus from editor, return it.
2393
2294
 
2394
2295
  if (entry) {
2395
- _context2.next = 8;
2296
+ _context2.next = 10;
2396
2297
  break;
2397
2298
  }
2398
2299
 
2300
+ logAction('cancelCreateEmbedDialog', {
2301
+ nodeType: INLINES.EMBEDDED_ENTRY
2302
+ });
2399
2303
  return _context2.abrupt("return");
2400
2304
 
2401
- case 8:
2305
+ case 10:
2402
2306
  inlineEntryNode = createInlineEntryNode(entry.sys.id); // Got to wait until focus is really back on the editor or setSelection() won't work.
2403
2307
 
2404
2308
  setTimeout(function () {
2405
2309
  Transforms.setSelection(editor, selection);
2406
2310
  Transforms.insertNodes(editor, inlineEntryNode);
2407
2311
  }, 0);
2312
+ logAction('insert', {
2313
+ nodeType: INLINES.EMBEDDED_ENTRY
2314
+ });
2408
2315
 
2409
- case 10:
2316
+ case 13:
2410
2317
  case "end":
2411
2318
  return _context2.stop();
2412
2319
  }
@@ -2420,7 +2327,7 @@ function ToolbarEmbeddedEntityInlineButton(props) {
2420
2327
  var editor = useContentfulEditor();
2421
2328
  var sdk = useSdkContext();
2422
2329
 
2423
- function handleClick(_x3) {
2330
+ function handleClick(_x4) {
2424
2331
  return _handleClick.apply(this, arguments);
2425
2332
  }
2426
2333
 
@@ -2442,7 +2349,7 @@ function ToolbarEmbeddedEntityInlineButton(props) {
2442
2349
  case 3:
2443
2350
  props.onClose();
2444
2351
  _context.next = 6;
2445
- return selectEntityAndInsert$1(editor, sdk);
2352
+ return selectEntityAndInsert$1(editor, sdk, editor.tracking.onToolbarAction);
2446
2353
 
2447
2354
  case 6:
2448
2355
  case "end":
@@ -2475,7 +2382,7 @@ function ToolbarEmbeddedEntityInlineButton(props) {
2475
2382
  className: "rich-text__embedded-entry-list-icon " + styles$6.icon
2476
2383
  }), /*#__PURE__*/createElement("span", null, "Inline entry")));
2477
2384
  }
2478
- function createEmbeddedEntityInlinePlugin(sdk, tracking) {
2385
+ function createEmbeddedEntityInlinePlugin(sdk) {
2479
2386
  var htmlAttributeName = 'data-embedded-entity-inline-id';
2480
2387
  return {
2481
2388
  key: INLINES.EMBEDDED_ENTRY,
@@ -2483,7 +2390,7 @@ function createEmbeddedEntityInlinePlugin(sdk, tracking) {
2483
2390
  isElement: true,
2484
2391
  isInline: true,
2485
2392
  isVoid: true,
2486
- component: withLinkTracking(tracking, EmbeddedEntityInline),
2393
+ component: withLinkTracking(EmbeddedEntityInline),
2487
2394
  options: {
2488
2395
  hotkey: 'mod+shift+2'
2489
2396
  },
@@ -2509,7 +2416,7 @@ function getWithEmbeddedEntryInlineEvents(sdk) {
2509
2416
  if (!editor) return;
2510
2417
 
2511
2418
  if (hotkey && isHotkey(hotkey, event)) {
2512
- selectEntityAndInsert$1(editor, sdk);
2419
+ selectEntityAndInsert$1(editor, sdk, editor.tracking.onShortcutAction);
2513
2420
  }
2514
2421
  };
2515
2422
  };
@@ -2612,6 +2519,10 @@ function ToolbarHeadingButton(props) {
2612
2519
  prevOnChange.apply(void 0, arguments);
2613
2520
  };
2614
2521
 
2522
+ var isActive = isBlockSelected(editor, type);
2523
+ editor.tracking.onToolbarAction(isActive ? 'remove' : 'insert', {
2524
+ nodeType: type
2525
+ });
2615
2526
  toggleNodeType(editor, {
2616
2527
  activeType: type,
2617
2528
  inactiveType: type
@@ -2733,6 +2644,24 @@ function createHeading(Tag, block) {
2733
2644
 
2734
2645
  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
2646
 
2647
+ var buildHeadingEventHandler = function buildHeadingEventHandler(type) {
2648
+ return function (editor, _ref) {
2649
+ var hotkey = _ref.options.hotkey;
2650
+ return function (event) {
2651
+ if (editor.selection && hotkey && isHotkey(hotkey, event)) {
2652
+ var isActive = isBlockSelected(editor, type);
2653
+ editor.tracking.onShortcutAction(isActive ? 'remove' : 'insert', {
2654
+ nodeType: type
2655
+ });
2656
+ toggleNodeType(editor, {
2657
+ activeType: type,
2658
+ inactiveType: BLOCKS.PARAGRAPH
2659
+ });
2660
+ }
2661
+ };
2662
+ };
2663
+ };
2664
+
2736
2665
  var createHeadingPlugin = function createHeadingPlugin() {
2737
2666
  var _transform;
2738
2667
 
@@ -2749,8 +2678,8 @@ var createHeadingPlugin = function createHeadingPlugin() {
2749
2678
  match: {
2750
2679
  type: HEADINGS
2751
2680
  },
2752
- validChildren: function validChildren(_, _ref) {
2753
- var node = _ref[0];
2681
+ validChildren: function validChildren(_, _ref2) {
2682
+ var node = _ref2[0];
2754
2683
  return isInlineOrText(node);
2755
2684
  },
2756
2685
  transform: (_transform = {}, _transform[BLOCKS.PARAGRAPH] = transformUnwrap, _transform["default"] = transformLift, _transform)
@@ -2767,8 +2696,8 @@ var createHeadingPlugin = function createHeadingPlugin() {
2767
2696
  start: true,
2768
2697
  // Exclude headings inside lists as it interferes with the list's
2769
2698
  // insertBreak implementation
2770
- filter: function filter(_ref2) {
2771
- var path = _ref2[1];
2699
+ filter: function filter(_ref3) {
2700
+ var path = _ref3[1];
2772
2701
  return !getAbove(editor, {
2773
2702
  at: path,
2774
2703
  match: {
@@ -2792,7 +2721,7 @@ var createHeadingPlugin = function createHeadingPlugin() {
2792
2721
  hotkey: ["mod+alt+" + level]
2793
2722
  },
2794
2723
  handlers: {
2795
- onKeyDown: onKeyDownToggleElement
2724
+ onKeyDown: buildHeadingEventHandler(nodeType)
2796
2725
  },
2797
2726
  deserializeHtml: {
2798
2727
  rules: [{
@@ -3322,13 +3251,15 @@ function HyperlinkModal(props) {
3322
3251
  testId: "confirm-cta"
3323
3252
  }, props.linkType ? 'Update' : 'Insert'))));
3324
3253
  }
3325
- function addOrEditLink(_x, _x2) {
3254
+ function addOrEditLink(_x, _x2, _x3) {
3326
3255
  return _addOrEditLink.apply(this, arguments);
3327
3256
  }
3328
3257
 
3329
3258
  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;
3259
+ _addOrEditLink = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee3(editor, sdk, logAction) {
3260
+ var _target$sys$linkType;
3261
+
3262
+ var linkType, linkText, linkTarget, linkEntity, _getNodeEntryFromSele, node, path, selectionBeforeBlur, currentLinkText, isEditing, data, text, url, type, target;
3332
3263
 
3333
3264
  return runtime_1.wrap(function _callee3$(_context3) {
3334
3265
  while (1) {
@@ -3353,9 +3284,11 @@ function _addOrEditLink() {
3353
3284
 
3354
3285
  selectionBeforeBlur = _extends({}, editor.selection);
3355
3286
  currentLinkText = linkText || Editor.string(editor, editor.selection);
3356
- _context3.next = 8;
3287
+ isEditing = Boolean(node && path);
3288
+ logAction(isEditing ? 'openEditHyperlinkDialog' : 'openCreateHyperlinkDialog');
3289
+ _context3.next = 10;
3357
3290
  return ModalDialogLauncher.openDialog({
3358
- title: linkType ? 'Edit hyperlink' : 'Insert hyperlink',
3291
+ title: isEditing ? 'Edit hyperlink' : 'Insert hyperlink',
3359
3292
  width: 'large',
3360
3293
  shouldCloseOnEscapePress: true,
3361
3294
  shouldCloseOnOverlayClick: true,
@@ -3372,17 +3305,18 @@ function _addOrEditLink() {
3372
3305
  });
3373
3306
  });
3374
3307
 
3375
- case 8:
3308
+ case 10:
3376
3309
  data = _context3.sent;
3377
3310
 
3378
3311
  if (data) {
3379
- _context3.next = 11;
3312
+ _context3.next = 14;
3380
3313
  break;
3381
3314
  }
3382
3315
 
3316
+ logAction(isEditing ? 'cancelEditHyperlinkDialog' : 'cancelCreateHyperlinkDialog');
3383
3317
  return _context3.abrupt("return");
3384
3318
 
3385
- case 11:
3319
+ case 14:
3386
3320
  text = data.linkText, url = data.linkTarget, type = data.linkType, target = data.linkEntity;
3387
3321
  Transforms.select(editor, selectionBeforeBlur);
3388
3322
  Editor.withoutNormalizing(editor, function () {
@@ -3394,9 +3328,13 @@ function _addOrEditLink() {
3394
3328
  path: path
3395
3329
  });
3396
3330
  });
3331
+ logAction(isEditing ? 'edit' : 'insert', {
3332
+ nodeType: type,
3333
+ linkType: (_target$sys$linkType = target == null ? void 0 : target.sys.linkType) != null ? _target$sys$linkType : 'uri'
3334
+ });
3397
3335
  focus(editor);
3398
3336
 
3399
- case 15:
3337
+ case 19:
3400
3338
  case "end":
3401
3339
  return _context3.stop();
3402
3340
  }
@@ -3460,7 +3398,7 @@ function UrlHyperlink(props) {
3460
3398
  event.preventDefault();
3461
3399
  event.stopPropagation();
3462
3400
  if (!editor) return;
3463
- addOrEditLink(editor, sdk);
3401
+ addOrEditLink(editor, sdk, editor.tracking.onViewportAction);
3464
3402
  }
3465
3403
 
3466
3404
  return /*#__PURE__*/createElement(Tooltip, {
@@ -3496,7 +3434,7 @@ function EntityHyperlink(props) {
3496
3434
  event.preventDefault();
3497
3435
  event.stopPropagation();
3498
3436
  if (!editor) return;
3499
- addOrEditLink(editor, sdk);
3437
+ addOrEditLink(editor, sdk, editor.tracking.onViewportAction);
3500
3438
  }
3501
3439
 
3502
3440
  return /*#__PURE__*/createElement(Tooltip, {
@@ -3543,8 +3481,9 @@ function ToolbarHyperlinkButton(props) {
3543
3481
  case 2:
3544
3482
  if (isActive) {
3545
3483
  unwrapLink(editor);
3484
+ editor.tracking.onToolbarAction('unlinkHyperlinks');
3546
3485
  } else {
3547
- addOrEditLink(editor, sdk);
3486
+ addOrEditLink(editor, sdk, editor.tracking.onToolbarAction);
3548
3487
  }
3549
3488
 
3550
3489
  case 3:
@@ -3593,8 +3532,9 @@ var buildHyperlinkEventHandler = function buildHyperlinkEventHandler(sdk) {
3593
3532
 
3594
3533
  if (isLinkActive(editor)) {
3595
3534
  unwrapLink(editor);
3535
+ editor.tracking.onShortcutAction('unlinkHyperlinks');
3596
3536
  } else {
3597
- addOrEditLink(editor, sdk);
3537
+ addOrEditLink(editor, sdk, editor.tracking.onShortcutAction);
3598
3538
  }
3599
3539
  };
3600
3540
  };
@@ -3620,7 +3560,7 @@ var getNodeOfType = function getNodeOfType(type) {
3620
3560
  };
3621
3561
  };
3622
3562
 
3623
- var createHyperlinkPlugin = function createHyperlinkPlugin(sdk, tracking) {
3563
+ var createHyperlinkPlugin = function createHyperlinkPlugin(sdk) {
3624
3564
  var common = {
3625
3565
  isElement: true,
3626
3566
  isInline: true
@@ -3651,7 +3591,7 @@ var createHyperlinkPlugin = function createHyperlinkPlugin(sdk, tracking) {
3651
3591
  _extends({}, common, {
3652
3592
  key: INLINES.ENTRY_HYPERLINK,
3653
3593
  type: INLINES.ENTRY_HYPERLINK,
3654
- component: withLinkTracking(tracking, EntityHyperlink),
3594
+ component: withLinkTracking(EntityHyperlink),
3655
3595
  deserializeHtml: {
3656
3596
  rules: [{
3657
3597
  validNodeName: ['A']
@@ -3665,7 +3605,7 @@ var createHyperlinkPlugin = function createHyperlinkPlugin(sdk, tracking) {
3665
3605
  _extends({}, common, {
3666
3606
  key: INLINES.ASSET_HYPERLINK,
3667
3607
  type: INLINES.ASSET_HYPERLINK,
3668
- component: withLinkTracking(tracking, EntityHyperlink),
3608
+ component: withLinkTracking(EntityHyperlink),
3669
3609
  deserializeHtml: {
3670
3610
  rules: [{
3671
3611
  validNodeName: ['A']
@@ -4139,6 +4079,7 @@ var createListPlugin = function createListPlugin() {
4139
4079
  }, _overrideByKey[ELEMENT_LI] = {
4140
4080
  type: BLOCKS.LIST_ITEM,
4141
4081
  component: ListItem,
4082
+ // @ts-expect-error
4142
4083
  normalizer: [{
4143
4084
  validNode: hasListAsDirectParent,
4144
4085
  transform: normalizeOrphanedListItem
@@ -4191,26 +4132,62 @@ function ToolbarListButton(props) {
4191
4132
  }, /*#__PURE__*/createElement(ListNumberedIcon, null)));
4192
4133
  }
4193
4134
 
4194
- function ToolbarBoldButton(props) {
4195
- var editor = useContentfulEditor();
4135
+ var createMarkToolbarButton = function createMarkToolbarButton(_ref) {
4136
+ var mark = _ref.mark,
4137
+ title = _ref.title,
4138
+ icon = _ref.icon;
4196
4139
 
4197
- function handleClick() {
4198
- if (!(editor != null && editor.selection)) return;
4199
- toggleMark(editor, {
4200
- key: MARKS.BOLD
4201
- });
4202
- focus(editor);
4203
- }
4140
+ var Mark = function Mark(_ref2) {
4141
+ var isDisabled = _ref2.isDisabled;
4142
+ var editor = useContentfulEditor();
4143
+ var handleClick = useCallback(function () {
4144
+ if (!(editor != null && editor.selection)) return;
4145
+ var isActive = isMarkActive(editor, mark);
4146
+ editor.tracking.onToolbarAction(isActive ? 'unmark' : 'mark', {
4147
+ markType: mark
4148
+ });
4149
+ toggleMark(editor, {
4150
+ key: mark
4151
+ });
4152
+ focus(editor);
4153
+ }, [editor]);
4154
+ if (!editor) return null;
4155
+ return /*#__PURE__*/createElement(ToolbarButton, {
4156
+ title: title,
4157
+ testId: mark + "-toolbar-button",
4158
+ onClick: handleClick,
4159
+ isActive: isMarkActive(editor, mark),
4160
+ isDisabled: isDisabled
4161
+ }, icon);
4162
+ };
4204
4163
 
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
- }
4164
+ Mark.displayName = mark;
4165
+ return Mark;
4166
+ };
4167
+
4168
+ var buildMarkEventHandler = function buildMarkEventHandler(type) {
4169
+ return function (editor, _ref) {
4170
+ var hotkey = _ref.options.hotkey;
4171
+ return function (event) {
4172
+ if (editor.selection && hotkey && isHotkey(hotkey, event)) {
4173
+ event.preventDefault();
4174
+ var isActive = isMarkActive(editor, type);
4175
+ editor.tracking.onShortcutAction(isActive ? 'unmark' : 'mark', {
4176
+ markType: type
4177
+ });
4178
+ toggleMark(editor, {
4179
+ key: type
4180
+ });
4181
+ }
4182
+ };
4183
+ };
4184
+ };
4185
+
4186
+ var ToolbarBoldButton = /*#__PURE__*/createMarkToolbarButton({
4187
+ title: 'Bold',
4188
+ mark: MARKS.BOLD,
4189
+ icon: /*#__PURE__*/createElement(FormatBoldIcon, null)
4190
+ });
4214
4191
  var styles$e = {
4215
4192
  bold: /*#__PURE__*/css({
4216
4193
  fontWeight: 600
@@ -4233,6 +4210,9 @@ var createBoldPlugin = function createBoldPlugin() {
4233
4210
  options: {
4234
4211
  hotkey: ['mod+b']
4235
4212
  },
4213
+ handlers: {
4214
+ onKeyDown: buildMarkEventHandler(MARKS.BOLD)
4215
+ },
4236
4216
  deserializeHtml: {
4237
4217
  rules: [{
4238
4218
  validNodeName: ['STRONG', 'B']
@@ -4250,26 +4230,11 @@ var createBoldPlugin = function createBoldPlugin() {
4250
4230
  });
4251
4231
  };
4252
4232
 
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
- }
4233
+ var ToolbarCodeButton = /*#__PURE__*/createMarkToolbarButton({
4234
+ title: 'Code',
4235
+ mark: MARKS.CODE,
4236
+ icon: /*#__PURE__*/createElement(CodeIcon, null)
4237
+ });
4273
4238
  var styles$f = {
4274
4239
  code: /*#__PURE__*/css({
4275
4240
  fontFamily: 'monospace',
@@ -4288,6 +4253,9 @@ var createCodePlugin = function createCodePlugin() {
4288
4253
  options: {
4289
4254
  hotkey: ['mod+/']
4290
4255
  },
4256
+ handlers: {
4257
+ onKeyDown: buildMarkEventHandler(MARKS.CODE)
4258
+ },
4291
4259
  deserializeHtml: {
4292
4260
  rules: [{
4293
4261
  validNodeName: ['CODE', 'PRE']
@@ -4300,26 +4268,11 @@ var createCodePlugin = function createCodePlugin() {
4300
4268
  });
4301
4269
  };
4302
4270
 
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
- }
4271
+ var ToolbarItalicButton = /*#__PURE__*/createMarkToolbarButton({
4272
+ title: 'Italic',
4273
+ mark: MARKS.ITALIC,
4274
+ icon: /*#__PURE__*/createElement(FormatItalicIcon, null)
4275
+ });
4323
4276
  var styles$g = {
4324
4277
  italic: /*#__PURE__*/css({
4325
4278
  fontStyle: 'italic'
@@ -4337,6 +4290,9 @@ var createItalicPlugin = function createItalicPlugin() {
4337
4290
  options: {
4338
4291
  hotkey: ['mod+i']
4339
4292
  },
4293
+ handlers: {
4294
+ onKeyDown: buildMarkEventHandler(MARKS.ITALIC)
4295
+ },
4340
4296
  deserializeHtml: {
4341
4297
  rules: [{
4342
4298
  validNodeName: ['I', 'EM']
@@ -4354,26 +4310,11 @@ var createItalicPlugin = function createItalicPlugin() {
4354
4310
  });
4355
4311
  };
4356
4312
 
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
- }
4313
+ var ToolbarUnderlineButton = /*#__PURE__*/createMarkToolbarButton({
4314
+ title: 'Underline',
4315
+ mark: MARKS.UNDERLINE,
4316
+ icon: /*#__PURE__*/createElement(FormatUnderlinedIcon, null)
4317
+ });
4377
4318
  function Underline(props) {
4378
4319
  return /*#__PURE__*/createElement("u", Object.assign({}, props.attributes), props.children);
4379
4320
  }
@@ -4384,6 +4325,9 @@ var createUnderlinePlugin = function createUnderlinePlugin() {
4384
4325
  options: {
4385
4326
  hotkey: ['mod+u']
4386
4327
  },
4328
+ handlers: {
4329
+ onKeyDown: buildMarkEventHandler(MARKS.UNDERLINE)
4330
+ },
4387
4331
  deserializeHtml: {
4388
4332
  rules: [{
4389
4333
  validNodeName: ['U']
@@ -4606,6 +4550,7 @@ var withNormalizer = function withNormalizer(editor) {
4606
4550
  var createNormalizerPlugin = function createNormalizerPlugin() {
4607
4551
  return {
4608
4552
  key: 'NormalizerPlugin',
4553
+ // @ts-expect-error
4609
4554
  withOverrides: withNormalizer
4610
4555
  };
4611
4556
  };
@@ -4783,9 +4728,12 @@ function Quote(props) {
4783
4728
  }), props.children);
4784
4729
  }
4785
4730
 
4786
- function toggleQuote(editor) {
4731
+ function toggleQuote(editor, logAction) {
4787
4732
  if (!editor.selection) return;
4788
4733
  var isActive = isBlockSelected(editor, BLOCKS.QUOTE);
4734
+ logAction(isActive ? 'remove' : 'insert', {
4735
+ nodeType: BLOCKS.QUOTE
4736
+ });
4789
4737
  Editor.withoutNormalizing(editor, function () {
4790
4738
  if (!editor.selection) return;
4791
4739
  Transforms.unwrapNodes(editor, {
@@ -4817,7 +4765,7 @@ var onKeyDownToggleQuote = function onKeyDownToggleQuote(editor, plugin) {
4817
4765
 
4818
4766
  if (hotkey && isHotkey(hotkey, event)) {
4819
4767
  event.preventDefault();
4820
- toggleQuote(editor);
4768
+ toggleQuote(editor, editor.tracking.onShortcutAction);
4821
4769
  }
4822
4770
  };
4823
4771
  };
@@ -4844,7 +4792,54 @@ function createQuotePlugin() {
4844
4792
  normalizer: [{
4845
4793
  validChildren: CONTAINERS[BLOCKS.QUOTE],
4846
4794
  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
- }]
4795
+ }],
4796
+ withOverrides: function withOverrides(editor) {
4797
+ var insertFragment = editor.insertFragment;
4798
+
4799
+ editor.insertFragment = function (fragment) {
4800
+ var startingNode = fragment.length && fragment[0];
4801
+ var startsWithBlockquote = Element.isElement(startingNode) && startingNode.type === BLOCKS.QUOTE;
4802
+ var containerEntry = getAbove(editor, {
4803
+ match: {
4804
+ type: TEXT_CONTAINERS
4805
+ }
4806
+ });
4807
+ var containerIsNotEmpty = containerEntry && Node.string(containerEntry[0]) !== '';
4808
+
4809
+ if (startsWithBlockquote && containerIsNotEmpty) {
4810
+ var selection = editor.selection;
4811
+
4812
+ var isContentSelected = function isContentSelected(selection) {
4813
+ return !!selection && Point.compare(selection.anchor, selection.focus) !== 0;
4814
+ }; // if something is selected (highlighted) we replace the selection
4815
+
4816
+
4817
+ if (isContentSelected(selection)) {
4818
+ Transforms["delete"](editor, {
4819
+ at: selection
4820
+ });
4821
+ } // get the cursor entry again, it may be different after deletion
4822
+
4823
+
4824
+ var _containerEntry = getAbove(editor, {
4825
+ match: {
4826
+ type: TEXT_CONTAINERS
4827
+ }
4828
+ });
4829
+
4830
+ var _containerIsNotEmpty = _containerEntry && Node.string(_containerEntry[0]) !== '';
4831
+
4832
+ if (_containerIsNotEmpty) {
4833
+ Transforms.insertNodes(editor, fragment);
4834
+ return;
4835
+ }
4836
+ }
4837
+
4838
+ insertFragment(fragment);
4839
+ };
4840
+
4841
+ return editor;
4842
+ }
4848
4843
  };
4849
4844
  }
4850
4845
 
@@ -4853,7 +4848,7 @@ function ToolbarQuoteButton(props) {
4853
4848
 
4854
4849
  function handleOnClick() {
4855
4850
  if (!editor) return;
4856
- toggleQuote(editor);
4851
+ toggleQuote(editor, editor.tracking.onToolbarAction);
4857
4852
  focus(editor);
4858
4853
  }
4859
4854
 
@@ -4902,8 +4897,7 @@ function hasHeadersOutsideFirstRow(nodes) {
4902
4897
  });
4903
4898
  }
4904
4899
 
4905
- function addTableTrackingEvents(editor, _ref6) {
4906
- var onViewportAction = _ref6.onViewportAction;
4900
+ function addTableTrackingEvents(editor) {
4907
4901
  var insertData = editor.insertData;
4908
4902
 
4909
4903
  editor.insertData = function (data) {
@@ -4917,7 +4911,7 @@ function addTableTrackingEvents(editor, _ref6) {
4917
4911
  if (hasTables(markupBefore)) return;
4918
4912
 
4919
4913
  if (hasTables(markupAfter)) {
4920
- onViewportAction('paste', {
4914
+ editor.tracking.onViewportAction('paste', {
4921
4915
  tablePasted: true,
4922
4916
  hasHeadersOutsideFirstRow: hasHeadersOutsideFirstRow(markupAfter)
4923
4917
  });
@@ -4929,29 +4923,6 @@ function addTableTrackingEvents(editor, _ref6) {
4929
4923
  };
4930
4924
  }
4931
4925
 
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
4926
  var addRow = function addRow(editor, getNextRowPath) {
4956
4927
  if (someNode(editor, {
4957
4928
  match: {
@@ -5197,9 +5168,6 @@ var TableActions = function TableActions() {
5197
5168
  var editor = useContentfulEditor();
5198
5169
  var isDisabled = useReadOnly();
5199
5170
 
5200
- var _useTrackingContext = useTrackingContext(),
5201
- onViewportAction = _useTrackingContext.onViewportAction;
5202
-
5203
5171
  var _React$useState = React__default.useState(false),
5204
5172
  isOpen = _React$useState[0],
5205
5173
  setOpen = _React$useState[1];
@@ -5249,11 +5217,11 @@ var TableActions = function TableActions() {
5249
5217
  }); // Tracking
5250
5218
 
5251
5219
  var actionName = type + "Table" + (element === 'Table' ? '' : element);
5252
- onViewportAction(actionName, {
5220
+ editor.tracking.onViewportAction(actionName, {
5253
5221
  tableSize: tableSize
5254
5222
  });
5255
5223
  };
5256
- }, [editor, isHeaderEnabled, close, onViewportAction]);
5224
+ }, [editor, isHeaderEnabled, close]);
5257
5225
 
5258
5226
  if (isDisabled) {
5259
5227
  return null;
@@ -5344,7 +5312,7 @@ var createTableOnKeyDown = function createTableOnKeyDown(editor, plugin) {
5344
5312
  };
5345
5313
  };
5346
5314
 
5347
- var createTablePlugin = function createTablePlugin(tracking) {
5315
+ var createTablePlugin = function createTablePlugin() {
5348
5316
  var _overrideByKey;
5349
5317
 
5350
5318
  return createTablePlugin$1({
@@ -5353,7 +5321,7 @@ var createTablePlugin = function createTablePlugin(tracking) {
5353
5321
  onKeyDown: createTableOnKeyDown
5354
5322
  },
5355
5323
  withOverrides: function withOverrides(editor) {
5356
- addTableTrackingEvents(editor, tracking);
5324
+ addTableTrackingEvents(editor);
5357
5325
  var insertFragment = editor.insertFragment;
5358
5326
 
5359
5327
  editor.insertFragment = function (fragments) {
@@ -5453,10 +5421,6 @@ var createTablePlugin = function createTablePlugin(tracking) {
5453
5421
 
5454
5422
  function ToolbarTableButton(props) {
5455
5423
  var editor = useContentfulEditor();
5456
-
5457
- var _useTrackingContext = useTrackingContext(),
5458
- onViewportAction = _useTrackingContext.onViewportAction;
5459
-
5460
5424
  var isActive = editor && isTableActive(editor);
5461
5425
 
5462
5426
  function handleClick() {
@@ -5477,7 +5441,7 @@ function ToolbarTableButton(props) {
5477
5441
  return _context.abrupt("return");
5478
5442
 
5479
5443
  case 2:
5480
- onViewportAction('insertTable');
5444
+ editor.tracking.onToolbarAction('insertTable');
5481
5445
  insertTableAndFocusFirstCell(editor);
5482
5446
  focus(editor);
5483
5447
 
@@ -5582,35 +5546,199 @@ function deleteEmptyParagraph(unit, editor, deleteFunction) {
5582
5546
  }
5583
5547
  }
5584
5548
 
5585
- var createTrailingParagraphPlugin = function createTrailingParagraphPlugin() {
5586
- return createTrailingBlockPlugin({
5587
- options: {
5588
- type: BLOCKS.PARAGRAPH,
5589
- level: 0
5549
+ var _extends2, _extends4, _inlines;
5550
+ var inlines = /*#__PURE__*/Object.values(INLINES).map(function (type) {
5551
+ return {
5552
+ type: type
5553
+ };
5554
+ });
5555
+ var schema = {
5556
+ document: {
5557
+ nodes: [{
5558
+ types: /*#__PURE__*/TOP_LEVEL_BLOCKS.map(function (type) {
5559
+ return {
5560
+ type: type
5561
+ };
5562
+ })
5563
+ }]
5564
+ },
5565
+ blocks: /*#__PURE__*/_extends((_extends2 = {}, _extends2[BLOCKS.PARAGRAPH] = {
5566
+ nodes: [{
5567
+ match: /*#__PURE__*/[].concat(inlines, [{
5568
+ object: 'text'
5569
+ }])
5570
+ }]
5571
+ }, _extends2[BLOCKS.HEADING_1] = {
5572
+ nodes: [{
5573
+ match: /*#__PURE__*/[].concat(inlines, [{
5574
+ object: 'text'
5575
+ }])
5576
+ }]
5577
+ }, _extends2[BLOCKS.HEADING_2] = {
5578
+ nodes: [{
5579
+ match: /*#__PURE__*/[].concat(inlines, [{
5580
+ object: 'text'
5581
+ }])
5582
+ }]
5583
+ }, _extends2[BLOCKS.HEADING_3] = {
5584
+ nodes: [{
5585
+ match: /*#__PURE__*/[].concat(inlines, [{
5586
+ object: 'text'
5587
+ }])
5588
+ }]
5589
+ }, _extends2[BLOCKS.HEADING_4] = {
5590
+ nodes: [{
5591
+ match: /*#__PURE__*/[].concat(inlines, [{
5592
+ object: 'text'
5593
+ }])
5594
+ }]
5595
+ }, _extends2[BLOCKS.HEADING_5] = {
5596
+ nodes: [{
5597
+ match: /*#__PURE__*/[].concat(inlines, [{
5598
+ object: 'text'
5599
+ }])
5600
+ }]
5601
+ }, _extends2[BLOCKS.HEADING_6] = {
5602
+ nodes: [{
5603
+ match: /*#__PURE__*/[].concat(inlines, [{
5604
+ object: 'text'
5605
+ }])
5606
+ }]
5607
+ }, _extends2), /*#__PURE__*/VOID_BLOCKS.reduce(function (blocks, nodeType) {
5608
+ var _extends3;
5609
+
5610
+ return _extends({}, blocks, (_extends3 = {}, _extends3[nodeType] = {
5611
+ isVoid: true
5612
+ }, _extends3));
5613
+ }, {}), (_extends4 = {}, _extends4[BLOCKS.QUOTE] = {
5614
+ nodes: [{
5615
+ match: [/*#__PURE__*/CONTAINERS[BLOCKS.QUOTE].map(function (type) {
5616
+ return {
5617
+ type: type
5618
+ };
5619
+ })],
5620
+ min: 1
5621
+ }],
5622
+ normalize: function normalize(editor, error) {
5623
+ if (error.code === 'child_type_invalid') {
5624
+ return editor.unwrapBlockByKey(error.node.key, BLOCKS.QUOTE);
5625
+ }
5590
5626
  }
5627
+ }, _extends4)),
5628
+ inlines: (_inlines = {}, _inlines[INLINES.HYPERLINK] = {
5629
+ nodes: [{
5630
+ match: [{
5631
+ object: 'text'
5632
+ }]
5633
+ }]
5634
+ }, _inlines[INLINES.ENTRY_HYPERLINK] = {
5635
+ nodes: [{
5636
+ match: [{
5637
+ object: 'text'
5638
+ }]
5639
+ }]
5640
+ }, _inlines[INLINES.ASSET_HYPERLINK] = {
5641
+ nodes: [{
5642
+ match: [{
5643
+ object: 'text'
5644
+ }]
5645
+ }]
5646
+ }, _inlines[INLINES.EMBEDDED_ENTRY] = {
5647
+ isVoid: true
5648
+ }, _inlines)
5649
+ };
5650
+
5651
+ function getCharacterCount(editor) {
5652
+ var document = toContentfulDocument({
5653
+ document: editor.children,
5654
+ schema: schema
5591
5655
  });
5656
+ return documentToPlainTextString(document).length;
5657
+ }
5658
+
5659
+ var actionOrigin = {
5660
+ TOOLBAR: 'toolbar-icon',
5661
+ SHORTCUT: 'shortcut',
5662
+ VIEWPORT: 'viewport-interaction',
5663
+ COMMAND_PALETTE: 'command-palette'
5592
5664
  };
5665
+ var createTrackingPlugin = function createTrackingPlugin(onAction) {
5666
+ var trackingActions = {
5667
+ onViewportAction: function onViewportAction(actionName, data) {
5668
+ if (data === void 0) {
5669
+ data = {};
5670
+ }
5593
5671
 
5594
- /**
5595
- * Re-creates a void node with valid children.
5596
- */
5672
+ return onAction(actionName, _extends({
5673
+ origin: actionOrigin.VIEWPORT
5674
+ }, data));
5675
+ },
5676
+ onShortcutAction: function onShortcutAction(actionName, data) {
5677
+ if (data === void 0) {
5678
+ data = {};
5679
+ }
5597
5680
 
5598
- var transformVoid = function transformVoid(editor, _ref) {
5599
- var node = _ref[0],
5600
- path = _ref[1];
5681
+ return onAction(actionName, _extends({
5682
+ origin: actionOrigin.SHORTCUT
5683
+ }, data));
5684
+ },
5685
+ onToolbarAction: function onToolbarAction(actionName, data) {
5686
+ if (data === void 0) {
5687
+ data = {};
5688
+ }
5601
5689
 
5602
- var validVoid = _extends({}, node, {
5603
- children: [{
5604
- text: ''
5605
- }]
5606
- }); // A workaround because Slate doesn't allow adjusting void nodes children
5690
+ return onAction(actionName, _extends({
5691
+ origin: actionOrigin.TOOLBAR
5692
+ }, data));
5693
+ },
5694
+ onCommandPaletteAction: function onCommandPaletteAction(actionName, data) {
5695
+ if (data === void 0) {
5696
+ data = {};
5697
+ }
5607
5698
 
5699
+ return onAction(actionName, _extends({
5700
+ origin: actionOrigin.COMMAND_PALETTE
5701
+ }, data));
5702
+ }
5703
+ };
5704
+ return {
5705
+ key: 'TrackingPlugin',
5706
+ withOverrides: function withOverrides(editor) {
5707
+ var insertData = editor.insertData;
5708
+ editor.tracking = trackingActions;
5709
+
5710
+ editor.insertData = function (data) {
5711
+ var isCopyAndPaste = data.types.length !== 0;
5712
+
5713
+ if (isCopyAndPaste) {
5714
+ var _window$getSelection;
5715
+
5716
+ var characterCountSelection = (_window$getSelection = window.getSelection()) == null ? void 0 : _window$getSelection.toString().length;
5717
+ var characterCountBefore = getCharacterCount(editor);
5718
+ setTimeout(function () {
5719
+ var characterCountAfter = getCharacterCount(editor);
5720
+ trackingActions.onShortcutAction('paste', {
5721
+ characterCountAfter: characterCountAfter,
5722
+ characterCountBefore: characterCountBefore,
5723
+ characterCountSelection: characterCountSelection
5724
+ });
5725
+ });
5726
+ }
5608
5727
 
5609
- Transforms.removeNodes(editor, {
5610
- at: path
5611
- });
5612
- Transforms.insertNodes(editor, [validVoid], {
5613
- at: path
5728
+ insertData(data);
5729
+ };
5730
+
5731
+ return editor;
5732
+ }
5733
+ };
5734
+ };
5735
+
5736
+ var createTrailingParagraphPlugin = function createTrailingParagraphPlugin() {
5737
+ return createTrailingBlockPlugin({
5738
+ options: {
5739
+ type: BLOCKS.PARAGRAPH,
5740
+ level: 0
5741
+ }
5614
5742
  });
5615
5743
  };
5616
5744
 
@@ -5642,34 +5770,17 @@ var createVoidsPlugin = function createVoidsPlugin() {
5642
5770
  return !(isRootLevel(path) && isFirstChild(path)) && !!node.isVoid;
5643
5771
  }
5644
5772
  }
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
5773
  }]
5664
5774
  };
5665
5775
  };
5666
5776
 
5667
- var getPlugins = function getPlugins(sdk, tracking) {
5777
+ var getPlugins = function getPlugins(sdk, onAction) {
5668
5778
  return [// AST must come after the HTML deserializer
5669
- createDeserializeHtmlPlugin(), createDeserializeAstPlugin(), createDeserializeDocxPlugin(), // Global shortcuts
5779
+ createDeserializeHtmlPlugin(), createDeserializeAstPlugin(), createDeserializeDocxPlugin(), // Tracking - This should come first so all plugins below will have access to `editor.tracking`
5780
+ createTrackingPlugin(onAction), // Global / Global shortcuts
5670
5781
  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
5782
+ createParagraphPlugin(), createListPlugin(), createHrPlugin(), createHeadingPlugin(), createQuotePlugin(), createTablePlugin(), createEmbeddedEntryBlockPlugin(sdk), createEmbeddedAssetBlockPlugin(sdk), // Inline elements
5783
+ createHyperlinkPlugin(sdk), createEmbeddedEntityInlinePlugin(sdk), // Marks
5673
5784
  createMarksPlugin(), // Other
5674
5785
  createTrailingParagraphPlugin(), createTextPlugin(), createVoidsPlugin(), createSelectOnBackspacePlugin(), // Pasting content from other sources
5675
5786
  createPasteHTMLPlugin(), // These plugins drive their configurations from the list of plugins
@@ -5978,18 +6089,56 @@ var useNormalizedSlateValue = function useNormalizedSlateValue(_ref) {
5978
6089
  }, [id, plugins, incomingDoc]);
5979
6090
  };
5980
6091
 
6092
+ /**
6093
+ * Returns whether a given operation is relevant enough to trigger a save.
6094
+ */
6095
+
6096
+ var isRelevantOperation = function isRelevantOperation(op) {
6097
+ if (op.type === 'set_selection') {
6098
+ return false;
6099
+ }
6100
+
6101
+ return true;
6102
+ };
6103
+
6104
+ var useOnValueChanged = function useOnValueChanged(_ref) {
6105
+ var editor = _ref.editor,
6106
+ handler = _ref.handler;
6107
+ var onChange = useMemo(function () {
6108
+ return debounce(function (document) {
6109
+ handler == null ? void 0 : handler(toContentfulDocument({
6110
+ document: document,
6111
+ schema: schema
6112
+ }));
6113
+ }, 500);
6114
+ }, [handler]);
6115
+ return useCallback(function (value) {
6116
+ var operations = editor.operations.filter(isRelevantOperation);
6117
+
6118
+ if (operations.length > 0) {
6119
+ onChange(value);
6120
+ }
6121
+ }, [editor, onChange]);
6122
+ };
6123
+
5981
6124
  var _excluded = ["sdk", "isInitiallyDisabled", "onAction"];
5982
6125
  var ConnectedRichTextEditor = function ConnectedRichTextEditor(props) {
5983
- var id = getContentfulEditorId(props.sdk);
5984
- var tracking = useTrackingContext();
6126
+ var id = useContentfulEditorId();
6127
+ var editor = useContentfulEditor();
5985
6128
  var plugins = React__default.useMemo(function () {
5986
- return getPlugins(props.sdk, tracking);
5987
- }, [props.sdk, tracking]);
6129
+ var _props$onAction;
6130
+
6131
+ return getPlugins(props.sdk, (_props$onAction = props.onAction) != null ? _props$onAction : noop);
6132
+ }, [props.sdk, props.onAction]);
5988
6133
  var initialValue = useNormalizedSlateValue({
5989
6134
  id: id,
5990
6135
  incomingDoc: props.value,
5991
6136
  plugins: plugins
5992
6137
  });
6138
+ var onValueChanged = useOnValueChanged({
6139
+ editor: editor,
6140
+ handler: props.onChange
6141
+ });
5993
6142
  var classNames = cx(styles$j.editor, props.minHeight !== undefined ? css({
5994
6143
  minHeight: props.minHeight
5995
6144
  }) : undefined, props.isDisabled ? styles$j.disabled : styles$j.enabled, props.isToolbarHidden && styles$j.hiddenToolbar);
@@ -6005,12 +6154,7 @@ var ConnectedRichTextEditor = function ConnectedRichTextEditor(props) {
6005
6154
  className: classNames,
6006
6155
  readOnly: props.isDisabled
6007
6156
  },
6008
- onChange: function onChange(document) {
6009
- props.onChange == null ? void 0 : props.onChange(toContentfulDocument({
6010
- document: document,
6011
- schema: schema
6012
- }));
6013
- }
6157
+ onChange: onValueChanged
6014
6158
  }, !props.isToolbarHidden && /*#__PURE__*/React__default.createElement(StickyToolbarWrapper, {
6015
6159
  isDisabled: props.isDisabled
6016
6160
  }, /*#__PURE__*/React__default.createElement(Toolbar, {
@@ -6027,12 +6171,11 @@ var RichTextEditor = function RichTextEditor(props) {
6027
6171
  var isEmptyValue = useCallback(function (value) {
6028
6172
  return !value || deepEquals(value, EMPTY_DOCUMENT);
6029
6173
  }, []);
6174
+ var editorId = getContentfulEditorId(sdk);
6030
6175
  return /*#__PURE__*/React__default.createElement(EntityProvider, {
6031
6176
  sdk: sdk
6032
6177
  }, /*#__PURE__*/React__default.createElement(SdkProvider, {
6033
6178
  sdk: sdk
6034
- }, /*#__PURE__*/React__default.createElement(TrackingProvider, {
6035
- onAction: onAction || noop
6036
6179
  }, /*#__PURE__*/React__default.createElement(FieldConnector, {
6037
6180
  throttle: 0,
6038
6181
  field: sdk.field,
@@ -6044,17 +6187,17 @@ var RichTextEditor = function RichTextEditor(props) {
6044
6187
  disabled = _ref.disabled,
6045
6188
  setValue = _ref.setValue,
6046
6189
  externalReset = _ref.externalReset;
6047
- return /*#__PURE__*/React__default.createElement(ContentfulEditorProvider, {
6048
- sdk: sdk
6190
+ return /*#__PURE__*/React__default.createElement(ContentfulEditorIdProvider, {
6191
+ value: editorId
6049
6192
  }, /*#__PURE__*/React__default.createElement(ConnectedRichTextEditor, Object.assign({}, otherProps, {
6050
6193
  key: "rich-text-editor-" + externalReset,
6051
6194
  value: lastRemoteValue,
6052
6195
  sdk: sdk,
6053
- onAction: onAction || noop,
6196
+ onAction: onAction,
6054
6197
  isDisabled: disabled,
6055
6198
  onChange: setValue
6056
6199
  })));
6057
- }))));
6200
+ })));
6058
6201
  };
6059
6202
 
6060
6203
  var LINK_TYPES$1 = {