@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.
- package/dist/cjs/RichTextEditor.js +42 -53
- package/dist/cjs/SyncEditorValue.js +107 -0
- package/dist/cjs/Toolbar/components/EmbedEntityWidget.js +8 -3
- package/dist/cjs/helpers/__tests__/removeInternalMarks.test.js +37 -21
- package/dist/cjs/helpers/callbacks.js +35 -0
- package/dist/cjs/helpers/getAllowedResourcesForNodeType.js +25 -0
- package/dist/cjs/helpers/newResourceEntitySelectorConfigFromRichTextField.js +21 -0
- package/dist/cjs/helpers/toSlateValue.js +51 -0
- package/dist/cjs/internal/hooks.js +12 -2
- package/dist/cjs/internal/misc.js +0 -6
- package/dist/cjs/plugins/DragAndDrop/index.js +1 -0
- package/dist/cjs/plugins/EmbeddedEntityBlock/LinkedEntityBlock.js +27 -44
- package/dist/cjs/plugins/EmbeddedEntityBlock/index.js +3 -35
- package/dist/cjs/plugins/EmbeddedEntityInline/index.js +3 -2
- package/dist/cjs/plugins/EmbeddedResourceBlock/LinkedResourceBlock.js +54 -0
- package/dist/cjs/plugins/EmbeddedResourceBlock/index.js +55 -0
- package/dist/cjs/plugins/Hyperlink/components/EntityHyperlink.js +2 -1
- package/dist/cjs/plugins/Hyperlink/createHyperlinkPlugin.js +2 -3
- package/dist/cjs/plugins/Table/onKeyDownTable.js +14 -0
- package/dist/cjs/plugins/Text/__tests__/createTextPlugin.test.js +5 -15
- package/dist/cjs/plugins/Text/createTextPlugin.js +1 -0
- package/dist/cjs/plugins/index.js +2 -5
- package/dist/cjs/plugins/links-tracking.js +8 -17
- package/dist/cjs/plugins/{EmbeddedEntityBlock/ToolbarIcon.js → shared/EmbeddedBlockToolbarIcon.js} +15 -7
- package/dist/cjs/plugins/shared/EmbeddedBlockUtil.js +170 -0
- package/dist/cjs/plugins/shared/FetchingWrappedResourceCard.js +110 -0
- package/dist/cjs/plugins/shared/LinkedBlockWrapper.js +45 -0
- package/dist/esm/RichTextEditor.js +37 -48
- package/dist/esm/SyncEditorValue.js +53 -0
- package/dist/esm/Toolbar/components/EmbedEntityWidget.js +8 -3
- package/dist/esm/helpers/__tests__/removeInternalMarks.test.js +37 -21
- package/dist/esm/helpers/callbacks.js +20 -0
- package/dist/esm/helpers/getAllowedResourcesForNodeType.js +10 -0
- package/dist/esm/helpers/newResourceEntitySelectorConfigFromRichTextField.js +6 -0
- package/dist/{cjs/helpers/sanitizeIncomingSlateDoc.js → esm/helpers/toSlateValue.js} +13 -10
- package/dist/esm/internal/hooks.js +9 -2
- package/dist/esm/internal/misc.js +0 -3
- package/dist/esm/plugins/DragAndDrop/index.js +1 -0
- package/dist/esm/plugins/EmbeddedEntityBlock/LinkedEntityBlock.js +27 -44
- package/dist/esm/plugins/EmbeddedEntityBlock/index.js +3 -27
- package/dist/esm/plugins/EmbeddedEntityInline/index.js +4 -3
- package/dist/esm/plugins/EmbeddedResourceBlock/LinkedResourceBlock.js +39 -0
- package/dist/esm/plugins/EmbeddedResourceBlock/index.js +45 -0
- package/dist/esm/plugins/Hyperlink/components/EntityHyperlink.js +2 -1
- package/dist/esm/plugins/Hyperlink/createHyperlinkPlugin.js +2 -3
- package/dist/esm/plugins/Table/onKeyDownTable.js +15 -1
- package/dist/esm/plugins/Text/__tests__/createTextPlugin.test.js +5 -15
- package/dist/esm/plugins/Text/createTextPlugin.js +1 -0
- package/dist/esm/plugins/index.js +2 -5
- package/dist/esm/plugins/links-tracking.js +6 -10
- package/dist/esm/plugins/{EmbeddedEntityBlock/ToolbarIcon.js → shared/EmbeddedBlockToolbarIcon.js} +14 -6
- package/dist/esm/plugins/shared/EmbeddedBlockUtil.js +144 -0
- package/dist/esm/plugins/shared/FetchingWrappedResourceCard.js +56 -0
- package/dist/esm/plugins/shared/LinkedBlockWrapper.js +30 -0
- package/dist/types/ContentfulEditorProvider.d.ts +2 -3
- package/dist/types/RichTextEditor.d.ts +2 -2
- package/dist/types/SyncEditorValue.d.ts +13 -0
- package/dist/types/dialogs/HypelinkDialog/HyperlinkDialog.d.ts +3 -3
- package/dist/types/helpers/callbacks.d.ts +3 -0
- package/dist/types/helpers/getAllowedResourcesForNodeType.d.ts +25 -0
- package/dist/types/helpers/newResourceEntitySelectorConfigFromRichTextField.d.ts +16 -0
- package/dist/types/helpers/toSlateValue.d.ts +7 -0
- package/dist/types/internal/hooks.d.ts +4 -2
- package/dist/types/internal/misc.d.ts +2 -2
- package/dist/types/plugins/EmbeddedEntityBlock/LinkedEntityBlock.d.ts +0 -1
- package/dist/types/plugins/EmbeddedEntityBlock/index.d.ts +1 -2
- package/dist/types/plugins/EmbeddedResourceBlock/LinkedResourceBlock.d.ts +18 -0
- package/dist/types/plugins/EmbeddedResourceBlock/index.d.ts +3 -0
- package/dist/types/plugins/links-tracking.d.ts +3 -3
- package/dist/types/plugins/shared/EmbeddedBlockToolbarIcon.d.ts +11 -0
- package/dist/types/plugins/shared/EmbeddedBlockUtil.d.ts +8 -0
- package/dist/types/plugins/shared/FetchingWrappedResourceCard.d.ts +14 -0
- package/dist/types/plugins/shared/LinkedBlockWrapper.d.ts +25 -0
- package/dist/types/test-utils/createEditor.d.ts +2 -0
- package/dist/types/test-utils/jsx.d.ts +1 -1
- package/package.json +18 -18
- package/dist/cjs/plugins/EmbeddedEntityBlock/Util.js +0 -108
- package/dist/cjs/prepareDocument.js +0 -86
- package/dist/cjs/useOnValueChanged.js +0 -58
- package/dist/esm/helpers/sanitizeIncomingSlateDoc.js +0 -23
- package/dist/esm/plugins/EmbeddedEntityBlock/Util.js +0 -85
- package/dist/esm/prepareDocument.js +0 -57
- package/dist/esm/useOnValueChanged.js +0 -43
- package/dist/types/helpers/sanitizeIncomingSlateDoc.d.ts +0 -6
- package/dist/types/plugins/EmbeddedEntityBlock/ToolbarIcon.d.ts +0 -11
- package/dist/types/plugins/EmbeddedEntityBlock/Util.d.ts +0 -4
- package/dist/types/prepareDocument.d.ts +0 -19
- 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
|
|
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,
|
|
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 {
|
|
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
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
+
}
|
|
@@ -1,13 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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 =
|
|
5
|
-
|
|
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
|
+
};
|
|
@@ -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
|
-
|
|
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
|
|
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(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
}
|