@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.
Files changed (39) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/demo/App.tsx +5 -0
  3. package/demo/AppContext.tsx +107 -70
  4. package/lib/EditorToolbar/FloatingToolbar.js +1 -1
  5. package/lib/EditorToolbar/Tools/ContentTools/ContentToolsDropdown.js +3 -3
  6. package/lib/EditorToolbar/Tools/Image/Form/ImageForm.d.ts +2 -1
  7. package/lib/EditorToolbar/Tools/Image/Form/ImageForm.js +53 -10
  8. package/lib/EditorToolbar/Tools/Image/ImageButton.js +8 -5
  9. package/lib/EditorToolbar/Tools/Image/ImageModal.js +3 -1
  10. package/lib/Extensions/Extensions.d.ts +1 -0
  11. package/lib/Extensions/Extensions.js +3 -0
  12. package/lib/Extensions/FetchUrlExtension/FetchUrlExtension.js +6 -0
  13. package/lib/Extensions/ImageExtension/DAMImageExtension.d.ts +17 -0
  14. package/lib/Extensions/ImageExtension/DAMImageExtension.js +97 -0
  15. package/lib/ui/Fields/ResourceBrowserSelector/ResourceBrowserSelector.d.ts +28 -0
  16. package/lib/ui/Fields/ResourceBrowserSelector/ResourceBrowserSelector.js +88 -0
  17. package/lib/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.js +9 -0
  18. package/lib/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.js +9 -0
  19. package/package.json +4 -2
  20. package/src/EditorToolbar/FloatingToolbar.spec.tsx +3 -1
  21. package/src/EditorToolbar/FloatingToolbar.tsx +1 -1
  22. package/src/EditorToolbar/Tools/ContentTools/ContentToolsDropdown.tsx +3 -3
  23. package/src/EditorToolbar/Tools/Image/Form/ImageForm.spec.tsx +27 -2
  24. package/src/EditorToolbar/Tools/Image/Form/ImageForm.tsx +61 -14
  25. package/src/EditorToolbar/Tools/Image/ImageButton.spec.tsx +70 -2
  26. package/src/EditorToolbar/Tools/Image/ImageButton.tsx +12 -6
  27. package/src/EditorToolbar/Tools/Image/ImageModal.tsx +4 -1
  28. package/src/Extensions/Extensions.ts +3 -0
  29. package/src/Extensions/FetchUrlExtension/FetchUrlExtension.ts +9 -0
  30. package/src/Extensions/ImageExtension/DAMImageExtension.spec.ts +87 -0
  31. package/src/Extensions/ImageExtension/DAMImageExtension.ts +119 -0
  32. package/src/ui/Fields/ResourceBrowserSelector/ResourceBrowserSelector.spec.tsx +219 -0
  33. package/src/ui/Fields/ResourceBrowserSelector/ResourceBrowserSelector.tsx +109 -0
  34. package/src/utils/converters/mocks/squizNodeJson.mock.ts +21 -0
  35. package/src/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.ts +10 -0
  36. package/src/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.ts +8 -0
  37. package/src/utils/getNodeNamesByGroup.spec.ts +1 -0
  38. package/tests/index.ts +1 -0
  39. 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}
@@ -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
- <ResourceBrowserContextProvider
17
- value={{
18
- onRequestSources: (): Promise<ResourceBrowserSource[]> =>
19
- Promise.resolve([
20
- {
21
- name: 'Matrix',
22
- id: 'matrixIdentifier',
23
- type: 'matrix',
24
- },
25
- ]),
26
- plugins: [
27
- MatrixResourceBrowserPlugin({
28
- onRequestSources: (): Promise<Source> => Promise.resolve(sources),
29
- onRequestChildren: (source: Source, resource: Resource | null): Promise<Resource[]> =>
30
- Promise.resolve(resource._children || resources),
31
- onRequestResource: (reference: ResourceReference): Promise<Resource | null> => {
32
- const flattenResources = (resources: unknown[]) => {
33
- return [
34
- ...resources,
35
- ...resources.flatMap((resource) =>
36
- '_children' in resource ? flattenResources(resource._children) : [],
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
- return Promise.resolve(
42
- flattenResources(resources).find((resource) => resource.id === reference.resource) || null,
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
- <EditorContext.Provider
69
- value={{
70
- matrix: {
71
- matrixDomain: 'https://matrix-domain.squiz.net',
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
- resolveNodeToUrl: (node: ResolveNodeType): Promise<string> => {
74
- const nodeResource = node.matrixAssetId;
75
- const flattenResources = (resources: unknown[]) => {
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
- {children}
90
- </EditorContext.Provider>
91
- </AiServiceProvider>
92
- </ResourceBrowserContextProvider>
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.map((item) => ({
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.length === 0) {
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
- assetImage: AssetImageAttributes;
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 MatrixAsset_1 = require("../../../../ui/Fields/MatrixAsset/MatrixAsset");
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
- [Extensions_1.NodeName.AssetImage]: { label: 'From source' },
43
- [Extensions_1.NodeName.Image]: { label: 'From URL' },
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') || Extensions_1.NodeName.AssetImage;
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: (value) => setValue('imageType', value) })),
92
- imageType === Extensions_1.NodeName.Image && (react_1.default.createElement(react_1.default.Fragment, null,
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
- imageType === Extensions_1.NodeName.AssetImage && (react_1.default.createElement("div", { className: "squiz-fte-form-group mb-2" },
139
- react_1.default.createElement(react_hook_form_1.Controller, { control: control, name: "assetImage", rules: {
140
- validate: (0, validation_1.hasProperties)('An image must be selected', ['matrixIdentifier', 'matrixAssetId']),
141
- }, render: ({ field: { onChange, value }, fieldState: { error } }) => (react_1.default.createElement(MatrixAsset_1.MatrixAsset, { modalTitle: "Insert image", allowedTypes: ['image'], value: value, onChange: onChange, error: error?.message })) })))));
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, assetImage } = data;
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(assetImage);
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
- assetImage: currentImage?.type?.name === Extensions_1.NodeName.AssetImage ? currentImageAttrs : {},
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 })));
@@ -4,6 +4,7 @@ export declare enum NodeName {
4
4
  Image = "image",
5
5
  CodeBlock = "codeBlock",
6
6
  AssetImage = "assetImage",
7
+ DAMImage = "DAMImage",
7
8
  Text = "text",
8
9
  TableControllerCell = "tableControllerCell",
9
10
  tableCell = "tableCell",
@@ -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 {};