@contentful/field-editor-rich-text 2.0.0-next.20 → 2.0.0-next.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
1
  import React__default, { createContext, useContext, useMemo, createElement, useEffect, useState, memo, Fragment, useCallback } from 'react';
2
- import { useEntities, ScheduledIconWithTooltip, MissingEntityCard, AssetThumbnail, getScheduleTooltipContent, EntityProvider } from '@contentful/field-editor-reference';
2
+ import { useEntities, ScheduledIconWithTooltip, MissingEntityCard, AssetThumbnail, EntityProvider, getScheduleTooltipContent } from '@contentful/field-editor-reference';
3
3
  import { entityHelpers, shortenStorageUnit, isValidImage, ModalDialogLauncher, FieldConnector } from '@contentful/field-editor-shared';
4
4
  import { BLOCKS, INLINES, TABLE_BLOCKS, TEXT_CONTAINERS, HEADINGS, LIST_ITEM_BLOCKS, MARKS, CONTAINERS, TOP_LEVEL_BLOCKS, VOID_BLOCKS, EMPTY_DOCUMENT } from '@contentful/rich-text-types';
5
- import { usePlateEditorState, usePlateEditorRef, getNodes, toggleNodeType, getText, getAbove, setNodes, isAncestorEmpty, getParent, getBlockAbove, isSelectionAtBlockStart, isSelectionAtBlockEnd, isFirstChild, insertNodes, moveChildren, isBlockAboveEmpty, mockPlugin, getPluginType, ELEMENT_DEFAULT, findNode, unwrapNodes, deleteFragment, isCollapsed, isRangeAcrossBlocks, wrapNodes, isMarkActive, toggleMark, someHtmlElement, match, KEY_DESERIALIZE_HTML, hasSingleChild, isLastChild, someNode, getChildren as getChildren$1, getLastChildPath, createDeserializeHtmlPlugin, createDeserializeAstPlugin, createPlateEditor, getPlateActions, Plate } from '@udecode/plate-core';
5
+ import { usePlateEditorRef, usePlateEditorState, getNodes, toggleNodeType, getText, getAbove, setNodes, isAncestorEmpty, match, getLastChildPath, wrapNodes, getPluginType, unwrapNodes, isCollapsed, isRangeAcrossBlocks, ELEMENT_DEFAULT, findNode, getParent, getBlockAbove, isSelectionAtBlockStart, isSelectionAtBlockEnd, isFirstChild, insertNodes, moveChildren, isBlockAboveEmpty, mockPlugin, deleteFragment, isMarkActive, toggleMark, someHtmlElement, KEY_DESERIALIZE_HTML, hasSingleChild, isLastChild, someNode, getChildren as getChildren$1, createDeserializeHtmlPlugin, createDeserializeAstPlugin, createPlateEditor, getPlateSelectors, getPlateActions, Plate } from '@udecode/plate-core';
6
6
  import { css, cx } from 'emotion';
7
7
  import deepEquals from 'fast-deep-equal';
8
8
  import noop from 'lodash-es/noop';
@@ -20,7 +20,8 @@ import { ClockIcon, AssetIcon, EmbeddedEntryBlockIcon, EmbeddedEntryInlineIcon,
20
20
  import tokens from '@contentful/f36-tokens';
21
21
  import find from 'lodash-es/find';
22
22
  import flow from 'lodash-es/flow';
23
- import { getListItemEntry, moveListItemUp, ELEMENT_LI, unwrapList as unwrapList$1, removeFirstListItem, removeListItem, isListNested, deleteForwardList, deleteFragmentList, normalizeList, createListPlugin as createListPlugin$1, ELEMENT_UL, ELEMENT_OL, ELEMENT_LIC } from '@udecode/plate-list';
23
+ import { getListTypes, ELEMENT_LIC, getListItemEntry, isListNested, moveListItemUp, ELEMENT_LI, unwrapList as unwrapList$1, removeFirstListItem, removeListItem, deleteForwardList, deleteFragmentList, normalizeList, createListPlugin as createListPlugin$1, ELEMENT_UL, ELEMENT_OL } from '@udecode/plate-list';
24
+ import castArray from 'lodash-es/castArray';
24
25
  import { createBoldPlugin as createBoldPlugin$1, createCodePlugin as createCodePlugin$1, createItalicPlugin as createItalicPlugin$1, createUnderlinePlugin as createUnderlinePlugin$1 } from '@udecode/plate-basic-marks';
25
26
  import isPlainObject from 'is-plain-obj';
26
27
  import { createParagraphPlugin as createParagraphPlugin$1 } from '@udecode/plate-paragraph';
@@ -944,14 +945,22 @@ function FetchingWrappedEntryCard(props) {
944
945
  var onEntityFetchComplete = props.onEntityFetchComplete;
945
946
  useEffect(function () {
946
947
  if (!entry || entry === 'failed') return;
948
+ var subscribed = true;
947
949
  entityHelpers.getEntryImage({
948
950
  entry: entry,
949
951
  contentType: contentType,
950
952
  localeCode: props.locale,
951
953
  defaultLocaleCode: defaultLocaleCode
952
- }, getOrLoadAsset).then(setFile)["catch"](function () {
953
- return setFile(null);
954
+ }, getOrLoadAsset)["catch"](function () {
955
+ return null;
956
+ }).then(function (file) {
957
+ if (subscribed) {
958
+ setFile(file);
959
+ }
954
960
  });
961
+ return function () {
962
+ subscribed = false;
963
+ };
955
964
  }, [entry, contentType, props.locale, defaultLocaleCode, props.sdk, file, getOrLoadAsset]);
956
965
  useEffect(function () {
957
966
  getOrLoadEntry(props.entryId);
@@ -1046,7 +1055,11 @@ function FetchingWrappedEntryCard(props) {
1046
1055
 
1047
1056
  var styles$3 = {
1048
1057
  root: /*#__PURE__*/css({
1049
- marginBottom: '1.25rem !important'
1058
+ marginBottom: '1.25rem !important',
1059
+ // The next 2 properties ensure Entity card won't be aligned above
1060
+ // a list item marker (i.e. bullet)
1061
+ display: 'inline-block',
1062
+ verticalAlign: 'text-top'
1050
1063
  })
1051
1064
  };
1052
1065
  function LinkedEntityBlock(props) {
@@ -2270,15 +2283,7 @@ function FetchingWrappedInlineEntryCard(props) {
2270
2283
  return /*#__PURE__*/React__default.createElement(InlineEntryCard, {
2271
2284
  testId: INLINES.EMBEDDED_ENTRY,
2272
2285
  isSelected: props.isSelected,
2273
- title: /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement("span", null, contentTypeName, " ", title), /*#__PURE__*/React__default.createElement(ScheduledIconWithTooltip, {
2274
- getEntityScheduledActions: loadEntityScheduledActions,
2275
- entityType: "Entry",
2276
- entityId: entry.sys.id
2277
- }, /*#__PURE__*/React__default.createElement(ClockIcon, {
2278
- className: styles$5.scheduledIcon,
2279
- variant: "muted",
2280
- testId: "scheduled-icon"
2281
- }))),
2286
+ title: contentTypeName + ": " + title,
2282
2287
  status: status,
2283
2288
  actions: [/*#__PURE__*/React__default.createElement(MenuItem, {
2284
2289
  key: "edit",
@@ -2290,7 +2295,15 @@ function FetchingWrappedInlineEntryCard(props) {
2290
2295
  disabled: props.isDisabled,
2291
2296
  testId: "card-action-remove"
2292
2297
  }, "Remove")]
2293
- });
2298
+ }, /*#__PURE__*/React__default.createElement(ScheduledIconWithTooltip, {
2299
+ getEntityScheduledActions: loadEntityScheduledActions,
2300
+ entityType: "Entry",
2301
+ entityId: entry.sys.id
2302
+ }, /*#__PURE__*/React__default.createElement(ClockIcon, {
2303
+ className: styles$5.scheduledIcon,
2304
+ variant: "muted",
2305
+ testId: "scheduled-icon"
2306
+ })), /*#__PURE__*/React__default.createElement(Text$1, null, title));
2294
2307
  }
2295
2308
 
2296
2309
  function createInlineEntryNode(id) {
@@ -2972,159 +2985,6 @@ var createHrPlugin = function createHrPlugin() {
2972
2985
  };
2973
2986
  };
2974
2987
 
2975
- function truncate(str, length) {
2976
- if (typeof str === 'string' && str.length > length) {
2977
- return str && str.substr(0, length + 1) // +1 to look ahead and be replaced below.
2978
- // Get rid of orphan letters but not one letter words (I, a, 2).
2979
- // Try to not have “.” as last character to avoid awkward “....”.
2980
- .replace(/(\s+\S(?=\S)|\s*)\.?.$/, '…');
2981
- }
2982
-
2983
- return str;
2984
- }
2985
-
2986
- function getEntityInfo(_ref) {
2987
- var entityTitle = _ref.entityTitle,
2988
- entityStatus = _ref.entityStatus,
2989
- contentTypeName = _ref.contentTypeName;
2990
- var title = truncate(entityTitle, 60) || 'Untitled';
2991
- return (contentTypeName || 'Asset') + " \"" + title + "\", " + entityStatus;
2992
- }
2993
-
2994
- function EntryAssetTooltip(_ref2) {
2995
- var id = _ref2.id,
2996
- type = _ref2.type,
2997
- sdk = _ref2.sdk;
2998
-
2999
- var _React$useState = useState(''),
3000
- entityTitle = _React$useState[0],
3001
- setEntityTitle = _React$useState[1];
3002
-
3003
- var _React$useState2 = useState(''),
3004
- entityStatus = _React$useState2[0],
3005
- setEntityStatus = _React$useState2[1];
3006
-
3007
- var _React$useState3 = useState([]),
3008
- jobs = _React$useState3[0],
3009
- setJobs = _React$useState3[1];
3010
-
3011
- var _React$useState4 = useState(true),
3012
- isLoading = _React$useState4[0],
3013
- setIsLoading = _React$useState4[1];
3014
-
3015
- var _React$useState5 = useState(false),
3016
- hasError = _React$useState5[0],
3017
- setHasError = _React$useState5[1];
3018
-
3019
- useEffect(function () {
3020
- function loadContent() {
3021
- return _loadContent.apply(this, arguments);
3022
- }
3023
-
3024
- function _loadContent() {
3025
- _loadContent = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee() {
3026
- var actions, contentType, entity, contentTypeId, contentTypes, _entityTitle, _jobs, _entityStatus;
3027
-
3028
- return runtime_1.wrap(function _callee$(_context) {
3029
- while (1) {
3030
- switch (_context.prev = _context.next) {
3031
- case 0:
3032
- _context.prev = 0;
3033
- setIsLoading(true);
3034
- setHasError(false);
3035
- actions = {
3036
- Asset: {
3037
- getEntity: sdk.space.getAsset,
3038
- getEntityTitle: function getEntityTitle(args) {
3039
- return entityHelpers.getAssetTitle(_extends({}, args, {
3040
- asset: args.entity
3041
- }));
3042
- }
3043
- },
3044
- Entry: {
3045
- getEntity: sdk.space.getEntry,
3046
- getEntityTitle: function getEntityTitle(args) {
3047
- return entityHelpers.getEntryTitle(_extends({}, args, {
3048
- entry: args.entity
3049
- }));
3050
- }
3051
- }
3052
- };
3053
- _context.next = 6;
3054
- return actions[type].getEntity(id);
3055
-
3056
- case 6:
3057
- entity = _context.sent;
3058
-
3059
- if (entity.sys.contentType) {
3060
- contentTypeId = entity.sys.contentType.sys.id;
3061
- contentTypes = sdk.space.getCachedContentTypes();
3062
- contentType = contentTypes.find(function (ct) {
3063
- return ct.sys.id === contentTypeId;
3064
- });
3065
- }
3066
-
3067
- _entityTitle = actions[type].getEntityTitle({
3068
- entity: entity,
3069
- contentType: contentType,
3070
- localeCode: sdk.field.locale,
3071
- defaultLocaleCode: sdk.locales["default"],
3072
- entityType: type
3073
- });
3074
- _context.next = 11;
3075
- return sdk.space.getEntityScheduledActions(type, id);
3076
-
3077
- case 11:
3078
- _jobs = _context.sent;
3079
- _entityStatus = entityHelpers.getEntryStatus(entity.sys);
3080
- setEntityTitle(_entityTitle);
3081
- setEntityStatus(_entityStatus);
3082
- setJobs(_jobs);
3083
- _context.next = 22;
3084
- break;
3085
-
3086
- case 18:
3087
- _context.prev = 18;
3088
- _context.t0 = _context["catch"](0);
3089
- console.log(_context.t0);
3090
- setHasError(true);
3091
-
3092
- case 22:
3093
- _context.prev = 22;
3094
- setIsLoading(false);
3095
- return _context.finish(22);
3096
-
3097
- case 25:
3098
- case "end":
3099
- return _context.stop();
3100
- }
3101
- }
3102
- }, _callee, null, [[0, 18, 22, 25]]);
3103
- }));
3104
- return _loadContent.apply(this, arguments);
3105
- }
3106
-
3107
- loadContent();
3108
- }, [id, type, sdk]);
3109
-
3110
- if (isLoading) {
3111
- return /*#__PURE__*/createElement(Fragment, null, "Loading " + type.toLowerCase() + "...");
3112
- }
3113
-
3114
- if (hasError) {
3115
- return /*#__PURE__*/createElement(Fragment, null, type + " missing or inaccessible");
3116
- }
3117
-
3118
- return /*#__PURE__*/createElement(Fragment, null, getEntityInfo({
3119
- entityTitle: entityTitle,
3120
- contentTypeName: type,
3121
- entityStatus: entityStatus
3122
- }), ' ', jobs.length > 0 ? getScheduleTooltipContent({
3123
- job: jobs[0],
3124
- jobsCount: jobs.length
3125
- }) : '');
3126
- }
3127
-
3128
2988
  var _templateObject$3, _SYS_LINK_TYPES, _LINK_TYPE_SELECTION_;
3129
2989
  var styles$b = {
3130
2990
  removeSelectionLabel: /*#__PURE__*/css(_templateObject$3 || (_templateObject$3 = /*#__PURE__*/_taggedTemplateLiteralLoose(["\n margin-left: ", ";\n "])), tokens.spacingS)
@@ -3436,11 +3296,213 @@ function _addOrEditLink() {
3436
3296
  return _addOrEditLink.apply(this, arguments);
3437
3297
  }
3438
3298
 
3299
+ function ToolbarHyperlinkButton(props) {
3300
+ var editor = useContentfulEditor();
3301
+ var isActive = !!(editor && isLinkActive(editor));
3302
+ var sdk = useSdkContext();
3303
+
3304
+ function handleClick() {
3305
+ return _handleClick.apply(this, arguments);
3306
+ }
3307
+
3308
+ function _handleClick() {
3309
+ _handleClick = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee() {
3310
+ return runtime_1.wrap(function _callee$(_context) {
3311
+ while (1) {
3312
+ switch (_context.prev = _context.next) {
3313
+ case 0:
3314
+ if (editor) {
3315
+ _context.next = 2;
3316
+ break;
3317
+ }
3318
+
3319
+ return _context.abrupt("return");
3320
+
3321
+ case 2:
3322
+ if (isActive) {
3323
+ unwrapLink(editor);
3324
+ editor.tracking.onToolbarAction('unlinkHyperlinks');
3325
+ } else {
3326
+ addOrEditLink(editor, sdk, editor.tracking.onToolbarAction);
3327
+ }
3328
+
3329
+ case 3:
3330
+ case "end":
3331
+ return _context.stop();
3332
+ }
3333
+ }
3334
+ }, _callee);
3335
+ }));
3336
+ return _handleClick.apply(this, arguments);
3337
+ }
3338
+
3339
+ if (!editor) return null;
3340
+ return /*#__PURE__*/createElement(ToolbarButton, {
3341
+ title: "Hyperlink",
3342
+ testId: "hyperlink-toolbar-button",
3343
+ onClick: handleClick,
3344
+ isActive: isActive,
3345
+ isDisabled: props.isDisabled
3346
+ }, /*#__PURE__*/createElement(LinkIcon, null));
3347
+ }
3348
+
3439
3349
  var hasText = function hasText(editor, entry) {
3440
3350
  var node = entry[0];
3441
3351
  return !isAncestorEmpty(editor, node) && Node.string(node).trim() !== '';
3442
3352
  };
3443
3353
 
3354
+ function truncate(str, length) {
3355
+ if (typeof str === 'string' && str.length > length) {
3356
+ return str && str.substr(0, length + 1) // +1 to look ahead and be replaced below.
3357
+ // Get rid of orphan letters but not one letter words (I, a, 2).
3358
+ // Try to not have “.” as last character to avoid awkward “....”.
3359
+ .replace(/(\s+\S(?=\S)|\s*)\.?.$/, '…');
3360
+ }
3361
+
3362
+ return str;
3363
+ }
3364
+
3365
+ function getEntityInfo(data) {
3366
+ if (!data) {
3367
+ return '';
3368
+ }
3369
+
3370
+ var entityTitle = data.entityTitle,
3371
+ contentTypeName = data.contentTypeName,
3372
+ entityStatus = data.entityStatus,
3373
+ jobs = data.jobs;
3374
+ var title = truncate(entityTitle, 60) || 'Untitled';
3375
+ var scheduledActions = jobs.length > 0 ? getScheduleTooltipContent({
3376
+ job: jobs[0],
3377
+ jobsCount: jobs.length
3378
+ }) : '';
3379
+ return (contentTypeName || 'Asset') + " \"" + title + "\", " + entityStatus + " " + scheduledActions;
3380
+ }
3381
+
3382
+ function fetchAllData(_x) {
3383
+ return _fetchAllData.apply(this, arguments);
3384
+ }
3385
+
3386
+ function _fetchAllData() {
3387
+ _fetchAllData = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee(_ref) {
3388
+ var sdk, entityId, entityType, localeCode, defaultLocaleCode, contentType, getEntity, entity, contentTypeId, entityTitle, entityDescription, jobs, entityStatus;
3389
+ return runtime_1.wrap(function _callee$(_context) {
3390
+ while (1) {
3391
+ switch (_context.prev = _context.next) {
3392
+ case 0:
3393
+ sdk = _ref.sdk, entityId = _ref.entityId, entityType = _ref.entityType, localeCode = _ref.localeCode, defaultLocaleCode = _ref.defaultLocaleCode;
3394
+ getEntity = entityType === 'Entry' ? sdk.space.getEntry : sdk.space.getAsset;
3395
+ _context.next = 4;
3396
+ return getEntity(entityId);
3397
+
3398
+ case 4:
3399
+ entity = _context.sent;
3400
+
3401
+ if (entity.sys.contentType) {
3402
+ contentTypeId = entity.sys.contentType.sys.id;
3403
+ contentType = sdk.space.getCachedContentTypes().find(function (ct) {
3404
+ return ct.sys.id === contentTypeId;
3405
+ });
3406
+ }
3407
+
3408
+ entityTitle = entityType === 'Entry' ? entityHelpers.getEntryTitle({
3409
+ entry: entity,
3410
+ contentType: contentType,
3411
+ localeCode: localeCode,
3412
+ defaultLocaleCode: defaultLocaleCode,
3413
+ defaultTitle: 'Untitled'
3414
+ }) : entityHelpers.getAssetTitle({
3415
+ asset: entity,
3416
+ localeCode: localeCode,
3417
+ defaultLocaleCode: defaultLocaleCode,
3418
+ defaultTitle: 'Untitled'
3419
+ });
3420
+ entityDescription = entityHelpers.getEntityDescription({
3421
+ entity: entity,
3422
+ contentType: contentType,
3423
+ localeCode: localeCode,
3424
+ defaultLocaleCode: defaultLocaleCode
3425
+ });
3426
+ _context.next = 10;
3427
+ return sdk.space.getEntityScheduledActions(entityType, entityId);
3428
+
3429
+ case 10:
3430
+ jobs = _context.sent;
3431
+ entityStatus = entityHelpers.getEntryStatus(entity.sys);
3432
+ return _context.abrupt("return", {
3433
+ jobs: jobs,
3434
+ entity: entity,
3435
+ entityTitle: entityTitle,
3436
+ entityDescription: entityDescription,
3437
+ entityStatus: entityStatus,
3438
+ contentTypeName: contentType ? contentType.name : ''
3439
+ });
3440
+
3441
+ case 13:
3442
+ case "end":
3443
+ return _context.stop();
3444
+ }
3445
+ }
3446
+ }, _callee);
3447
+ }));
3448
+ return _fetchAllData.apply(this, arguments);
3449
+ }
3450
+
3451
+ function useRequestStatus(_ref2) {
3452
+ var sdk = _ref2.sdk,
3453
+ target = _ref2.target,
3454
+ onEntityFetchComplete = _ref2.onEntityFetchComplete;
3455
+
3456
+ var _useState = useState({
3457
+ type: 'loading'
3458
+ }),
3459
+ requestStatus = _useState[0],
3460
+ setRequestStatus = _useState[1];
3461
+
3462
+ useEffect(function () {
3463
+ if (target) {
3464
+ var _target$sys, _target$sys2;
3465
+
3466
+ fetchAllData({
3467
+ sdk: sdk,
3468
+ entityId: target == null ? void 0 : (_target$sys = target.sys) == null ? void 0 : _target$sys.id,
3469
+ entityType: target == null ? void 0 : (_target$sys2 = target.sys) == null ? void 0 : _target$sys2.linkType,
3470
+ localeCode: sdk.field.locale,
3471
+ defaultLocaleCode: sdk.locales["default"]
3472
+ }).then(function (entityInfo) {
3473
+ setRequestStatus({
3474
+ type: 'success',
3475
+ data: entityInfo
3476
+ });
3477
+ })["catch"](function (e) {
3478
+ console.log(e);
3479
+ setRequestStatus({
3480
+ type: 'error',
3481
+ error: e
3482
+ });
3483
+ })["finally"](function () {
3484
+ onEntityFetchComplete == null ? void 0 : onEntityFetchComplete();
3485
+ });
3486
+ }
3487
+ }, [sdk, target, onEntityFetchComplete]);
3488
+ return requestStatus;
3489
+ }
3490
+
3491
+ function useEntityInfo(props) {
3492
+ var status = useRequestStatus(props);
3493
+ var linkType = props.target.sys.linkType;
3494
+
3495
+ if (status.type === 'loading') {
3496
+ return "Loading " + linkType.toLowerCase() + "...";
3497
+ }
3498
+
3499
+ if (status.type === 'error') {
3500
+ return linkType + " missing or inaccessible";
3501
+ }
3502
+
3503
+ return getEntityInfo(status.data);
3504
+ }
3505
+
3444
3506
  var styles$c = {
3445
3507
  hyperlinkWrapper: /*#__PURE__*/css({
3446
3508
  display: 'inline',
@@ -3458,33 +3520,21 @@ var styles$c = {
3458
3520
  '&:focus': {
3459
3521
  fill: tokens.gray900
3460
3522
  }
3461
- }),
3462
- hyperlinkIEFallback: /*#__PURE__*/css({
3463
- color: '#1683d0',
3464
- textDecoration: 'underline'
3465
- }),
3466
- // TODO: use these styles once we can use the icon
3467
- hyperlinkIcon: /*#__PURE__*/css({
3468
- position: 'relative',
3469
- top: '4px',
3470
- height: '14px',
3471
- margin: '0 -2px 0 -1px',
3472
- webkitTransition: 'fill 100ms ease-in-out',
3473
- transition: 'fill 100ms ease-in-out',
3474
- '&:hover': {
3475
- fill: tokens.gray900
3476
- },
3477
- '&:focus': {
3478
- fill: tokens.gray900
3479
- }
3480
3523
  })
3481
3524
  };
3482
3525
 
3483
- function UrlHyperlink(props) {
3526
+ function EntityHyperlink(props) {
3484
3527
  var editor = useContentfulEditor();
3485
3528
  var isReadOnly = useReadOnly();
3486
3529
  var sdk = useSdkContext();
3487
- var uri = props.element.data.uri;
3530
+ var target = props.element.data.target;
3531
+ var onEntityFetchComplete = props.onEntityFetchComplete;
3532
+ var tooltipContent = useEntityInfo({
3533
+ target: target,
3534
+ sdk: sdk,
3535
+ onEntityFetchComplete: onEntityFetchComplete
3536
+ });
3537
+ if (!target) return null;
3488
3538
 
3489
3539
  function handleClick(event) {
3490
3540
  event.preventDefault();
@@ -3494,33 +3544,25 @@ function UrlHyperlink(props) {
3494
3544
  }
3495
3545
 
3496
3546
  return /*#__PURE__*/createElement(Tooltip, {
3497
- content: uri,
3547
+ content: tooltipContent,
3498
3548
  targetWrapperClassName: styles$c.hyperlinkWrapper,
3499
3549
  placement: "bottom",
3500
3550
  maxWidth: "auto"
3501
3551
  }, /*#__PURE__*/createElement(TextLink, {
3502
3552
  as: "a",
3503
- href: uri,
3504
- rel: "noopener noreferrer",
3505
3553
  onClick: handleClick,
3506
3554
  isDisabled: isReadOnly,
3507
- className: styles$c.hyperlink
3555
+ className: styles$c.hyperlink,
3556
+ "data-link-type": target.sys.linkType,
3557
+ "data-link-id": target.sys.id
3508
3558
  }, props.children));
3509
3559
  }
3510
3560
 
3511
- function EntityHyperlink(props) {
3561
+ function UrlHyperlink(props) {
3512
3562
  var editor = useContentfulEditor();
3513
3563
  var isReadOnly = useReadOnly();
3514
3564
  var sdk = useSdkContext();
3515
- var target = props.element.data.target;
3516
- var onEntityFetchComplete = props.onEntityFetchComplete;
3517
- useEffect(function () {
3518
- // The real entity loading happens in the tooltip
3519
- // Since that is deferred the link is considered rendered as soon
3520
- // the component mounts (link text displayed)
3521
- onEntityFetchComplete == null ? void 0 : onEntityFetchComplete();
3522
- }, [onEntityFetchComplete]);
3523
- if (!target) return null;
3565
+ var uri = props.element.data.uri;
3524
3566
 
3525
3567
  function handleClick(event) {
3526
3568
  event.preventDefault();
@@ -3530,74 +3572,20 @@ function EntityHyperlink(props) {
3530
3572
  }
3531
3573
 
3532
3574
  return /*#__PURE__*/createElement(Tooltip, {
3533
- content: /*#__PURE__*/createElement(EntryAssetTooltip, {
3534
- id: target.sys.id,
3535
- type: target.sys.linkType,
3536
- sdk: sdk
3537
- }),
3575
+ content: uri,
3538
3576
  targetWrapperClassName: styles$c.hyperlinkWrapper,
3539
3577
  placement: "bottom",
3540
3578
  maxWidth: "auto"
3541
3579
  }, /*#__PURE__*/createElement(TextLink, {
3542
3580
  as: "a",
3581
+ href: uri,
3582
+ rel: "noopener noreferrer",
3543
3583
  onClick: handleClick,
3544
3584
  isDisabled: isReadOnly,
3545
- className: styles$c.hyperlink,
3546
- "data-link-type": target.sys.linkType,
3547
- "data-link-id": target.sys.id
3585
+ className: styles$c.hyperlink
3548
3586
  }, props.children));
3549
3587
  }
3550
3588
 
3551
- function ToolbarHyperlinkButton(props) {
3552
- var editor = useContentfulEditor();
3553
- var isActive = !!(editor && isLinkActive(editor));
3554
- var sdk = useSdkContext();
3555
-
3556
- function handleClick() {
3557
- return _handleClick.apply(this, arguments);
3558
- }
3559
-
3560
- function _handleClick() {
3561
- _handleClick = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee() {
3562
- return runtime_1.wrap(function _callee$(_context) {
3563
- while (1) {
3564
- switch (_context.prev = _context.next) {
3565
- case 0:
3566
- if (editor) {
3567
- _context.next = 2;
3568
- break;
3569
- }
3570
-
3571
- return _context.abrupt("return");
3572
-
3573
- case 2:
3574
- if (isActive) {
3575
- unwrapLink(editor);
3576
- editor.tracking.onToolbarAction('unlinkHyperlinks');
3577
- } else {
3578
- addOrEditLink(editor, sdk, editor.tracking.onToolbarAction);
3579
- }
3580
-
3581
- case 3:
3582
- case "end":
3583
- return _context.stop();
3584
- }
3585
- }
3586
- }, _callee);
3587
- }));
3588
- return _handleClick.apply(this, arguments);
3589
- }
3590
-
3591
- if (!editor) return null;
3592
- return /*#__PURE__*/createElement(ToolbarButton, {
3593
- title: "Hyperlink",
3594
- testId: "hyperlink-toolbar-button",
3595
- onClick: handleClick,
3596
- isActive: isActive,
3597
- isDisabled: props.isDisabled
3598
- }, /*#__PURE__*/createElement(LinkIcon, null));
3599
- }
3600
-
3601
3589
  var isAnchor = function isAnchor(element) {
3602
3590
  return element.nodeName === 'A' && !!element.getAttribute('href') && element.getAttribute('href') !== '#';
3603
3591
  };
@@ -3741,8 +3729,331 @@ function ListItem(props) {
3741
3729
  }), props.children);
3742
3730
  }
3743
3731
 
3744
- var isList = function isList(node) {
3745
- return [BLOCKS.OL_LIST, BLOCKS.UL_LIST].includes(node.type);
3732
+ /**
3733
+ * Credit: Modified version of Plate's list plugin
3734
+ * See: https://github.com/udecode/plate/blob/main/packages/nodes/list
3735
+ */
3736
+ var moveListItemDown = function moveListItemDown(editor, _ref) {
3737
+ var list = _ref.list,
3738
+ listItem = _ref.listItem;
3739
+ var listNode = list[0];
3740
+ var listItemPath = listItem[1];
3741
+ var previousListItemPath;
3742
+
3743
+ try {
3744
+ previousListItemPath = Path.previous(listItemPath);
3745
+ } catch (e) {
3746
+ return;
3747
+ } // Previous sibling is the new parent
3748
+
3749
+
3750
+ var previousSiblingItem = Editor.node(editor, previousListItemPath);
3751
+
3752
+ if (previousSiblingItem) {
3753
+ var previousPath = previousSiblingItem[1];
3754
+ var subList = Array.from(Node.children(editor, previousPath)).find(function (_ref2) {
3755
+ var n = _ref2[0];
3756
+ return match(n, {
3757
+ type: getListTypes(editor)
3758
+ });
3759
+ });
3760
+ var newPath = Path.next(getLastChildPath(subList != null ? subList : previousSiblingItem));
3761
+ Editor.withoutNormalizing(editor, function () {
3762
+ if (!subList) {
3763
+ // Create new sub-list
3764
+ wrapNodes(editor, {
3765
+ type: listNode.type,
3766
+ children: [],
3767
+ data: {}
3768
+ }, {
3769
+ at: listItemPath
3770
+ });
3771
+ } // Move the current item to the sub-list
3772
+
3773
+
3774
+ Transforms.moveNodes(editor, {
3775
+ at: listItemPath,
3776
+ to: newPath
3777
+ });
3778
+ });
3779
+ }
3780
+ };
3781
+
3782
+ /**
3783
+ * Credit: Modified version of Plate's list plugin
3784
+ * See: https://github.com/udecode/plate/blob/main/packages/nodes/list
3785
+ */
3786
+ var moveListItems = function moveListItems(editor, _temp) {
3787
+ var _editor$selection;
3788
+
3789
+ var _ref = _temp === void 0 ? {} : _temp,
3790
+ _ref$increase = _ref.increase,
3791
+ increase = _ref$increase === void 0 ? true : _ref$increase,
3792
+ _ref$at = _ref.at,
3793
+ at = _ref$at === void 0 ? (_editor$selection = editor.selection) != null ? _editor$selection : undefined : _ref$at;
3794
+
3795
+ var _nodes = getNodes(editor, {
3796
+ at: at,
3797
+ match: {
3798
+ type: getPluginType(editor, ELEMENT_LIC)
3799
+ }
3800
+ }); // Get the selected lic
3801
+
3802
+
3803
+ var lics = Array.from(_nodes);
3804
+ if (!lics.length) return;
3805
+ var highestLicPaths = [];
3806
+ var highestLicPathRefs = []; // Filter out the nested lic, we just need to move the highest ones
3807
+
3808
+ lics.forEach(function (lic) {
3809
+ var licPath = lic[1];
3810
+ var liPath = Path.parent(licPath);
3811
+ var isAncestor = highestLicPaths.some(function (path) {
3812
+ var highestLiPath = Path.parent(path);
3813
+ return Path.isAncestor(highestLiPath, liPath);
3814
+ });
3815
+
3816
+ if (!isAncestor) {
3817
+ highestLicPaths.push(licPath);
3818
+ highestLicPathRefs.push(Editor.pathRef(editor, licPath));
3819
+ }
3820
+ });
3821
+ var licPathRefsToMove = increase ? highestLicPathRefs : highestLicPathRefs.reverse();
3822
+ Editor.withoutNormalizing(editor, function () {
3823
+ licPathRefsToMove.forEach(function (licPathRef) {
3824
+ var licPath = licPathRef.unref();
3825
+ if (!licPath) return;
3826
+ var liEntry = getListItemEntry(editor, {
3827
+ at: licPath
3828
+ });
3829
+
3830
+ if (!liEntry) {
3831
+ return;
3832
+ }
3833
+
3834
+ if (increase) {
3835
+ moveListItemDown(editor, liEntry);
3836
+ } else if (isListNested(editor, liEntry.list[1])) {
3837
+ moveListItemUp(editor, liEntry);
3838
+ }
3839
+ });
3840
+ });
3841
+ };
3842
+
3843
+ /**
3844
+ * Credit: Modified version of Plate's list plugin
3845
+ * See: https://github.com/udecode/plate/blob/main/packages/nodes/list
3846
+ */
3847
+ var listTypes = [BLOCKS.UL_LIST, BLOCKS.OL_LIST];
3848
+ var unwrapList = function unwrapList(editor, _temp) {
3849
+ var _ref = _temp === void 0 ? {} : _temp,
3850
+ at = _ref.at;
3851
+
3852
+ Editor.withoutNormalizing(editor, function () {
3853
+ do {
3854
+ unwrapNodes(editor, {
3855
+ at: at,
3856
+ match: {
3857
+ type: BLOCKS.LIST_ITEM
3858
+ },
3859
+ split: true
3860
+ });
3861
+ unwrapNodes(editor, {
3862
+ at: at,
3863
+ match: {
3864
+ type: listTypes
3865
+ },
3866
+ split: true
3867
+ });
3868
+ } while (getAbove(editor, {
3869
+ match: {
3870
+ type: listTypes,
3871
+ at: at
3872
+ }
3873
+ }));
3874
+ });
3875
+ };
3876
+
3877
+ var listTypes$1 = [BLOCKS.UL_LIST, BLOCKS.OL_LIST];
3878
+ var toggleList = function toggleList(editor, _ref) {
3879
+ var type = _ref.type;
3880
+ return Editor.withoutNormalizing(editor, function () {
3881
+ if (!editor.selection) {
3882
+ return;
3883
+ }
3884
+
3885
+ if (isCollapsed(editor.selection) || !isRangeAcrossBlocks(editor)) {
3886
+ // selection is collapsed
3887
+ var res = getListItemEntry(editor);
3888
+
3889
+ if (res) {
3890
+ var list = res.list;
3891
+
3892
+ if (list[0].type !== type) {
3893
+ setNodes(editor, {
3894
+ type: type
3895
+ }, {
3896
+ at: editor.selection,
3897
+ match: function match(n) {
3898
+ return listTypes$1.includes(n.type);
3899
+ },
3900
+ mode: 'lowest'
3901
+ });
3902
+ } else {
3903
+ unwrapList(editor);
3904
+ }
3905
+ } else {
3906
+ var _list = {
3907
+ type: type,
3908
+ children: [],
3909
+ data: {}
3910
+ };
3911
+ wrapNodes(editor, _list);
3912
+ var nodes = [].concat(getNodes(editor, {
3913
+ match: {
3914
+ type: getPluginType(editor, ELEMENT_DEFAULT)
3915
+ }
3916
+ }));
3917
+ var listItem = {
3918
+ type: BLOCKS.LIST_ITEM,
3919
+ children: [],
3920
+ data: {}
3921
+ };
3922
+
3923
+ for (var _iterator = _createForOfIteratorHelperLoose(nodes), _step; !(_step = _iterator()).done;) {
3924
+ var _step$value = _step.value,
3925
+ path = _step$value[1];
3926
+ wrapNodes(editor, listItem, {
3927
+ at: path
3928
+ });
3929
+ }
3930
+ }
3931
+ } else {
3932
+ // selection is a range
3933
+ var _Range$edges = Range.edges(editor.selection),
3934
+ startPoint = _Range$edges[0],
3935
+ endPoint = _Range$edges[1];
3936
+
3937
+ var commonEntry = Node.common(editor, startPoint.path, endPoint.path);
3938
+
3939
+ if (listTypes$1.includes(commonEntry[0].type) || commonEntry[0].type === BLOCKS.LIST_ITEM) {
3940
+ if (commonEntry[0].type !== type) {
3941
+ var startList = findNode(editor, {
3942
+ at: Range.start(editor.selection),
3943
+ match: {
3944
+ type: listTypes$1
3945
+ },
3946
+ mode: 'lowest'
3947
+ });
3948
+ var endList = findNode(editor, {
3949
+ at: Range.end(editor.selection),
3950
+ match: {
3951
+ type: listTypes$1
3952
+ },
3953
+ mode: 'lowest'
3954
+ });
3955
+
3956
+ if (!startList || !endList) {
3957
+ return;
3958
+ }
3959
+
3960
+ var rangeLength = Math.min(startList[1].length, endList[1].length);
3961
+ setNodes(editor, {
3962
+ type: type
3963
+ }, {
3964
+ at: editor.selection,
3965
+ match: function match(n, path) {
3966
+ return listTypes$1.includes(n.type) && path.length >= rangeLength;
3967
+ },
3968
+ mode: 'all'
3969
+ });
3970
+ } else {
3971
+ unwrapList(editor);
3972
+ }
3973
+ } else {
3974
+ var rootPathLength = commonEntry[1].length;
3975
+
3976
+ var _nodes = Array.from(getNodes(editor, {
3977
+ mode: 'all'
3978
+ })).filter(function (_ref2) {
3979
+ var path = _ref2[1];
3980
+ return path.length === rootPathLength + 1;
3981
+ }).reverse();
3982
+
3983
+ _nodes.forEach(function (n) {
3984
+ if (listTypes$1.includes(n[0].type)) {
3985
+ setNodes(editor, {
3986
+ type: type
3987
+ }, {
3988
+ at: n[1]
3989
+ });
3990
+ } else {
3991
+ setNodes(editor, {
3992
+ type: getPluginType(editor, ELEMENT_LIC)
3993
+ }, {
3994
+ at: n[1]
3995
+ });
3996
+ var _listItem = {
3997
+ type: BLOCKS.LIST_ITEM,
3998
+ children: [],
3999
+ data: {}
4000
+ };
4001
+ wrapNodes(editor, _listItem, {
4002
+ at: n[1]
4003
+ });
4004
+ var _list2 = {
4005
+ type: type,
4006
+ children: [],
4007
+ data: {}
4008
+ };
4009
+ wrapNodes(editor, _list2, {
4010
+ at: n[1]
4011
+ });
4012
+ }
4013
+ });
4014
+ }
4015
+ }
4016
+ });
4017
+ };
4018
+
4019
+ var onKeyDownList = function onKeyDownList(editor, _ref) {
4020
+ var type = _ref.type,
4021
+ hotkey = _ref.options.hotkey;
4022
+ return function (e) {
4023
+ if (e.key === 'Tab' && editor.selection) {
4024
+ var listSelected = getAbove(editor, {
4025
+ at: editor.selection,
4026
+ match: {
4027
+ type: type
4028
+ }
4029
+ });
4030
+
4031
+ if (listSelected) {
4032
+ e.preventDefault();
4033
+ moveListItems(editor, {
4034
+ increase: !e.shiftKey
4035
+ });
4036
+ return;
4037
+ }
4038
+ }
4039
+
4040
+ if (!hotkey) return;
4041
+ var hotkeys = castArray(hotkey);
4042
+
4043
+ for (var _iterator = _createForOfIteratorHelperLoose(hotkeys), _step; !(_step = _iterator()).done;) {
4044
+ var _hotkey = _step.value;
4045
+
4046
+ if (isHotkey(_hotkey)(e)) {
4047
+ toggleList(editor, {
4048
+ type: type
4049
+ });
4050
+ }
4051
+ }
4052
+ };
4053
+ };
4054
+
4055
+ var isList = function isList(node) {
4056
+ return [BLOCKS.OL_LIST, BLOCKS.UL_LIST].includes(node.type);
3746
4057
  };
3747
4058
 
3748
4059
  var hasListAsDirectParent = function hasListAsDirectParent(editor, _ref) {
@@ -4110,50 +4421,16 @@ var insertListFragment = function insertListFragment(editor) {
4110
4421
  select: true
4111
4422
  });
4112
4423
  return Transforms.insertNodes(editor, blocks, {
4113
- at: editor.selection,
4114
- select: true
4115
- });
4116
- }
4117
-
4118
- var filtered = isListRoot(fragment[0]) ? [{
4119
- text: ''
4120
- }].concat(fragment) : fragment;
4121
- return insertFragment(filtered);
4122
- };
4123
- };
4124
-
4125
- /**
4126
- * Credit: Modified version of Plate's list plugin
4127
- * See: https://github.com/udecode/plate/blob/main/packages/nodes/list
4128
- */
4129
- var listTypes = [BLOCKS.UL_LIST, BLOCKS.OL_LIST];
4130
- var unwrapList = function unwrapList(editor, _temp) {
4131
- var _ref = _temp === void 0 ? {} : _temp,
4132
- at = _ref.at;
4133
-
4134
- Editor.withoutNormalizing(editor, function () {
4135
- do {
4136
- unwrapNodes(editor, {
4137
- at: at,
4138
- match: {
4139
- type: BLOCKS.LIST_ITEM
4140
- },
4141
- split: true
4142
- });
4143
- unwrapNodes(editor, {
4144
- at: at,
4145
- match: {
4146
- type: listTypes
4147
- },
4148
- split: true
4149
- });
4150
- } while (getAbove(editor, {
4151
- match: {
4152
- type: listTypes,
4153
- at: at
4154
- }
4155
- }));
4156
- });
4424
+ at: editor.selection,
4425
+ select: true
4426
+ });
4427
+ }
4428
+
4429
+ var filtered = isListRoot(fragment[0]) ? [{
4430
+ text: ''
4431
+ }].concat(fragment) : fragment;
4432
+ return insertFragment(filtered);
4433
+ };
4157
4434
  };
4158
4435
 
4159
4436
  /**
@@ -4265,12 +4542,18 @@ var createListPlugin = function createListPlugin() {
4265
4542
  overrideByKey: (_overrideByKey = {}, _overrideByKey[ELEMENT_UL] = {
4266
4543
  type: BLOCKS.UL_LIST,
4267
4544
  component: ListUL,
4545
+ handlers: {
4546
+ onKeyDown: onKeyDownList
4547
+ },
4268
4548
  // The withList is added on ELEMENT_UL plugin in upstream code
4269
4549
  // so we need to override it here
4270
4550
  withOverrides: withList
4271
4551
  }, _overrideByKey[ELEMENT_OL] = {
4272
4552
  type: BLOCKS.OL_LIST,
4273
- component: ListOL
4553
+ component: ListOL,
4554
+ handlers: {
4555
+ onKeyDown: onKeyDownList
4556
+ }
4274
4557
  }, _overrideByKey[ELEMENT_LIC] = {
4275
4558
  type: BLOCKS.PARAGRAPH
4276
4559
  }, _overrideByKey[ELEMENT_LI] = {
@@ -4294,148 +4577,6 @@ var createListPlugin = function createListPlugin() {
4294
4577
  });
4295
4578
  };
4296
4579
 
4297
- var listTypes$1 = [BLOCKS.UL_LIST, BLOCKS.OL_LIST];
4298
- var toggleList = function toggleList(editor, _ref) {
4299
- var type = _ref.type;
4300
- return Editor.withoutNormalizing(editor, function () {
4301
- if (!editor.selection) {
4302
- return;
4303
- }
4304
-
4305
- if (isCollapsed(editor.selection) || !isRangeAcrossBlocks(editor)) {
4306
- // selection is collapsed
4307
- var res = getListItemEntry(editor);
4308
-
4309
- if (res) {
4310
- var list = res.list;
4311
-
4312
- if (list[0].type !== type) {
4313
- setNodes(editor, {
4314
- type: type
4315
- }, {
4316
- at: editor.selection,
4317
- match: function match(n) {
4318
- return listTypes$1.includes(n.type);
4319
- },
4320
- mode: 'lowest'
4321
- });
4322
- } else {
4323
- unwrapList(editor);
4324
- }
4325
- } else {
4326
- var _list = {
4327
- type: type,
4328
- children: [],
4329
- data: {}
4330
- };
4331
- wrapNodes(editor, _list);
4332
- var nodes = [].concat(getNodes(editor, {
4333
- match: {
4334
- type: getPluginType(editor, ELEMENT_DEFAULT)
4335
- }
4336
- }));
4337
- var listItem = {
4338
- type: BLOCKS.LIST_ITEM,
4339
- children: [],
4340
- data: {}
4341
- };
4342
-
4343
- for (var _iterator = _createForOfIteratorHelperLoose(nodes), _step; !(_step = _iterator()).done;) {
4344
- var _step$value = _step.value,
4345
- path = _step$value[1];
4346
- wrapNodes(editor, listItem, {
4347
- at: path
4348
- });
4349
- }
4350
- }
4351
- } else {
4352
- // selection is a range
4353
- var _Range$edges = Range.edges(editor.selection),
4354
- startPoint = _Range$edges[0],
4355
- endPoint = _Range$edges[1];
4356
-
4357
- var commonEntry = Node.common(editor, startPoint.path, endPoint.path);
4358
-
4359
- if (listTypes$1.includes(commonEntry[0].type) || commonEntry[0].type === BLOCKS.LIST_ITEM) {
4360
- if (commonEntry[0].type !== type) {
4361
- var startList = findNode(editor, {
4362
- at: Range.start(editor.selection),
4363
- match: {
4364
- type: listTypes$1
4365
- },
4366
- mode: 'lowest'
4367
- });
4368
- var endList = findNode(editor, {
4369
- at: Range.end(editor.selection),
4370
- match: {
4371
- type: listTypes$1
4372
- },
4373
- mode: 'lowest'
4374
- });
4375
-
4376
- if (!startList || !endList) {
4377
- return;
4378
- }
4379
-
4380
- var rangeLength = Math.min(startList[1].length, endList[1].length);
4381
- setNodes(editor, {
4382
- type: type
4383
- }, {
4384
- at: editor.selection,
4385
- match: function match(n, path) {
4386
- return listTypes$1.includes(n.type) && path.length >= rangeLength;
4387
- },
4388
- mode: 'all'
4389
- });
4390
- } else {
4391
- unwrapList(editor);
4392
- }
4393
- } else {
4394
- var rootPathLength = commonEntry[1].length;
4395
-
4396
- var _nodes = Array.from(getNodes(editor, {
4397
- mode: 'all'
4398
- })).filter(function (_ref2) {
4399
- var path = _ref2[1];
4400
- return path.length === rootPathLength + 1;
4401
- }).reverse();
4402
-
4403
- _nodes.forEach(function (n) {
4404
- if (listTypes$1.includes(n[0].type)) {
4405
- setNodes(editor, {
4406
- type: type
4407
- }, {
4408
- at: n[1]
4409
- });
4410
- } else {
4411
- setNodes(editor, {
4412
- type: getPluginType(editor, ELEMENT_LIC)
4413
- }, {
4414
- at: n[1]
4415
- });
4416
- var _listItem = {
4417
- type: BLOCKS.LIST_ITEM,
4418
- children: [],
4419
- data: {}
4420
- };
4421
- wrapNodes(editor, _listItem, {
4422
- at: n[1]
4423
- });
4424
- var _list2 = {
4425
- type: type,
4426
- children: [],
4427
- data: {}
4428
- };
4429
- wrapNodes(editor, _list2, {
4430
- at: n[1]
4431
- });
4432
- }
4433
- });
4434
- }
4435
- }
4436
- });
4437
- };
4438
-
4439
4580
  function ToolbarListButton(props) {
4440
4581
  var sdk = useSdkContext();
4441
4582
  var editor = useContentfulEditor();
@@ -6237,6 +6378,80 @@ var disableCorePlugins = {
6237
6378
  eventEditor: true
6238
6379
  };
6239
6380
 
6381
+ /**
6382
+ * For legacy reasons, a document may not have any content at all
6383
+ * e.g:
6384
+ *
6385
+ * {nodeType: document, data: {}, content: []}
6386
+ *
6387
+ * Rendering such document will break the Slate editor
6388
+ */
6389
+
6390
+ var hasContent = function hasContent(doc) {
6391
+ if (!doc) {
6392
+ return false;
6393
+ }
6394
+
6395
+ return doc.content.length > 0;
6396
+ };
6397
+ /*
6398
+ Plate api doesn't allow to modify (easily) the editor value programmatically
6399
+ after the editor instance is created
6400
+
6401
+ This function is inspired to https://github.com/udecode/plate/issues/1269#issuecomment-1057643622
6402
+ */
6403
+
6404
+ var setEditorContent = function setEditorContent(editor, nodes) {
6405
+ // Replaces editor content while keeping change history
6406
+ Editor.withoutNormalizing(editor, function () {
6407
+ var children = [].concat(editor.children);
6408
+ children.forEach(function (node) {
6409
+ return editor.apply({
6410
+ type: 'remove_node',
6411
+ path: [0],
6412
+ node: node
6413
+ });
6414
+ });
6415
+
6416
+ if (nodes) {
6417
+ var nodesArray = Node.isNode(nodes) ? [nodes] : nodes;
6418
+ nodesArray.forEach(function (node, i) {
6419
+ return editor.apply({
6420
+ type: 'insert_node',
6421
+ path: [i],
6422
+ node: node
6423
+ });
6424
+ });
6425
+ }
6426
+
6427
+ var point = Editor.end(editor, []);
6428
+
6429
+ if (point) {
6430
+ Transforms.select(editor, point);
6431
+ }
6432
+ });
6433
+ };
6434
+ /**
6435
+ * Converts a contenful rich text document to the corresponding slate editor
6436
+ * value
6437
+ */
6438
+
6439
+ var documentToEditorValue = function documentToEditorValue(doc) {
6440
+ return toSlatejsDocument({
6441
+ document: hasContent(doc) ? doc : EMPTY_DOCUMENT,
6442
+ // TODO: get rid of schema, https://github.com/contentful/field-editors/pull/1065#discussion_r826723248
6443
+ schema: schema
6444
+ });
6445
+ };
6446
+ var normalizeEditorValue = function normalizeEditorValue(value, options) {
6447
+ var editor = createPlateEditor(options);
6448
+ editor.children = value;
6449
+ Editor.normalize(editor, {
6450
+ force: true
6451
+ });
6452
+ return editor.children;
6453
+ };
6454
+
6240
6455
  var STYLE_EDITOR_BORDER = "1px solid " + tokens.gray400;
6241
6456
  var styles$j = {
6242
6457
  root: /*#__PURE__*/css({
@@ -6333,7 +6548,17 @@ var EmbedEntityWidget = function EmbedEntityWidget(_ref) {
6333
6548
  setCanAccessAssets = _useState2[1];
6334
6549
 
6335
6550
  React__default.useEffect(function () {
6336
- sdk.access.can('read', 'Asset').then(setCanAccessAssets);
6551
+ var subscribed = true;
6552
+ sdk.access.can('read', 'Asset').then(function (can) {
6553
+ if (!subscribed) {
6554
+ return;
6555
+ }
6556
+
6557
+ setCanAccessAssets(can);
6558
+ });
6559
+ return function () {
6560
+ subscribed = false;
6561
+ };
6337
6562
  }, [sdk]);
6338
6563
  var inlineEntryEmbedEnabled = isNodeTypeEnabled(sdk.field, INLINES.EMBEDDED_ENTRY);
6339
6564
  var blockEntryEmbedEnabled = isNodeTypeEnabled(sdk.field, BLOCKS.EMBEDDED_ENTRY) && canInsertBlocks;
@@ -6488,50 +6713,6 @@ var StickyToolbarWrapper = function StickyToolbarWrapper(_ref) {
6488
6713
  }, children);
6489
6714
  };
6490
6715
 
6491
- /**
6492
- * For legacy reasons, a document may not have any content at all
6493
- * e.g:
6494
- *
6495
- * {nodeType: document, data: {}, content: []}
6496
- *
6497
- * Rendering such document will break the Slate editor
6498
- */
6499
-
6500
- var hasContent = function hasContent(doc) {
6501
- if (!doc) {
6502
- return false;
6503
- }
6504
-
6505
- return doc.content.length > 0;
6506
- };
6507
-
6508
- var useNormalizedSlateValue = function useNormalizedSlateValue(_ref) {
6509
- var id = _ref.id,
6510
- incomingDoc = _ref.incomingDoc,
6511
- plugins = _ref.plugins;
6512
- return useMemo(function () {
6513
- var editor = createPlateEditor({
6514
- id: id,
6515
- plugins: plugins,
6516
- disableCorePlugins: disableCorePlugins
6517
- });
6518
- var doc = toSlatejsDocument({
6519
- document: hasContent(incomingDoc) ? incomingDoc : EMPTY_DOCUMENT,
6520
- schema: schema
6521
- }); // Sets editor value & kicks normalization
6522
-
6523
- editor.children = doc;
6524
- Editor.normalize(editor, {
6525
- force: true
6526
- }); // TODO: return the editor itself to avoid recompiling & initializing all
6527
- // of the plugins again. It's currently not possible due to a bug in Plate
6528
- // with initialValues
6529
- // See: https://slate-js.slack.com/archives/C013QHXSCG1/p1645112799942819
6530
-
6531
- return editor.children;
6532
- }, [id, plugins, incomingDoc]);
6533
- };
6534
-
6535
6716
  /**
6536
6717
  * Returns whether a given operation is relevant enough to trigger a save.
6537
6718
  */
@@ -6545,8 +6726,10 @@ var isRelevantOperation = function isRelevantOperation(op) {
6545
6726
  };
6546
6727
 
6547
6728
  var useOnValueChanged = function useOnValueChanged(_ref) {
6548
- var editor = _ref.editor,
6549
- handler = _ref.handler;
6729
+ var editorId = _ref.editorId,
6730
+ handler = _ref.handler,
6731
+ skip = _ref.skip,
6732
+ onSkip = _ref.onSkip;
6550
6733
  var onChange = useMemo(function () {
6551
6734
  return debounce(function (document) {
6552
6735
  handler == null ? void 0 : handler(toContentfulDocument({
@@ -6556,45 +6739,84 @@ var useOnValueChanged = function useOnValueChanged(_ref) {
6556
6739
  }, 500);
6557
6740
  }, [handler]);
6558
6741
  return useCallback(function (value) {
6559
- var operations = editor.operations.filter(isRelevantOperation);
6742
+ var editor = getPlateSelectors(editorId).editor();
6743
+
6744
+ if (!editor) {
6745
+ throw new Error('Editor change callback called but editor not defined. Editor id: ' + editorId);
6746
+ }
6747
+
6748
+ var operations = editor == null ? void 0 : editor.operations.filter(isRelevantOperation);
6560
6749
 
6561
6750
  if (operations.length > 0) {
6751
+ if (skip) {
6752
+ onSkip == null ? void 0 : onSkip();
6753
+ return;
6754
+ }
6755
+
6562
6756
  onChange(value);
6563
6757
  }
6564
- }, [editor, onChange]);
6758
+ }, [editorId, onChange, skip, onSkip]);
6565
6759
  };
6566
6760
 
6567
6761
  var _excluded = ["sdk", "isInitiallyDisabled", "onAction"];
6568
6762
  var ConnectedRichTextEditor = function ConnectedRichTextEditor(props) {
6569
- var id = getContentfulEditorId(props.sdk); // TODO: remove in favor of getting the editor from useNormalizedSlateValue after upgrading to Plate v10
6570
-
6571
- var editor = useContentfulEditor(id);
6763
+ var id = getContentfulEditorId(props.sdk);
6572
6764
  var plugins = React__default.useMemo(function () {
6573
6765
  var _props$onAction;
6574
6766
 
6575
6767
  return getPlugins(props.sdk, (_props$onAction = props.onAction) != null ? _props$onAction : noop);
6576
6768
  }, [props.sdk, props.onAction]);
6577
- var initialValue = useNormalizedSlateValue({
6578
- id: id,
6579
- incomingDoc: props.value,
6580
- plugins: plugins
6581
- });
6769
+
6770
+ var _useState = useState(true),
6771
+ isFirstRender = _useState[0],
6772
+ setIsFirstRender = _useState[1];
6773
+
6774
+ var _useState2 = useState(false),
6775
+ pendingExternalUpdate = _useState2[0],
6776
+ setPendingExternalUpdate = _useState2[1];
6777
+
6582
6778
  var onValueChanged = useOnValueChanged({
6583
- editor: editor,
6584
- handler: props.onChange
6779
+ editorId: id,
6780
+ handler: props.onChange,
6781
+ skip: pendingExternalUpdate || isFirstRender,
6782
+ onSkip: function onSkip() {
6783
+ return setPendingExternalUpdate(false);
6784
+ }
6585
6785
  });
6786
+ useEffect(function () {
6787
+ /*
6788
+ This effect is called when the value prop changes. Normally
6789
+ this happens when the value is changed outside of the editor,
6790
+ like in snapshots restoration or remote updates
6791
+ Plate won't update the displayed value on its own, see:
6792
+ - https://github.com/ianstormtaylor/slate/pull/4540
6793
+ - https://github.com/udecode/plate/issues/1169
6794
+ The content is forcely set to the new value and it's ensured
6795
+ the change listener isn't invoked
6796
+ */
6797
+ setIsFirstRender(false);
6798
+ var editor = getPlateSelectors(id).editor();
6799
+
6800
+ if (!editor) {
6801
+ return;
6802
+ }
6803
+
6804
+ setPendingExternalUpdate(true);
6805
+ setEditorContent(editor, documentToEditorValue(props.value));
6806
+ }, [props.value, id]);
6586
6807
  var classNames = cx(styles$j.editor, props.minHeight !== undefined ? css({
6587
6808
  minHeight: props.minHeight
6588
6809
  }) : undefined, props.isDisabled ? styles$j.disabled : styles$j.enabled, props.isToolbarHidden && styles$j.hiddenToolbar);
6589
6810
  useEffect(function () {
6590
- // Ensure the plate state is cleared after the component unmounts
6591
- // This prevent new editors for the same field to display old outdated values
6592
- // Typical scenario: coming back to the entry editor after restoring a previous entry version
6593
- getPlateActions(id).enabled(true);
6594
- return function () {
6595
- return getPlateActions(id).enabled(false);
6596
- };
6597
- }, [id]);
6811
+ if (!isFirstRender) {
6812
+ return;
6813
+ }
6814
+
6815
+ getPlateActions(id).value(normalizeEditorValue(documentToEditorValue(props.value), {
6816
+ plugins: plugins,
6817
+ disableCorePlugins: disableCorePlugins
6818
+ }));
6819
+ }, [isFirstRender, plugins, id, props.value]);
6598
6820
  return /*#__PURE__*/React__default.createElement(SdkProvider, {
6599
6821
  sdk: props.sdk
6600
6822
  }, /*#__PURE__*/React__default.createElement(ContentfulEditorIdProvider, {
@@ -6604,7 +6826,6 @@ var ConnectedRichTextEditor = function ConnectedRichTextEditor(props) {
6604
6826
  "data-test-id": "rich-text-editor"
6605
6827
  }, /*#__PURE__*/React__default.createElement(Plate, {
6606
6828
  id: id,
6607
- initialValue: initialValue,
6608
6829
  plugins: plugins,
6609
6830
  disableCorePlugins: disableCorePlugins,
6610
6831
  editableProps: {
@@ -6628,6 +6849,7 @@ var RichTextEditor = function RichTextEditor(props) {
6628
6849
  var isEmptyValue = useCallback(function (value) {
6629
6850
  return !value || deepEquals(value, EMPTY_DOCUMENT);
6630
6851
  }, []);
6852
+ var id = getContentfulEditorId(props.sdk);
6631
6853
  return /*#__PURE__*/React__default.createElement(EntityProvider, {
6632
6854
  sdk: sdk
6633
6855
  }, /*#__PURE__*/React__default.createElement(FieldConnector, {
@@ -6639,10 +6861,9 @@ var RichTextEditor = function RichTextEditor(props) {
6639
6861
  }, function (_ref) {
6640
6862
  var lastRemoteValue = _ref.lastRemoteValue,
6641
6863
  disabled = _ref.disabled,
6642
- setValue = _ref.setValue,
6643
- externalReset = _ref.externalReset;
6864
+ setValue = _ref.setValue;
6644
6865
  return /*#__PURE__*/React__default.createElement(ConnectedRichTextEditor, Object.assign({}, otherProps, {
6645
- key: "rich-text-editor-" + externalReset,
6866
+ key: "rich-text-editor-" + id,
6646
6867
  value: lastRemoteValue,
6647
6868
  sdk: sdk,
6648
6869
  onAction: onAction,