@squiz/formatted-text-editor 2.1.0 → 2.2.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/CHANGELOG.md +24 -0
- package/demo/App.tsx +5 -0
- package/demo/AppContext.tsx +107 -70
- package/lib/EditorToolbar/FloatingToolbar.js +1 -1
- package/lib/EditorToolbar/Tools/ContentTools/ContentToolsDropdown.js +3 -3
- package/lib/EditorToolbar/Tools/Image/Form/ImageForm.d.ts +2 -1
- package/lib/EditorToolbar/Tools/Image/Form/ImageForm.js +53 -10
- package/lib/EditorToolbar/Tools/Image/ImageButton.js +8 -5
- package/lib/EditorToolbar/Tools/Image/ImageModal.js +3 -1
- package/lib/Extensions/Extensions.d.ts +1 -0
- package/lib/Extensions/Extensions.js +3 -0
- package/lib/Extensions/FetchUrlExtension/FetchUrlExtension.js +6 -0
- package/lib/Extensions/ImageExtension/DAMImageExtension.d.ts +17 -0
- package/lib/Extensions/ImageExtension/DAMImageExtension.js +97 -0
- package/lib/ui/Fields/ResourceBrowserSelector/ResourceBrowserSelector.d.ts +28 -0
- package/lib/ui/Fields/ResourceBrowserSelector/ResourceBrowserSelector.js +88 -0
- package/lib/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.js +9 -0
- package/lib/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.js +9 -0
- package/package.json +4 -2
- package/src/EditorToolbar/FloatingToolbar.spec.tsx +3 -1
- package/src/EditorToolbar/FloatingToolbar.tsx +1 -1
- package/src/EditorToolbar/Tools/ContentTools/ContentToolsDropdown.tsx +3 -3
- package/src/EditorToolbar/Tools/Image/Form/ImageForm.spec.tsx +27 -2
- package/src/EditorToolbar/Tools/Image/Form/ImageForm.tsx +61 -14
- package/src/EditorToolbar/Tools/Image/ImageButton.spec.tsx +70 -2
- package/src/EditorToolbar/Tools/Image/ImageButton.tsx +12 -6
- package/src/EditorToolbar/Tools/Image/ImageModal.tsx +4 -1
- package/src/Extensions/Extensions.ts +3 -0
- package/src/Extensions/FetchUrlExtension/FetchUrlExtension.ts +9 -0
- package/src/Extensions/ImageExtension/DAMImageExtension.spec.ts +87 -0
- package/src/Extensions/ImageExtension/DAMImageExtension.ts +119 -0
- package/src/ui/Fields/ResourceBrowserSelector/ResourceBrowserSelector.spec.tsx +219 -0
- package/src/ui/Fields/ResourceBrowserSelector/ResourceBrowserSelector.tsx +109 -0
- package/src/utils/converters/mocks/squizNodeJson.mock.ts +21 -0
- package/src/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.ts +10 -0
- package/src/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.ts +8 -0
- package/src/utils/getNodeNamesByGroup.spec.ts +1 -0
- package/tests/index.ts +1 -0
- package/tests/mockResourceBrowser.tsx +46 -0
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,29 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 2.2.1
|
4
|
+
|
5
|
+
### Patch Changes
|
6
|
+
|
7
|
+
- b4b34a6: Added basic checks in case no content tools are provided (no context)
|
8
|
+
|
9
|
+
## 2.2.0
|
10
|
+
|
11
|
+
### Minor Changes
|
12
|
+
|
13
|
+
- 985e1a5: ### Updates to DAM asset resolver package
|
14
|
+
|
15
|
+
**Changes:**
|
16
|
+
|
17
|
+
- Updated DAM resolver package versions.
|
18
|
+
- Updated Json validation schema so multiple resolvers can be used for SquizImage type.
|
19
|
+
- Updated higher order node map so Dam images could be resolved to simple url.
|
20
|
+
- Updated page builder resolver to handle DAM images
|
21
|
+
|
22
|
+
### Patch Changes
|
23
|
+
|
24
|
+
- Updated dependencies [985e1a5]
|
25
|
+
- @squiz/dx-json-schema-lib@1.72.0
|
26
|
+
|
3
27
|
## 2.1.0
|
4
28
|
|
5
29
|
### Minor Changes
|
package/demo/App.tsx
CHANGED
@@ -81,6 +81,11 @@ function App() {
|
|
81
81
|
<a href="https://www.google.com"><strong>Mr Bean</strong></a>, nice to <a href="https://www.google.com">meet you</a>.
|
82
82
|
<img src="https://media2.giphy.com/media/3o6ozsIxg5legYvggo/giphy.gif" height="150" width="200"/>
|
83
83
|
<img data-matrix-asset-id="1" data-matrix-identifier="matrixIdentifier" data-matrix-domain="https://matrix-domain.squiz.net">
|
84
|
+
<img
|
85
|
+
data-dam-object-id="CA87B42E-9410-402F-B3669D6900DD0793"
|
86
|
+
data-dam-system-identifier="byder001"
|
87
|
+
data-dam-system-type="bynder"
|
88
|
+
>
|
84
89
|
</p>
|
85
90
|
`}
|
86
91
|
onChange={handleEditorChange}
|
package/demo/AppContext.tsx
CHANGED
@@ -5,89 +5,126 @@ import MatrixResourceBrowserPlugin, {
|
|
5
5
|
Resource,
|
6
6
|
ResourceReference,
|
7
7
|
} from '@squiz/matrix-resource-browser-plugin';
|
8
|
+
import DamResourceBrowserPlugin from '@squiz/dam-resource-browser-plugin';
|
8
9
|
import { EditorContext } from '../src';
|
9
10
|
import resources from './resources.json';
|
10
11
|
import sources from './sources.json';
|
11
12
|
import { ResolveNodeType } from '../src/types';
|
12
13
|
import { AiServiceProvider } from '@squiz/dxp-ai-client-react';
|
14
|
+
import { QueryClientProvider, QueryClient } from 'react-query';
|
13
15
|
|
14
16
|
export type AppContextProps = PropsWithChildren;
|
17
|
+
|
18
|
+
// Set up React query for testing
|
19
|
+
const createTestQueryClient = () =>
|
20
|
+
new QueryClient({
|
21
|
+
defaultOptions: {
|
22
|
+
queries: {
|
23
|
+
retry: false,
|
24
|
+
},
|
25
|
+
},
|
26
|
+
});
|
27
|
+
|
28
|
+
const testQueryClient = createTestQueryClient();
|
29
|
+
|
15
30
|
export const AppContext = ({ children }: AppContextProps) => (
|
16
|
-
<
|
17
|
-
|
18
|
-
|
19
|
-
Promise
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
31
|
+
<QueryClientProvider client={testQueryClient}>
|
32
|
+
<ResourceBrowserContextProvider
|
33
|
+
value={{
|
34
|
+
onRequestSources: (): Promise<ResourceBrowserSource[]> =>
|
35
|
+
Promise.resolve([
|
36
|
+
{
|
37
|
+
name: 'Matrix',
|
38
|
+
id: 'matrixIdentifier',
|
39
|
+
type: 'matrix',
|
40
|
+
},
|
41
|
+
{
|
42
|
+
name: 'Bynder',
|
43
|
+
id: 'byder001',
|
44
|
+
type: 'dam',
|
45
|
+
configuration: {
|
46
|
+
externalType: 'bynder',
|
47
|
+
},
|
48
|
+
},
|
49
|
+
]),
|
50
|
+
plugins: [
|
51
|
+
DamResourceBrowserPlugin(),
|
52
|
+
MatrixResourceBrowserPlugin({
|
53
|
+
onRequestSources: (): Promise<Source> => Promise.resolve(sources),
|
54
|
+
onRequestChildren: (source: Source, resource: Resource | null): Promise<Resource[]> =>
|
55
|
+
Promise.resolve(resource._children || resources),
|
56
|
+
onRequestResource: (reference: ResourceReference): Promise<Resource | null> => {
|
57
|
+
const flattenResources = (resources: unknown[]) => {
|
58
|
+
return [
|
59
|
+
...resources,
|
60
|
+
...resources.flatMap((resource) =>
|
61
|
+
'_children' in resource ? flattenResources(resource._children) : [],
|
62
|
+
),
|
63
|
+
];
|
64
|
+
};
|
40
65
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
}}
|
48
|
-
>
|
49
|
-
<AiServiceProvider
|
50
|
-
clientConfig={{
|
51
|
-
// We are using a simple Express proxy here for testing locally in FTE
|
52
|
-
// You can find this proxy here: https://gitlab.squiz.net/tgrob/dxp-ai-client-proxy
|
53
|
-
baseUrl: 'http://localhost:7777',
|
54
|
-
baseApiParams: {
|
55
|
-
headers: {
|
56
|
-
// You will need to create an API key to test this in FTE, details can be found here:
|
57
|
-
// https://squizgroup.atlassian.net/wiki/spaces/PRODUCT/pages/2895119377/FEaaS+Playbook+Configuring+a+Matrix+instance+for+the+Component+Service#Create-an-API-key
|
58
|
-
'x-api-key': '',
|
59
|
-
},
|
60
|
-
},
|
61
|
-
customFetch: async (input, init) => {
|
62
|
-
const response = await fetch(input, init);
|
63
|
-
return response;
|
64
|
-
},
|
66
|
+
return Promise.resolve(
|
67
|
+
flattenResources(resources).find((resource) => resource.id === reference.resource) || null,
|
68
|
+
);
|
69
|
+
},
|
70
|
+
}),
|
71
|
+
],
|
65
72
|
}}
|
66
|
-
tags={['tag1']}
|
67
73
|
>
|
68
|
-
<
|
69
|
-
|
70
|
-
|
71
|
-
|
74
|
+
<AiServiceProvider
|
75
|
+
clientConfig={{
|
76
|
+
// We are using a simple Express proxy here for testing locally in FTE
|
77
|
+
// You can find this proxy here: https://gitlab.squiz.net/tgrob/dxp-ai-client-proxy
|
78
|
+
baseUrl: 'http://localhost:7777',
|
79
|
+
baseApiParams: {
|
80
|
+
headers: {
|
81
|
+
// You will need to create an API key to test this in FTE, details can be found here:
|
82
|
+
// https://squizgroup.atlassian.net/wiki/spaces/PRODUCT/pages/2895119377/FEaaS+Playbook+Configuring+a+Matrix+instance+for+the+Component+Service#Create-an-API-key
|
83
|
+
'x-api-key': '',
|
84
|
+
},
|
72
85
|
},
|
73
|
-
|
74
|
-
const
|
75
|
-
|
76
|
-
return [
|
77
|
-
...resources,
|
78
|
-
...resources.flatMap((resource) =>
|
79
|
-
'_children' in resource ? flattenResources(resource._children) : [],
|
80
|
-
),
|
81
|
-
];
|
82
|
-
};
|
83
|
-
|
84
|
-
const resource = flattenResources(resources).find((resource) => resource.id === nodeResource);
|
85
|
-
return Promise.resolve(resource.url || '');
|
86
|
+
customFetch: async (input, init) => {
|
87
|
+
const response = await fetch(input, init);
|
88
|
+
return response;
|
86
89
|
},
|
87
90
|
}}
|
91
|
+
tags={['tag1']}
|
88
92
|
>
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
+
<EditorContext.Provider
|
94
|
+
value={{
|
95
|
+
matrix: {
|
96
|
+
matrixDomain: 'https://matrix-domain.squiz.net',
|
97
|
+
},
|
98
|
+
resolveNodeToUrl: (node: ResolveNodeType): Promise<string> => {
|
99
|
+
console.log(`resolveNodeToUrl ${JSON.stringify(node)}`);
|
100
|
+
// Matrix Resource
|
101
|
+
if (node.matrixAssetId) {
|
102
|
+
const nodeResource = node.matrixAssetId;
|
103
|
+
const flattenResources = (resources: unknown[]) => {
|
104
|
+
return [
|
105
|
+
...resources,
|
106
|
+
...resources.flatMap((resource) =>
|
107
|
+
'_children' in resource ? flattenResources(resource._children) : [],
|
108
|
+
),
|
109
|
+
];
|
110
|
+
};
|
111
|
+
|
112
|
+
const resource = flattenResources(resources).find((resource) => resource.id === nodeResource);
|
113
|
+
return Promise.resolve(resource.url || '');
|
114
|
+
}
|
115
|
+
|
116
|
+
// DAM Resource
|
117
|
+
if (node.damSystemType === 'bynder') {
|
118
|
+
return Promise.resolve('https://squiz-sandbox.bynder.com/m/4c92419541508c37/original/rx77.jpg');
|
119
|
+
}
|
120
|
+
|
121
|
+
return Promise.resolve('');
|
122
|
+
},
|
123
|
+
}}
|
124
|
+
>
|
125
|
+
{children}
|
126
|
+
</EditorContext.Provider>
|
127
|
+
</AiServiceProvider>
|
128
|
+
</ResourceBrowserContextProvider>
|
129
|
+
</QueryClientProvider>
|
93
130
|
);
|
@@ -52,7 +52,7 @@ const FloatingToolbar = () => {
|
|
52
52
|
extensionNames.italic && react_1.default.createElement(ItalicButton_1.default, { key: "italic" }),
|
53
53
|
extensionNames.underline && react_1.default.createElement(UnderlineButton_1.default, { key: "underline" }),
|
54
54
|
];
|
55
|
-
if (active.image() || active.assetImage()) {
|
55
|
+
if (active.image() || active.assetImage() || active.DAMImage()) {
|
56
56
|
buttons = [react_1.default.createElement(ImageButton_1.default, { key: "add-image", inPopover: true })];
|
57
57
|
}
|
58
58
|
else if (marks?.[Extensions_1.MarkName.Link].isExclusivelyActive || marks?.[Extensions_1.MarkName.AssetLink].isExclusivelyActive) {
|
@@ -10,7 +10,7 @@ const dxp_ai_client_react_1 = require("@squiz/dxp-ai-client-react");
|
|
10
10
|
const react_2 = require("@remirror/react");
|
11
11
|
const ContentToolsDropdown = () => {
|
12
12
|
const { contentTools } = (0, dxp_ai_client_react_1.useAiService)();
|
13
|
-
const dropdownItems = contentTools
|
13
|
+
const dropdownItems = contentTools?.map((item) => ({
|
14
14
|
items: [
|
15
15
|
{
|
16
16
|
action: () => alert(JSON.stringify(item, null, 2)),
|
@@ -21,7 +21,7 @@ const ContentToolsDropdown = () => {
|
|
21
21
|
key: item.id,
|
22
22
|
}));
|
23
23
|
// No content tools to show, don't show dropdown at all
|
24
|
-
if (contentTools
|
24
|
+
if (!contentTools || contentTools?.length === 0) {
|
25
25
|
return null;
|
26
26
|
}
|
27
27
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
@@ -30,6 +30,6 @@ const ContentToolsDropdown = () => {
|
|
30
30
|
format: sds_1.BUTTON_FORMAT_TRANSPARENT,
|
31
31
|
icon: AiIcon_1.ICON_AI,
|
32
32
|
theme: sds_1.BUTTON_THEME_DEFAULT,
|
33
|
-
}, className: "content-tools-dropdown", dropdownPosition: sds_1.DROPDOWN_POSITION_RIGHT, heading: 'Rewrite to...', sections: dropdownItems })));
|
33
|
+
}, className: "content-tools-dropdown", dropdownPosition: sds_1.DROPDOWN_POSITION_RIGHT, heading: 'Rewrite to...', sections: dropdownItems ?? [] })));
|
34
34
|
};
|
35
35
|
exports.default = ContentToolsDropdown;
|
@@ -3,11 +3,12 @@ import { SubmitHandler } from 'react-hook-form';
|
|
3
3
|
import { ImageAttributes } from '@remirror/extension-image/dist-types/image-extension';
|
4
4
|
import { NodeName } from '../../../../Extensions/Extensions';
|
5
5
|
import { AssetImageAttributes } from '../../../../Extensions/ImageExtension/AssetImageExtension';
|
6
|
+
import { DAMImageAttributes } from '../../../../Extensions/ImageExtension/DAMImageExtension';
|
6
7
|
import { DeepPartial } from '../../../../types';
|
7
8
|
export type ImageFormData = {
|
8
9
|
imageType: NodeName;
|
9
10
|
image: Pick<ImageAttributes, 'src' | 'alt' | 'width' | 'height'>;
|
10
|
-
|
11
|
+
resourceImage: AssetImageAttributes & DAMImageAttributes;
|
11
12
|
};
|
12
13
|
export type FormProps = {
|
13
14
|
data: DeepPartial<ImageFormData>;
|
@@ -37,16 +37,22 @@ const InsertLinkRounded_1 = __importDefault(require("@mui/icons-material/InsertL
|
|
37
37
|
const Extensions_1 = require("../../../../Extensions/Extensions");
|
38
38
|
const validation_1 = require("../../../../utils/validation");
|
39
39
|
const Tabs_1 = require("../../../../ui/Tabs/Tabs");
|
40
|
-
const
|
40
|
+
const ResourceBrowserSelector_1 = require("../../../../ui/Fields/ResourceBrowserSelector/ResourceBrowserSelector");
|
41
|
+
var ViewTypes;
|
42
|
+
(function (ViewTypes) {
|
43
|
+
ViewTypes["Resource"] = "Resource";
|
44
|
+
ViewTypes["URL"] = "URL";
|
45
|
+
})(ViewTypes || (ViewTypes = {}));
|
41
46
|
const imageTypeOptions = {
|
42
|
-
[
|
43
|
-
[
|
47
|
+
[ViewTypes.Resource]: { label: 'From source' },
|
48
|
+
[ViewTypes.URL]: { label: 'From URL' },
|
44
49
|
};
|
45
50
|
const ImageForm = ({ data, onSubmit }) => {
|
46
51
|
const { control, register, handleSubmit, setValue, watch, formState: { errors }, } = (0, react_hook_form_1.useForm)({
|
47
52
|
defaultValues: data,
|
48
53
|
});
|
49
|
-
const imageType = watch('imageType')
|
54
|
+
const imageType = watch('imageType');
|
55
|
+
const [viewType, setViewType] = (0, react_1.useState)(ViewTypes.Resource);
|
50
56
|
const [aspectRatioFromWidth, setAspectRatioFromWidth] = (0, react_1.useState)(9 / 16);
|
51
57
|
const [aspectRatioFromHeight, setAspectRatioFromHeight] = (0, react_1.useState)(16 / 9);
|
52
58
|
const [aspectRatioLocked, setAspectRatioLocked] = (0, react_1.useState)(true);
|
@@ -86,10 +92,32 @@ const ImageForm = ({ data, onSubmit }) => {
|
|
86
92
|
const toggleAspectRatio = () => {
|
87
93
|
setAspectRatioLocked(!aspectRatioLocked);
|
88
94
|
};
|
95
|
+
(0, react_1.useEffect)(() => {
|
96
|
+
if (imageType === Extensions_1.NodeName.Image) {
|
97
|
+
setViewType(ViewTypes.URL);
|
98
|
+
}
|
99
|
+
else {
|
100
|
+
setViewType(ViewTypes.Resource);
|
101
|
+
}
|
102
|
+
}, [imageType, setViewType]);
|
103
|
+
const handleChangeViewType = (0, react_1.useCallback)((value) => {
|
104
|
+
setViewType(value);
|
105
|
+
// If its the URL field type we know what the imageType should be
|
106
|
+
if (value === ViewTypes.URL) {
|
107
|
+
console.log(`handleChangeViewType: ${value} NodeName.Image`);
|
108
|
+
setValue('imageType', Extensions_1.NodeName.Image);
|
109
|
+
}
|
110
|
+
else {
|
111
|
+
// Need a value here and this is the assumed default elsewhere
|
112
|
+
// Will be set again later once Resource Browser returns a resource value
|
113
|
+
console.log(`handleChangeViewType: ${value} NodeName.AssetImage`);
|
114
|
+
setValue('imageType', Extensions_1.NodeName.AssetImage);
|
115
|
+
}
|
116
|
+
}, [setViewType, setValue]);
|
89
117
|
return (react_1.default.createElement("form", { className: "squiz-fte-form", onSubmit: handleSubmit(onSubmit) },
|
90
118
|
react_1.default.createElement("div", { className: "squiz-fte-form-group mb-4" },
|
91
|
-
react_1.default.createElement(Tabs_1.Tabs, { value: imageType, options: imageTypeOptions, onChange:
|
92
|
-
|
119
|
+
react_1.default.createElement(Tabs_1.Tabs, { value: imageType === Extensions_1.NodeName.Image ? ViewTypes.URL : ViewTypes.Resource, options: imageTypeOptions, onChange: handleChangeViewType })),
|
120
|
+
viewType === ViewTypes.URL && (react_1.default.createElement(react_1.default.Fragment, null,
|
93
121
|
react_1.default.createElement("div", { className: "squiz-fte-form-group mb-2" },
|
94
122
|
react_1.default.createElement(Input_1.Input, { label: "Source", required: true, error: errors?.image?.src?.message, ...register('image.src', {
|
95
123
|
onChange: setDimensionsFromURL,
|
@@ -135,9 +163,24 @@ const ImageForm = ({ data, onSubmit }) => {
|
|
135
163
|
}) }))),
|
136
164
|
react_1.default.createElement("div", { className: "squiz-fte-form-group mb-2" },
|
137
165
|
react_1.default.createElement(Input_1.Input, { label: "Alternative description", error: errors?.image?.alt?.message, ...register('image.alt') })))),
|
138
|
-
|
139
|
-
react_1.default.createElement(react_hook_form_1.Controller, { control: control, name: "
|
140
|
-
validate: (
|
141
|
-
|
166
|
+
viewType === ViewTypes.Resource && (react_1.default.createElement("div", { className: "squiz-fte-form-group mb-2" },
|
167
|
+
react_1.default.createElement(react_hook_form_1.Controller, { control: control, name: "resourceImage", rules: {
|
168
|
+
validate: (value) => {
|
169
|
+
const matrixValidation = (0, validation_1.hasProperties)('An image must be selected', [
|
170
|
+
'matrixIdentifier',
|
171
|
+
'matrixAssetId',
|
172
|
+
])(value);
|
173
|
+
const damValidation = (0, validation_1.hasProperties)('An image must be selected', [
|
174
|
+
'damObjectId',
|
175
|
+
'damSystemIdentifier',
|
176
|
+
])(value);
|
177
|
+
// One of the two needs to validate
|
178
|
+
return matrixValidation && damValidation;
|
179
|
+
},
|
180
|
+
}, render: ({ field: { onChange, value }, fieldState: { error } }) => (react_1.default.createElement(ResourceBrowserSelector_1.ResourceBrowserSelector, { modalTitle: "Insert image", allowedTypes: ['image'], value: value, onChange: (value) => {
|
181
|
+
console.log(`onChange: ${value}`);
|
182
|
+
setValue('imageType', value.target.value.nodeType);
|
183
|
+
onChange(value);
|
184
|
+
}, error: error?.message })) })))));
|
142
185
|
};
|
143
186
|
exports.default = ImageForm;
|
@@ -35,23 +35,26 @@ const Extensions_1 = require("../../../Extensions/Extensions");
|
|
35
35
|
const getShortcutSymbol_1 = require("../../../utils/getShortcutSymbol");
|
36
36
|
const ImageButton = ({ inPopover = false }) => {
|
37
37
|
const [showModal, setShowModal] = (0, react_1.useState)(false);
|
38
|
-
const { insertImage, insertAssetImage } = (0, react_2.useCommands)();
|
38
|
+
const { insertImage, insertAssetImage, insertDAMImage } = (0, react_2.useCommands)();
|
39
39
|
const active = (0, react_2.useActive)();
|
40
40
|
const selection = (0, react_2.useCurrentSelection)();
|
41
41
|
// if the active selection is not an image, disable the button as it means it will be text
|
42
|
-
const disabled = (!selection.empty && !active.image() && !active.assetImage()) || active.codeBlock();
|
42
|
+
const disabled = (!selection.empty && !active.image() && !active.assetImage() && !active.DAMImage()) || active.codeBlock();
|
43
43
|
const handleClick = () => {
|
44
44
|
if (!showModal) {
|
45
45
|
setShowModal(true);
|
46
46
|
}
|
47
47
|
};
|
48
48
|
const insertImageFromData = (data) => {
|
49
|
-
const { imageType, image,
|
49
|
+
const { imageType, image, resourceImage } = data;
|
50
50
|
if (imageType === Extensions_1.NodeName.Image) {
|
51
51
|
insertImage(image);
|
52
52
|
}
|
53
|
+
else if (imageType === Extensions_1.NodeName.DAMImage) {
|
54
|
+
insertDAMImage(resourceImage);
|
55
|
+
}
|
53
56
|
else {
|
54
|
-
insertAssetImage(
|
57
|
+
insertAssetImage(resourceImage);
|
55
58
|
}
|
56
59
|
};
|
57
60
|
const handleSubmit = async (data) => {
|
@@ -70,7 +73,7 @@ const ImageButton = ({ inPopover = false }) => {
|
|
70
73
|
(0, react_2.useKeymap)('Mod-l', disabled ? () => false : handleShortcut);
|
71
74
|
}
|
72
75
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
73
|
-
react_1.default.createElement(Button_1.default, { handleOnClick: handleClick, isActive: active.image() || active.assetImage(), icon: react_1.default.createElement(ImageRounded_1.default, null), label: `Image (${(0, getShortcutSymbol_1.getShortcutSymbol)()}+L)`, isDisabled: disabled }),
|
76
|
+
react_1.default.createElement(Button_1.default, { handleOnClick: handleClick, isActive: active.image() || active.assetImage() || active.DAMImage(), icon: react_1.default.createElement(ImageRounded_1.default, null), label: `Image (${(0, getShortcutSymbol_1.getShortcutSymbol)()}+L)`, isDisabled: disabled }),
|
74
77
|
showModal && react_1.default.createElement(ImageModal_1.default, { onCancel: () => setShowModal(false), onSubmit: handleSubmit })));
|
75
78
|
};
|
76
79
|
exports.default = ImageButton;
|
@@ -16,7 +16,9 @@ const ImageModal = ({ onCancel, onSubmit }) => {
|
|
16
16
|
const formData = {
|
17
17
|
imageType: currentImage?.type.name === Extensions_1.NodeName.Image ? Extensions_1.NodeName.Image : Extensions_1.NodeName.AssetImage,
|
18
18
|
image: currentImage?.type?.name === Extensions_1.NodeName.Image ? currentImageAttrs : {},
|
19
|
-
|
19
|
+
resourceImage: currentImage?.type?.name === Extensions_1.NodeName.DAMImage || currentImage?.type?.name === Extensions_1.NodeName.AssetImage
|
20
|
+
? currentImageAttrs
|
21
|
+
: {},
|
20
22
|
};
|
21
23
|
return (react_1.default.createElement(FormModal_1.default, { title: "Image", icon: react_1.default.createElement(ImageRounded_1.default, null), onCancel: onCancel },
|
22
24
|
react_1.default.createElement(ImageForm_1.default, { data: formData, onSubmit: onSubmit })));
|
@@ -8,6 +8,7 @@ const LinkExtension_1 = require("./LinkExtension/LinkExtension");
|
|
8
8
|
const ImageExtension_1 = require("./ImageExtension/ImageExtension");
|
9
9
|
const CommandsExtension_1 = require("./CommandsExtension/CommandsExtension");
|
10
10
|
const AssetImageExtension_1 = require("./ImageExtension/AssetImageExtension");
|
11
|
+
const DAMImageExtension_1 = require("./ImageExtension/DAMImageExtension");
|
11
12
|
const CodeBlockExtension_1 = require("./CodeBlockExtension/CodeBlockExtension");
|
12
13
|
const ClearFormattingExtension_1 = require("./ClearFormattingExtension/ClearFormattingExtension");
|
13
14
|
const UnsupportedNodeExtension_1 = require("./UnsuportedExtension/UnsupportedNodeExtension");
|
@@ -19,6 +20,7 @@ var NodeName;
|
|
19
20
|
NodeName["Image"] = "image";
|
20
21
|
NodeName["CodeBlock"] = "codeBlock";
|
21
22
|
NodeName["AssetImage"] = "assetImage";
|
23
|
+
NodeName["DAMImage"] = "DAMImage";
|
22
24
|
NodeName["Text"] = "text";
|
23
25
|
NodeName["TableControllerCell"] = "tableControllerCell";
|
24
26
|
NodeName["tableCell"] = "tableCell";
|
@@ -50,6 +52,7 @@ const createExtensions = (context) => {
|
|
50
52
|
new AssetImageExtension_1.AssetImageExtension({
|
51
53
|
matrixDomain: context.matrix.matrixDomain,
|
52
54
|
}),
|
55
|
+
new DAMImageExtension_1.DAMImageExtension(),
|
53
56
|
new LinkExtension_1.LinkExtension(),
|
54
57
|
new AssetLinkExtension_1.AssetLinkExtension({
|
55
58
|
matrixDomain: context.matrix.matrixDomain,
|
@@ -25,6 +25,12 @@ let FetchUrlExtension = class FetchUrlExtension extends core_1.PlainExtension {
|
|
25
25
|
tr.replaceWith(pos, pos + node.nodeSize, newNode);
|
26
26
|
}));
|
27
27
|
}
|
28
|
+
if (node.type.name === Extensions_1.NodeName.DAMImage && node.attrs.src === '') {
|
29
|
+
promises.push(this.fetchAndReplace(node.attrs, (url) => {
|
30
|
+
const newNode = state.schema.nodes[Extensions_1.NodeName.DAMImage].create({ ...node.attrs, src: url });
|
31
|
+
tr.replaceWith(pos, pos + node.nodeSize, newNode);
|
32
|
+
}));
|
33
|
+
}
|
28
34
|
const assetLinkMark = this.findAssetLinkMark(node.marks);
|
29
35
|
if (node.type.name === 'text' && assetLinkMark) {
|
30
36
|
promises.push(this.fetchAndReplace(assetLinkMark.attrs, (url) => {
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import { ApplySchemaAttributes, NodeExtension, NodeExtensionSpec, NodeSpecOverride, CommandFunction } from '@remirror/core';
|
2
|
+
import { NodeName } from '../Extensions';
|
3
|
+
export type DAMImageAttributes = {
|
4
|
+
damObjectId: string;
|
5
|
+
damSystemIdentifier: string;
|
6
|
+
damSystemType: string;
|
7
|
+
damAdditional?: {
|
8
|
+
variant: string;
|
9
|
+
};
|
10
|
+
url: string;
|
11
|
+
};
|
12
|
+
export declare class DAMImageExtension extends NodeExtension {
|
13
|
+
get name(): NodeName.DAMImage;
|
14
|
+
createTags(): ("inline" | "media")[];
|
15
|
+
createNodeSpec(extra: ApplySchemaAttributes, override: NodeSpecOverride): NodeExtensionSpec;
|
16
|
+
insertDAMImage(attrs: DAMImageAttributes): CommandFunction;
|
17
|
+
}
|
@@ -0,0 +1,97 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
7
|
+
};
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
9
|
+
exports.DAMImageExtension = void 0;
|
10
|
+
const core_1 = require("@remirror/core");
|
11
|
+
const remirror_1 = require("remirror");
|
12
|
+
const Extensions_1 = require("../Extensions");
|
13
|
+
let DAMImageExtension = class DAMImageExtension extends core_1.NodeExtension {
|
14
|
+
get name() {
|
15
|
+
return Extensions_1.NodeName.DAMImage;
|
16
|
+
}
|
17
|
+
createTags() {
|
18
|
+
return [core_1.ExtensionTag.InlineNode, core_1.ExtensionTag.Media];
|
19
|
+
}
|
20
|
+
createNodeSpec(extra, override) {
|
21
|
+
return {
|
22
|
+
inline: true,
|
23
|
+
draggable: true,
|
24
|
+
selectable: true,
|
25
|
+
...override,
|
26
|
+
attrs: {
|
27
|
+
...extra.defaults(),
|
28
|
+
damObjectId: {},
|
29
|
+
damSystemIdentifier: {},
|
30
|
+
damSystemType: {},
|
31
|
+
damAdditional: { default: undefined },
|
32
|
+
src: { default: '' },
|
33
|
+
},
|
34
|
+
parseDOM: [
|
35
|
+
{
|
36
|
+
tag: 'img[data-dam-object-id]',
|
37
|
+
getAttrs: (node) => {
|
38
|
+
if (!(0, core_1.isElementDomNode)(node)) {
|
39
|
+
return false;
|
40
|
+
}
|
41
|
+
const damObjectId = node.getAttribute('data-dam-object-id');
|
42
|
+
const damSystemIdentifier = node.getAttribute('data-dam-system-identifier');
|
43
|
+
const damSystemType = node.getAttribute('data-dam-system-type');
|
44
|
+
let damAdditional = node.getAttribute('data-dam-additional') || undefined;
|
45
|
+
if (!damObjectId || !damSystemIdentifier || !damSystemType) {
|
46
|
+
return false;
|
47
|
+
}
|
48
|
+
if (damAdditional) {
|
49
|
+
damAdditional = JSON.parse(damAdditional);
|
50
|
+
}
|
51
|
+
return {
|
52
|
+
...extra.parse(node),
|
53
|
+
damObjectId,
|
54
|
+
damSystemIdentifier,
|
55
|
+
damSystemType,
|
56
|
+
damAdditional,
|
57
|
+
src: '',
|
58
|
+
};
|
59
|
+
},
|
60
|
+
},
|
61
|
+
],
|
62
|
+
toDOM: (node) => {
|
63
|
+
const { damObjectId, damSystemIdentifier, damSystemType, damAdditional, src, ...rest } = (0, core_1.omitExtraAttributes)(node.attrs, extra);
|
64
|
+
return [
|
65
|
+
'img',
|
66
|
+
{
|
67
|
+
...extra.dom(node),
|
68
|
+
...rest,
|
69
|
+
src,
|
70
|
+
'data-dam-object-id': damObjectId,
|
71
|
+
'data-dam-system-identifier': damSystemIdentifier,
|
72
|
+
'data-dam-system-type': damSystemType,
|
73
|
+
'data-dam-additional': damAdditional ? JSON.stringify(damAdditional) : undefined,
|
74
|
+
},
|
75
|
+
];
|
76
|
+
},
|
77
|
+
};
|
78
|
+
}
|
79
|
+
insertDAMImage(attrs) {
|
80
|
+
return ({ tr, dispatch }) => {
|
81
|
+
const { from, to } = (0, remirror_1.getTextSelection)(tr.selection, tr.doc);
|
82
|
+
const node = this.type.create({ ...attrs, src: attrs.url });
|
83
|
+
dispatch?.(tr.replaceRangeWith(from, to, node));
|
84
|
+
return true;
|
85
|
+
};
|
86
|
+
}
|
87
|
+
};
|
88
|
+
__decorate([
|
89
|
+
(0, core_1.command)()
|
90
|
+
], DAMImageExtension.prototype, "insertDAMImage", null);
|
91
|
+
DAMImageExtension = __decorate([
|
92
|
+
(0, core_1.extension)({
|
93
|
+
defaultOptions: {},
|
94
|
+
defaultPriority: core_1.ExtensionPriority.High,
|
95
|
+
})
|
96
|
+
], DAMImageExtension);
|
97
|
+
exports.DAMImageExtension = DAMImageExtension;
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { InputContainerProps } from '../InputContainer/InputContainer';
|
3
|
+
import { NodeName } from '../../../Extensions/Extensions';
|
4
|
+
type MatrixAsset = {
|
5
|
+
matrixIdentifier?: string;
|
6
|
+
matrixAssetId?: string;
|
7
|
+
};
|
8
|
+
type DAMAsset = {
|
9
|
+
damSystemIdentifier?: string;
|
10
|
+
damObjectId?: string;
|
11
|
+
damSystemType?: string;
|
12
|
+
};
|
13
|
+
type ResourceBrowserSelectorValue = MatrixAsset & DAMAsset & {
|
14
|
+
nodeType?: NodeName;
|
15
|
+
url?: string;
|
16
|
+
};
|
17
|
+
export type ResourceBrowserSelectorProps<T extends ResourceBrowserSelectorValue> = Omit<InputContainerProps, 'children'> & {
|
18
|
+
modalTitle: string;
|
19
|
+
allowedTypes?: string[];
|
20
|
+
value?: T | null;
|
21
|
+
onChange: (value: {
|
22
|
+
target: {
|
23
|
+
value: T;
|
24
|
+
};
|
25
|
+
}) => void;
|
26
|
+
};
|
27
|
+
export declare const ResourceBrowserSelector: <T extends ResourceBrowserSelectorValue>({ modalTitle, allowedTypes, value, onChange, ...props }: ResourceBrowserSelectorProps<T>) => React.JSX.Element;
|
28
|
+
export {};
|