@contentful/field-editor-rich-text 3.5.0 → 3.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/dist/cjs/RichTextEditor.js +42 -53
  2. package/dist/cjs/SyncEditorValue.js +107 -0
  3. package/dist/cjs/Toolbar/components/EmbedEntityWidget.js +8 -3
  4. package/dist/cjs/helpers/__tests__/removeInternalMarks.test.js +37 -21
  5. package/dist/cjs/helpers/callbacks.js +35 -0
  6. package/dist/cjs/helpers/getAllowedResourcesForNodeType.js +25 -0
  7. package/dist/cjs/helpers/newResourceEntitySelectorConfigFromRichTextField.js +21 -0
  8. package/dist/cjs/helpers/toSlateValue.js +51 -0
  9. package/dist/cjs/internal/hooks.js +12 -2
  10. package/dist/cjs/internal/misc.js +0 -6
  11. package/dist/cjs/plugins/DragAndDrop/index.js +1 -0
  12. package/dist/cjs/plugins/EmbeddedEntityBlock/LinkedEntityBlock.js +27 -44
  13. package/dist/cjs/plugins/EmbeddedEntityBlock/index.js +3 -35
  14. package/dist/cjs/plugins/EmbeddedEntityInline/index.js +3 -2
  15. package/dist/cjs/plugins/EmbeddedResourceBlock/LinkedResourceBlock.js +54 -0
  16. package/dist/cjs/plugins/EmbeddedResourceBlock/index.js +55 -0
  17. package/dist/cjs/plugins/Hyperlink/components/EntityHyperlink.js +2 -1
  18. package/dist/cjs/plugins/Hyperlink/createHyperlinkPlugin.js +2 -3
  19. package/dist/cjs/plugins/Table/onKeyDownTable.js +14 -0
  20. package/dist/cjs/plugins/Text/__tests__/createTextPlugin.test.js +5 -15
  21. package/dist/cjs/plugins/Text/createTextPlugin.js +1 -0
  22. package/dist/cjs/plugins/index.js +2 -5
  23. package/dist/cjs/plugins/links-tracking.js +8 -17
  24. package/dist/cjs/plugins/{EmbeddedEntityBlock/ToolbarIcon.js → shared/EmbeddedBlockToolbarIcon.js} +15 -7
  25. package/dist/cjs/plugins/shared/EmbeddedBlockUtil.js +170 -0
  26. package/dist/cjs/plugins/shared/FetchingWrappedResourceCard.js +110 -0
  27. package/dist/cjs/plugins/shared/LinkedBlockWrapper.js +45 -0
  28. package/dist/esm/RichTextEditor.js +37 -48
  29. package/dist/esm/SyncEditorValue.js +53 -0
  30. package/dist/esm/Toolbar/components/EmbedEntityWidget.js +8 -3
  31. package/dist/esm/helpers/__tests__/removeInternalMarks.test.js +37 -21
  32. package/dist/esm/helpers/callbacks.js +20 -0
  33. package/dist/esm/helpers/getAllowedResourcesForNodeType.js +10 -0
  34. package/dist/esm/helpers/newResourceEntitySelectorConfigFromRichTextField.js +6 -0
  35. package/dist/{cjs/helpers/sanitizeIncomingSlateDoc.js → esm/helpers/toSlateValue.js} +13 -10
  36. package/dist/esm/internal/hooks.js +9 -2
  37. package/dist/esm/internal/misc.js +0 -3
  38. package/dist/esm/plugins/DragAndDrop/index.js +1 -0
  39. package/dist/esm/plugins/EmbeddedEntityBlock/LinkedEntityBlock.js +27 -44
  40. package/dist/esm/plugins/EmbeddedEntityBlock/index.js +3 -27
  41. package/dist/esm/plugins/EmbeddedEntityInline/index.js +4 -3
  42. package/dist/esm/plugins/EmbeddedResourceBlock/LinkedResourceBlock.js +39 -0
  43. package/dist/esm/plugins/EmbeddedResourceBlock/index.js +45 -0
  44. package/dist/esm/plugins/Hyperlink/components/EntityHyperlink.js +2 -1
  45. package/dist/esm/plugins/Hyperlink/createHyperlinkPlugin.js +2 -3
  46. package/dist/esm/plugins/Table/onKeyDownTable.js +15 -1
  47. package/dist/esm/plugins/Text/__tests__/createTextPlugin.test.js +5 -15
  48. package/dist/esm/plugins/Text/createTextPlugin.js +1 -0
  49. package/dist/esm/plugins/index.js +2 -5
  50. package/dist/esm/plugins/links-tracking.js +6 -10
  51. package/dist/esm/plugins/{EmbeddedEntityBlock/ToolbarIcon.js → shared/EmbeddedBlockToolbarIcon.js} +14 -6
  52. package/dist/esm/plugins/shared/EmbeddedBlockUtil.js +144 -0
  53. package/dist/esm/plugins/shared/FetchingWrappedResourceCard.js +56 -0
  54. package/dist/esm/plugins/shared/LinkedBlockWrapper.js +30 -0
  55. package/dist/types/ContentfulEditorProvider.d.ts +2 -3
  56. package/dist/types/RichTextEditor.d.ts +2 -2
  57. package/dist/types/SyncEditorValue.d.ts +13 -0
  58. package/dist/types/dialogs/HypelinkDialog/HyperlinkDialog.d.ts +3 -3
  59. package/dist/types/helpers/callbacks.d.ts +3 -0
  60. package/dist/types/helpers/getAllowedResourcesForNodeType.d.ts +25 -0
  61. package/dist/types/helpers/newResourceEntitySelectorConfigFromRichTextField.d.ts +16 -0
  62. package/dist/types/helpers/toSlateValue.d.ts +7 -0
  63. package/dist/types/internal/hooks.d.ts +4 -2
  64. package/dist/types/internal/misc.d.ts +2 -2
  65. package/dist/types/plugins/EmbeddedEntityBlock/LinkedEntityBlock.d.ts +0 -1
  66. package/dist/types/plugins/EmbeddedEntityBlock/index.d.ts +1 -2
  67. package/dist/types/plugins/EmbeddedResourceBlock/LinkedResourceBlock.d.ts +18 -0
  68. package/dist/types/plugins/EmbeddedResourceBlock/index.d.ts +3 -0
  69. package/dist/types/plugins/links-tracking.d.ts +3 -3
  70. package/dist/types/plugins/shared/EmbeddedBlockToolbarIcon.d.ts +11 -0
  71. package/dist/types/plugins/shared/EmbeddedBlockUtil.d.ts +8 -0
  72. package/dist/types/plugins/shared/FetchingWrappedResourceCard.d.ts +14 -0
  73. package/dist/types/plugins/shared/LinkedBlockWrapper.d.ts +25 -0
  74. package/dist/types/test-utils/createEditor.d.ts +2 -0
  75. package/dist/types/test-utils/jsx.d.ts +1 -1
  76. package/package.json +18 -18
  77. package/dist/cjs/plugins/EmbeddedEntityBlock/Util.js +0 -108
  78. package/dist/cjs/prepareDocument.js +0 -86
  79. package/dist/cjs/useOnValueChanged.js +0 -58
  80. package/dist/esm/helpers/sanitizeIncomingSlateDoc.js +0 -23
  81. package/dist/esm/plugins/EmbeddedEntityBlock/Util.js +0 -85
  82. package/dist/esm/prepareDocument.js +0 -57
  83. package/dist/esm/useOnValueChanged.js +0 -43
  84. package/dist/types/helpers/sanitizeIncomingSlateDoc.d.ts +0 -6
  85. package/dist/types/plugins/EmbeddedEntityBlock/ToolbarIcon.d.ts +0 -11
  86. package/dist/types/plugins/EmbeddedEntityBlock/Util.d.ts +0 -4
  87. package/dist/types/prepareDocument.d.ts +0 -19
  88. package/dist/types/useOnValueChanged.d.ts +0 -8
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "FetchingWrappedResourceCard", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return FetchingWrappedResourceCard;
9
+ }
10
+ });
11
+ const _react = _interop_require_wildcard(require("react"));
12
+ const _f36components = require("@contentful/f36-components");
13
+ const _fieldeditorreference = require("@contentful/field-editor-reference");
14
+ const _fastdeepequal = _interop_require_default(require("fast-deep-equal"));
15
+ function _interop_require_default(obj) {
16
+ return obj && obj.__esModule ? obj : {
17
+ default: obj
18
+ };
19
+ }
20
+ function _getRequireWildcardCache(nodeInterop) {
21
+ if (typeof WeakMap !== "function") return null;
22
+ var cacheBabelInterop = new WeakMap();
23
+ var cacheNodeInterop = new WeakMap();
24
+ return (_getRequireWildcardCache = function(nodeInterop) {
25
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
26
+ })(nodeInterop);
27
+ }
28
+ function _interop_require_wildcard(obj, nodeInterop) {
29
+ if (!nodeInterop && obj && obj.__esModule) {
30
+ return obj;
31
+ }
32
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
33
+ return {
34
+ default: obj
35
+ };
36
+ }
37
+ var cache = _getRequireWildcardCache(nodeInterop);
38
+ if (cache && cache.has(obj)) {
39
+ return cache.get(obj);
40
+ }
41
+ var newObj = {};
42
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
43
+ for(var key in obj){
44
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
45
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
46
+ if (desc && (desc.get || desc.set)) {
47
+ Object.defineProperty(newObj, key, desc);
48
+ } else {
49
+ newObj[key] = obj[key];
50
+ }
51
+ }
52
+ }
53
+ newObj.default = obj;
54
+ if (cache) {
55
+ cache.set(obj, newObj);
56
+ }
57
+ return newObj;
58
+ }
59
+ const InternalEntryCard = _react.memo((props)=>{
60
+ if (props.status === 'loading') {
61
+ return _react.createElement(_f36components.EntryCard, {
62
+ isLoading: true
63
+ });
64
+ }
65
+ if (!props.data || props.status === 'error') {
66
+ return _react.createElement(_fieldeditorreference.MissingEntityCard, {
67
+ entityType: "Entry",
68
+ isDisabled: props.isDisabled,
69
+ onRemove: props.onRemove
70
+ });
71
+ }
72
+ const { contentType , resource: entry , space } = props.data;
73
+ return _react.createElement(_fieldeditorreference.WrappedEntryCard, {
74
+ size: "default",
75
+ getAsset: ()=>Promise.resolve(),
76
+ isSelected: props.isSelected,
77
+ isDisabled: props.isDisabled,
78
+ localeCode: props.data.defaultLocaleCode,
79
+ defaultLocaleCode: props.data.defaultLocaleCode,
80
+ contentType: contentType,
81
+ spaceName: space?.name,
82
+ entry: entry,
83
+ onEdit: props.onEdit,
84
+ onRemove: props.isDisabled ? undefined : props.onRemove,
85
+ isClickable: false,
86
+ getEntityScheduledActions: ()=>Promise.resolve([])
87
+ });
88
+ }, _fastdeepequal.default);
89
+ InternalEntryCard.displayName = 'ReferenceCard';
90
+ const FetchingWrappedResourceCard = (props)=>{
91
+ const { link , onEntityFetchComplete } = props;
92
+ const { data , status } = (0, _fieldeditorreference.useResource)(link.linkType, link.urn);
93
+ _react.useEffect(()=>{
94
+ if (status === 'success') {
95
+ onEntityFetchComplete?.();
96
+ }
97
+ }, [
98
+ onEntityFetchComplete,
99
+ status
100
+ ]);
101
+ return _react.createElement(InternalEntryCard, {
102
+ data: data,
103
+ status: status,
104
+ sdk: props.sdk,
105
+ isDisabled: props.isDisabled,
106
+ isSelected: props.isSelected,
107
+ onEdit: props.onEdit,
108
+ onRemove: props.onRemove
109
+ });
110
+ };
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "LinkedBlockWrapper", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return LinkedBlockWrapper;
9
+ }
10
+ });
11
+ const _react = _interop_require_default(require("react"));
12
+ const _emotion = require("emotion");
13
+ const _environment = require("../../helpers/environment");
14
+ function _interop_require_default(obj) {
15
+ return obj && obj.__esModule ? obj : {
16
+ default: obj
17
+ };
18
+ }
19
+ const styles = {
20
+ root: (0, _emotion.css)({
21
+ marginBottom: '1.25rem !important',
22
+ display: 'block'
23
+ }),
24
+ container: (0, _emotion.css)({
25
+ display: 'inline-block',
26
+ verticalAlign: 'text-top',
27
+ width: '100%'
28
+ })
29
+ };
30
+ const isResourceLink = (link)=>!!link.urn;
31
+ function LinkedBlockWrapper({ attributes , card , children , element }) {
32
+ const link = element.data.target.sys;
33
+ return _react.default.createElement("div", {
34
+ ...attributes,
35
+ className: styles.root,
36
+ "data-entity-type": link.linkType,
37
+ "data-entity-id": isResourceLink(link) ? link.urn : link.id,
38
+ contentEditable: _environment.IS_CHROME ? undefined : false,
39
+ draggable: _environment.IS_CHROME ? true : undefined
40
+ }, _react.default.createElement("div", {
41
+ contentEditable: _environment.IS_CHROME ? false : undefined,
42
+ draggable: _environment.IS_CHROME ? true : undefined,
43
+ className: styles.container
44
+ }, card), children);
45
+ }
@@ -1,20 +1,20 @@
1
- import React, { useCallback, useState, useEffect } from 'react';
1
+ import * as React from 'react';
2
2
  import { EntityProvider } from '@contentful/field-editor-reference';
3
3
  import { FieldConnector } from '@contentful/field-editor-shared';
4
4
  import * as Contentful from '@contentful/rich-text-types';
5
- import { Plate, getPlateActions } from '@udecode/plate-core';
5
+ import { Plate, PlateProvider } 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/noop';
9
9
  import { ContentfulEditorIdProvider, getContentfulEditorId } from './ContentfulEditorProvider';
10
- import { getPlateSelectors } from './internal/misc';
10
+ import { createOnChangeCallback } from './helpers/callbacks';
11
+ import { toSlateValue } from './helpers/toSlateValue';
11
12
  import { getPlugins, disableCorePlugins } from './plugins';
12
- import { documentToEditorValue, normalizeEditorValue, setEditorContent } from './prepareDocument';
13
13
  import { styles } from './RichTextEditor.styles';
14
14
  import { SdkProvider } from './SdkProvider';
15
+ import { SyncEditorValue } from './SyncEditorValue';
15
16
  import Toolbar from './Toolbar';
16
17
  import StickyToolbarWrapper from './Toolbar/components/StickyToolbarWrapper';
17
- import { useOnValueChanged } from './useOnValueChanged';
18
18
  export const ConnectedRichTextEditor = (props)=>{
19
19
  const id = getContentfulEditorId(props.sdk);
20
20
  const plugins = React.useMemo(()=>getPlugins(props.sdk, props.onAction ?? noop, props.restrictedMarks), [
@@ -22,43 +22,24 @@ export const ConnectedRichTextEditor = (props)=>{
22
22
  props.onAction,
23
23
  props.restrictedMarks
24
24
  ]);
25
- const [isFirstRender, setIsFirstRender] = useState(true);
26
- const [pendingExternalUpdate, setPendingExternalUpdate] = useState(false);
27
- const onValueChanged = useOnValueChanged({
28
- editorId: id,
29
- handler: props.onChange,
30
- skip: pendingExternalUpdate || isFirstRender,
31
- onSkip: ()=>setPendingExternalUpdate(false)
32
- });
33
- useEffect(()=>{
34
- setIsFirstRender(false);
35
- const editor = getPlateSelectors(id).editor();
36
- if (!editor) {
37
- return;
38
- }
39
- setPendingExternalUpdate(true);
40
- setEditorContent(editor, documentToEditorValue(props.value));
25
+ const handleChange = props.onChange;
26
+ const isFirstRender = React.useRef(true);
27
+ const value = toSlateValue(props.value);
28
+ const onChange = React.useMemo(()=>createOnChangeCallback((document)=>{
29
+ if (!isFirstRender.current && handleChange) {
30
+ handleChange(document);
31
+ }
32
+ }), [
33
+ handleChange
34
+ ]);
35
+ const firstInteractionHandler = React.useCallback(()=>{
36
+ isFirstRender.current = false;
41
37
  }, [
42
- props.value,
43
- id
38
+ isFirstRender
44
39
  ]);
45
40
  const classNames = cx(styles.editor, props.minHeight !== undefined ? css({
46
41
  minHeight: props.minHeight
47
42
  }) : undefined, props.isDisabled ? styles.disabled : styles.enabled, props.isToolbarHidden && styles.hiddenToolbar);
48
- useEffect(()=>{
49
- if (!isFirstRender) {
50
- return;
51
- }
52
- getPlateActions(id).value(normalizeEditorValue(documentToEditorValue(props.value), {
53
- plugins,
54
- disableCorePlugins
55
- }));
56
- }, [
57
- isFirstRender,
58
- plugins,
59
- id,
60
- props.value
61
- ]);
62
43
  return React.createElement(SdkProvider, {
63
44
  sdk: props.sdk
64
45
  }, React.createElement(ContentfulEditorIdProvider, {
@@ -66,25 +47,33 @@ export const ConnectedRichTextEditor = (props)=>{
66
47
  }, React.createElement("div", {
67
48
  className: styles.root,
68
49
  "data-test-id": "rich-text-editor"
69
- }, React.createElement(Plate, {
50
+ }, React.createElement(PlateProvider, {
70
51
  id: id,
52
+ initialValue: value,
53
+ normalizeInitialValue: true,
71
54
  plugins: plugins,
72
55
  disableCorePlugins: disableCorePlugins,
56
+ onChange: onChange
57
+ }, !props.isToolbarHidden && React.createElement(StickyToolbarWrapper, {
58
+ isDisabled: props.isDisabled
59
+ }, React.createElement(Toolbar, {
60
+ isDisabled: props.isDisabled
61
+ })), React.createElement(SyncEditorValue, {
62
+ incomingValue: value
63
+ }), React.createElement(Plate, {
64
+ id: id,
73
65
  editableProps: {
74
66
  className: classNames,
75
- readOnly: props.isDisabled
76
- },
77
- onChange: onValueChanged,
78
- firstChildren: !props.isToolbarHidden && React.createElement(StickyToolbarWrapper, {
79
- isDisabled: props.isDisabled
80
- }, React.createElement(Toolbar, {
81
- isDisabled: props.isDisabled
82
- }))
83
- }))));
67
+ readOnly: props.isDisabled,
68
+ onKeyDown: firstInteractionHandler,
69
+ onChange: firstInteractionHandler,
70
+ onClick: firstInteractionHandler
71
+ }
72
+ })))));
84
73
  };
85
74
  const RichTextEditor = (props)=>{
86
75
  const { sdk , isInitiallyDisabled , onAction , restrictedMarks , ...otherProps } = props;
87
- const isEmptyValue = useCallback((value)=>!value || deepEquals(value, Contentful.EMPTY_DOCUMENT), []);
76
+ const isEmptyValue = React.useCallback((value)=>!value || deepEquals(value, Contentful.EMPTY_DOCUMENT), []);
88
77
  const id = getContentfulEditorId(props.sdk);
89
78
  return React.createElement(EntityProvider, {
90
79
  sdk: sdk
@@ -0,0 +1,53 @@
1
+ import * as React from 'react';
2
+ import equal from 'fast-deep-equal';
3
+ import { usePlateSelectors } from './internal/hooks';
4
+ import { withoutNormalizing } from './internal/misc';
5
+ import { isNode, getEndPoint } from './internal/queries';
6
+ import { select } from './internal/transforms';
7
+ const setEditorContent = (editor, nodes)=>{
8
+ withoutNormalizing(editor, ()=>{
9
+ const children = [
10
+ ...editor.children
11
+ ];
12
+ children.forEach((node)=>editor.apply({
13
+ type: 'remove_node',
14
+ path: [
15
+ 0
16
+ ],
17
+ node
18
+ }));
19
+ if (nodes) {
20
+ const nodesArray = isNode(nodes) ? [
21
+ nodes
22
+ ] : nodes;
23
+ nodesArray.forEach((node, i)=>{
24
+ editor.apply({
25
+ type: 'insert_node',
26
+ path: [
27
+ i
28
+ ],
29
+ node
30
+ });
31
+ });
32
+ }
33
+ const point = getEndPoint(editor, []);
34
+ if (point) {
35
+ select(editor, point);
36
+ }
37
+ });
38
+ };
39
+ export const SyncEditorValue = ({ incomingValue })=>{
40
+ const editor = usePlateSelectors().editor();
41
+ const lastIncomingValue = React.useRef(incomingValue);
42
+ React.useEffect(()=>{
43
+ if (equal(lastIncomingValue.current, incomingValue)) {
44
+ return;
45
+ }
46
+ lastIncomingValue.current = incomingValue;
47
+ setEditorContent(editor, incomingValue);
48
+ }, [
49
+ editor,
50
+ incomingValue
51
+ ]);
52
+ return null;
53
+ };
@@ -3,8 +3,8 @@ import { BLOCKS, INLINES } from '@contentful/rich-text-types';
3
3
  import { useContentfulEditor } from '../../ContentfulEditorProvider';
4
4
  import { isLinkActive } from '../../helpers/editor';
5
5
  import { isNodeTypeEnabled } from '../../helpers/validations';
6
- import { ToolbarIcon as EmbeddedEntityBlockToolbarIcon } from '../../plugins/EmbeddedEntityBlock';
7
6
  import { ToolbarEmbeddedEntityInlineButton } from '../../plugins/EmbeddedEntityInline';
7
+ import { EmbeddedBlockToolbarIcon } from '../../plugins/shared/EmbeddedBlockToolbarIcon';
8
8
  import { useSdkContext } from '../../SdkProvider';
9
9
  import { EmbeddedEntityDropdownButton } from './EmbeddedEntityDropdownButton';
10
10
  export const EmbedEntityWidget = ({ isDisabled , canInsertBlocks })=>{
@@ -15,15 +15,20 @@ export const EmbedEntityWidget = ({ isDisabled , canInsertBlocks })=>{
15
15
  const onToggleEntityDropdown = ()=>setEmbedDropdownOpen(!isEmbedDropdownOpen);
16
16
  const inlineEntryEmbedEnabled = isNodeTypeEnabled(sdk.field, INLINES.EMBEDDED_ENTRY);
17
17
  const blockEntryEmbedEnabled = isNodeTypeEnabled(sdk.field, BLOCKS.EMBEDDED_ENTRY) && canInsertBlocks;
18
+ const blockResourceEmbedEnabled = isNodeTypeEnabled(sdk.field, BLOCKS.EMBEDDED_RESOURCE) && canInsertBlocks;
18
19
  const blockAssetEmbedEnabled = isNodeTypeEnabled(sdk.field, BLOCKS.EMBEDDED_ASSET) && canInsertBlocks;
19
- const actions = React.createElement(React.Fragment, null, blockEntryEmbedEnabled && React.createElement(EmbeddedEntityBlockToolbarIcon, {
20
+ const actions = React.createElement(React.Fragment, null, blockEntryEmbedEnabled && React.createElement(EmbeddedBlockToolbarIcon, {
20
21
  isDisabled: !!isDisabled,
21
22
  nodeType: BLOCKS.EMBEDDED_ENTRY,
22
23
  onClose: onCloseEntityDropdown
24
+ }), blockResourceEmbedEnabled && React.createElement(EmbeddedBlockToolbarIcon, {
25
+ isDisabled: !!isDisabled,
26
+ nodeType: BLOCKS.EMBEDDED_RESOURCE,
27
+ onClose: onCloseEntityDropdown
23
28
  }), inlineEntryEmbedEnabled && React.createElement(ToolbarEmbeddedEntityInlineButton, {
24
29
  isDisabled: !!isDisabled || isLinkActive(editor),
25
30
  onClose: onCloseEntityDropdown
26
- }), blockAssetEmbedEnabled && React.createElement(EmbeddedEntityBlockToolbarIcon, {
31
+ }), blockAssetEmbedEnabled && React.createElement(EmbeddedBlockToolbarIcon, {
27
32
  isDisabled: !!isDisabled,
28
33
  nodeType: BLOCKS.EMBEDDED_ASSET,
29
34
  onClose: onCloseEntityDropdown
@@ -7,36 +7,52 @@ describe('internal mark', ()=>{
7
7
  const data = [
8
8
  {
9
9
  title: 'Paragraph mark is removed',
10
- input: toContentfulDocument(jsx("editor", null, jsx("hp", null, jsx("htext", {
11
- [COMMAND_PROMPT]: true
12
- }))).children),
13
- expected: toContentfulDocument(jsx("editor", null, jsx("hp", null, jsx("htext", null))).children)
10
+ input: toContentfulDocument({
11
+ document: jsx("editor", null, jsx("hp", null, jsx("htext", {
12
+ [COMMAND_PROMPT]: true
13
+ }))).children
14
+ }),
15
+ expected: toContentfulDocument({
16
+ document: jsx("editor", null, jsx("hp", null, jsx("htext", null))).children
17
+ })
14
18
  },
15
19
  {
16
20
  title: 'Heading mark is removed',
17
- input: toContentfulDocument(jsx("editor", null, jsx("hh1", null, jsx("htext", {
18
- [COMMAND_PROMPT]: true
19
- }))).children),
20
- expected: toContentfulDocument(jsx("editor", null, jsx("hh1", null, jsx("htext", null))).children)
21
+ input: toContentfulDocument({
22
+ document: jsx("editor", null, jsx("hh1", null, jsx("htext", {
23
+ [COMMAND_PROMPT]: true
24
+ }))).children
25
+ }),
26
+ expected: toContentfulDocument({
27
+ document: jsx("editor", null, jsx("hh1", null, jsx("htext", null))).children
28
+ })
21
29
  },
22
30
  {
23
31
  title: 'Block quote mark is removed',
24
- input: toContentfulDocument(jsx("editor", null, jsx("hquote", null, jsx("hp", null, jsx("htext", {
25
- [COMMAND_PROMPT]: true
26
- })))).children),
27
- expected: toContentfulDocument(jsx("editor", null, jsx("hquote", null, jsx("hp", null, jsx("htext", null)))).children)
32
+ input: toContentfulDocument({
33
+ document: jsx("editor", null, jsx("hquote", null, jsx("hp", null, jsx("htext", {
34
+ [COMMAND_PROMPT]: true
35
+ })))).children
36
+ }),
37
+ expected: toContentfulDocument({
38
+ document: jsx("editor", null, jsx("hquote", null, jsx("hp", null, jsx("htext", null)))).children
39
+ })
28
40
  },
29
41
  {
30
42
  title: 'Other marks are not removed',
31
- input: toContentfulDocument(jsx("editor", null, jsx("hquote", null, jsx("hp", null, jsx("htext", {
32
- bold: true,
33
- underline: true,
34
- [COMMAND_PROMPT]: true
35
- })))).children),
36
- expected: toContentfulDocument(jsx("editor", null, jsx("hquote", null, jsx("hp", null, jsx("htext", {
37
- bold: true,
38
- underline: true
39
- })))).children)
43
+ input: toContentfulDocument({
44
+ document: jsx("editor", null, jsx("hquote", null, jsx("hp", null, jsx("htext", {
45
+ bold: true,
46
+ underline: true,
47
+ [COMMAND_PROMPT]: true
48
+ })))).children
49
+ }),
50
+ expected: toContentfulDocument({
51
+ document: jsx("editor", null, jsx("hquote", null, jsx("hp", null, jsx("htext", {
52
+ bold: true,
53
+ underline: true
54
+ })))).children
55
+ })
40
56
  }
41
57
  ];
42
58
  for (const { input , expected , title } of data){
@@ -0,0 +1,20 @@
1
+ import { toContentfulDocument } from '@contentful/contentful-slatejs-adapter';
2
+ import equal from 'fast-deep-equal';
3
+ import debounce from 'lodash/debounce';
4
+ import schema from '../constants/Schema';
5
+ import { removeInternalMarks } from './removeInternalMarks';
6
+ export const createOnChangeCallback = (handler)=>{
7
+ let cache = null;
8
+ return debounce((document)=>{
9
+ if (equal(document, cache)) {
10
+ return;
11
+ }
12
+ cache = document;
13
+ const doc = removeInternalMarks(toContentfulDocument({
14
+ document: document,
15
+ schema: schema
16
+ }));
17
+ const cleanedDocument = removeInternalMarks(doc);
18
+ handler?.(cleanedDocument);
19
+ }, 500);
20
+ };
@@ -0,0 +1,10 @@
1
+ import find from 'lodash/find';
2
+ import flow from 'lodash/flow';
3
+ import get from 'lodash/get';
4
+ export default function getAllowedResourcesForNodeType(field, nodeType) {
5
+ return flow((validations)=>find(validations, 'nodes'), (validations)=>get(validations, [
6
+ 'nodes',
7
+ nodeType,
8
+ 'allowedResources'
9
+ ], []))(field.validations);
10
+ }
@@ -0,0 +1,6 @@
1
+ import getAllowedResourcesForNodeType from './getAllowedResourcesForNodeType';
2
+ export default function newResourceEntitySelectorConfigFromRichTextField(field, nodeType) {
3
+ return {
4
+ allowedResources: getAllowedResourcesForNodeType(field, nodeType)
5
+ };
6
+ }
@@ -1,13 +1,6 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "sanitizeIncomingSlateDoc", {
6
- enumerable: true,
7
- get: function() {
8
- return sanitizeIncomingSlateDoc;
9
- }
10
- });
1
+ import { toSlatejsDocument } from '@contentful/contentful-slatejs-adapter';
2
+ import { EMPTY_DOCUMENT } from '@contentful/rich-text-types';
3
+ import schema from '../constants/Schema';
11
4
  const isTextElement = (node)=>'text' in node;
12
5
  function sanitizeIncomingSlateDoc(nodes = []) {
13
6
  return nodes.map((node)=>{
@@ -31,3 +24,13 @@ function sanitizeIncomingSlateDoc(nodes = []) {
31
24
  };
32
25
  });
33
26
  }
27
+ export const toSlateValue = (doc)=>{
28
+ const hasContent = (doc)=>{
29
+ return (doc?.content || []).length > 0;
30
+ };
31
+ const slateDoc = toSlatejsDocument({
32
+ document: doc && hasContent(doc) ? doc : EMPTY_DOCUMENT,
33
+ schema
34
+ });
35
+ return sanitizeIncomingSlateDoc(slateDoc);
36
+ };
@@ -1,5 +1,12 @@
1
1
  import * as p from '@udecode/plate-core';
2
2
  import * as sr from 'slate-react';
3
3
  export const useReadOnly = sr.useReadOnly;
4
- export const usePlateEditorRef = p.usePlateEditorRef;
5
- export const usePlateEditorState = p.usePlateEditorState;
4
+ export const usePlateEditorRef = (id)=>{
5
+ return p.usePlateEditorRef(id);
6
+ };
7
+ export const usePlateEditorState = (id)=>{
8
+ return p.usePlateEditorState(id);
9
+ };
10
+ export const usePlateSelectors = (id)=>{
11
+ return p.usePlateSelectors(id);
12
+ };
@@ -23,6 +23,3 @@ export const fromDOMPoint = (editor, domPoint, opts = {
23
23
  export const mockPlugin = (plugin)=>{
24
24
  return p.mockPlugin(plugin);
25
25
  };
26
- export const getPlateSelectors = (id)=>{
27
- return p.getPlateSelectors(id);
28
- };
@@ -4,6 +4,7 @@ export function createDragAndDropPlugin() {
4
4
  const DRAGGABLE_TYPES = [
5
5
  BLOCKS.EMBEDDED_ENTRY,
6
6
  BLOCKS.EMBEDDED_ASSET,
7
+ BLOCKS.EMBEDDED_RESOURCE,
7
8
  BLOCKS.HR,
8
9
  INLINES.EMBEDDED_ENTRY
9
10
  ];
@@ -1,26 +1,16 @@
1
1
  import * as React from 'react';
2
- import { css } from 'emotion';
3
2
  import { useReadOnly, useSelected } from 'slate-react';
4
3
  import { useContentfulEditor } from '../../ContentfulEditorProvider';
5
- import { IS_CHROME } from '../../helpers/environment';
6
4
  import { findNodePath } from '../../internal/queries';
7
5
  import { removeNodes } from '../../internal/transforms';
8
6
  import { useSdkContext } from '../../SdkProvider';
7
+ import { useLinkTracking } from '../links-tracking';
9
8
  import { FetchingWrappedAssetCard } from '../shared/FetchingWrappedAssetCard';
10
9
  import { FetchingWrappedEntryCard } from '../shared/FetchingWrappedEntryCard';
11
- const styles = {
12
- root: css({
13
- marginBottom: '1.25rem !important',
14
- display: 'block'
15
- }),
16
- container: css({
17
- display: 'inline-block',
18
- verticalAlign: 'text-top',
19
- width: '100%'
20
- })
21
- };
10
+ import { LinkedBlockWrapper } from '../shared/LinkedBlockWrapper';
22
11
  export function LinkedEntityBlock(props) {
23
- const { attributes , children , element , onEntityFetchComplete } = props;
12
+ const { attributes , children , element } = props;
13
+ const { onEntityFetchComplete } = useLinkTracking();
24
14
  const isSelected = useSelected();
25
15
  const editor = useContentfulEditor();
26
16
  const sdk = useSdkContext();
@@ -46,34 +36,27 @@ export function LinkedEntityBlock(props) {
46
36
  editor,
47
37
  element
48
38
  ]);
49
- return React.createElement("div", {
50
- ...attributes,
51
- className: styles.root,
52
- "data-entity-type": entityType,
53
- "data-entity-id": entityId,
54
- contentEditable: IS_CHROME ? undefined : false,
55
- draggable: IS_CHROME ? true : undefined
56
- }, React.createElement("div", {
57
- contentEditable: IS_CHROME ? false : undefined,
58
- draggable: IS_CHROME ? true : undefined,
59
- className: styles.container
60
- }, entityType === 'Entry' && React.createElement(FetchingWrappedEntryCard, {
61
- sdk: sdk,
62
- entryId: entityId,
63
- locale: sdk.field.locale,
64
- isDisabled: isDisabled,
65
- isSelected: isSelected,
66
- onRemove: handleRemoveClick,
67
- onEdit: handleEditClick,
68
- onEntityFetchComplete: onEntityFetchComplete
69
- }), entityType === 'Asset' && React.createElement(FetchingWrappedAssetCard, {
70
- sdk: sdk,
71
- assetId: entityId,
72
- locale: sdk.field.locale,
73
- isDisabled: isDisabled,
74
- isSelected: isSelected,
75
- onRemove: handleRemoveClick,
76
- onEdit: handleEditClick,
77
- onEntityFetchComplete: onEntityFetchComplete
78
- })), children);
39
+ return React.createElement(LinkedBlockWrapper, {
40
+ attributes: attributes,
41
+ card: React.createElement(React.Fragment, null, entityType === 'Entry' && React.createElement(FetchingWrappedEntryCard, {
42
+ sdk: sdk,
43
+ entryId: entityId,
44
+ locale: sdk.field.locale,
45
+ isDisabled: isDisabled,
46
+ isSelected: isSelected,
47
+ onRemove: handleRemoveClick,
48
+ onEdit: handleEditClick,
49
+ onEntityFetchComplete: onEntityFetchComplete
50
+ }), entityType === 'Asset' && React.createElement(FetchingWrappedAssetCard, {
51
+ sdk: sdk,
52
+ assetId: entityId,
53
+ locale: sdk.field.locale,
54
+ isDisabled: isDisabled,
55
+ isSelected: isSelected,
56
+ onRemove: handleRemoveClick,
57
+ onEdit: handleEditClick,
58
+ onEntityFetchComplete: onEntityFetchComplete
59
+ })),
60
+ element: element
61
+ }, children);
79
62
  }