@squiz/formatted-text-editor 2.6.5 → 2.6.6

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 (36) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/lib/EditorToolbar/Tools/Link/Form/LinkForm.d.ts +3 -2
  3. package/lib/EditorToolbar/Tools/Link/Form/LinkForm.js +18 -4
  4. package/lib/EditorToolbar/Tools/Link/LinkButton.js +11 -7
  5. package/lib/EditorToolbar/Tools/Link/LinkModal.js +8 -4
  6. package/lib/EditorToolbar/Tools/Link/RemoveLinkButton.js +2 -2
  7. package/lib/Extensions/Extensions.d.ts +2 -1
  8. package/lib/Extensions/Extensions.js +3 -0
  9. package/lib/Extensions/FetchUrlExtension/FetchUrlExtension.d.ts +1 -0
  10. package/lib/Extensions/FetchUrlExtension/FetchUrlExtension.js +10 -0
  11. package/lib/Extensions/LinkExtension/AssetLinkExtension.js +1 -1
  12. package/lib/Extensions/LinkExtension/DamLinkExtension.d.ts +29 -0
  13. package/lib/Extensions/LinkExtension/DamLinkExtension.js +111 -0
  14. package/lib/Extensions/LinkExtension/LinkExtension.js +1 -1
  15. package/lib/ui/Fields/MatrixAsset/MatrixAsset.d.ts +16 -2
  16. package/lib/ui/Fields/MatrixAsset/MatrixAsset.js +71 -20
  17. package/lib/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.js +10 -0
  18. package/lib/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.js +13 -0
  19. package/package.json +2 -2
  20. package/src/EditorToolbar/Tools/Link/Form/LinkForm.tsx +26 -7
  21. package/src/EditorToolbar/Tools/Link/LinkButton.spec.tsx +74 -1
  22. package/src/EditorToolbar/Tools/Link/LinkButton.tsx +19 -8
  23. package/src/EditorToolbar/Tools/Link/LinkModal.tsx +10 -5
  24. package/src/EditorToolbar/Tools/Link/RemoveLinkButton.tsx +4 -3
  25. package/src/Extensions/Extensions.ts +3 -0
  26. package/src/Extensions/FetchUrlExtension/FetchUrlExtension.ts +14 -0
  27. package/src/Extensions/LinkExtension/AssetLinkExtension.ts +1 -1
  28. package/src/Extensions/LinkExtension/DamLinkExtension.spec.ts +110 -0
  29. package/src/Extensions/LinkExtension/DamLinkExtension.ts +137 -0
  30. package/src/Extensions/LinkExtension/LinkExtension.ts +1 -1
  31. package/src/ui/Fields/MatrixAsset/MatrixAsset.tsx +83 -26
  32. package/src/utils/converters/mocks/squizNodeJson.mock.ts +48 -0
  33. package/src/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.spec.ts +63 -0
  34. package/src/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.ts +10 -0
  35. package/src/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.ts +12 -0
  36. package/src/utils/getMarkNamesByGroup.spec.ts +1 -1
@@ -1,14 +1,33 @@
1
- import React from 'react';
2
- import { ResourceBrowserResource, ResourceBrowser } from '@squiz/resource-browser';
1
+ import React, { useCallback } from 'react';
2
+ import { DAMResource, DamResourceBrowserSource } from '@squiz/dam-resource-browser-plugin';
3
+ import { ResourceBrowser, ResourceBrowserResource, ResourceBrowserUnresolvedResource } from '@squiz/resource-browser';
3
4
  import { InputContainer, InputContainerProps } from '../InputContainer/InputContainer';
5
+ import { LinkTarget } from '../../../Extensions/LinkExtension/common';
4
6
 
5
7
  type MatrixAssetValue = {
6
8
  matrixIdentifier?: string;
7
9
  matrixAssetId?: string;
8
- url?: string;
10
+ matrixDomain?: string;
9
11
  };
10
12
 
11
- export type MatrixAssetProps<T extends MatrixAssetValue> = Omit<InputContainerProps, 'children'> & {
13
+ type DAMAssetValue = {
14
+ damSystemIdentifier?: string;
15
+ damObjectId?: string;
16
+ damSystemType?: string;
17
+ damAdditional?: { variant: string };
18
+ };
19
+
20
+ export type ResourceBrowserSelectorValue = MatrixAssetValue &
21
+ DAMAssetValue & {
22
+ url?: string;
23
+ target?: LinkTarget;
24
+ subType?: 'matrix' | 'dam';
25
+ };
26
+
27
+ export type ResourceBrowserSelectorProps<T extends ResourceBrowserSelectorValue> = Omit<
28
+ InputContainerProps,
29
+ 'children'
30
+ > & {
12
31
  modalTitle: string;
13
32
  allowedTypes?: string[];
14
33
  value?: T | null;
@@ -19,38 +38,76 @@ export type MatrixAssetProps<T extends MatrixAssetValue> = Omit<InputContainerPr
19
38
  onChange: (value: { target: { value: T } }) => void;
20
39
  };
21
40
 
22
- export const MatrixAsset = <T extends MatrixAssetValue>({
41
+ export const MatrixAsset = <T extends ResourceBrowserSelectorValue>({
23
42
  modalTitle,
24
43
  allowedTypes,
25
44
  value,
26
45
  onChange,
27
46
  ...props
28
- }: MatrixAssetProps<T>) => {
47
+ }: ResourceBrowserSelectorProps<T>) => {
48
+ const convertFormDataToResourceBrowserValue = useCallback(
49
+ (value: T | null): ResourceBrowserUnresolvedResource | null => {
50
+ if (value && value.damSystemIdentifier && value.damObjectId) {
51
+ return {
52
+ sourceId: value.damSystemIdentifier,
53
+ resourceId: value.damObjectId,
54
+ variant: value.damAdditional?.variant,
55
+ };
56
+ }
57
+ if (value && value.matrixIdentifier && value.matrixAssetId) {
58
+ return {
59
+ sourceId: value.matrixIdentifier,
60
+ resourceId: value.matrixAssetId,
61
+ };
62
+ }
63
+ return null;
64
+ },
65
+ [],
66
+ );
67
+
68
+ const handleResourceChange = useCallback(
69
+ (resource: ResourceBrowserResource | null) => {
70
+ let onChangeData: ResourceBrowserSelectorValue = {
71
+ ...value,
72
+ matrixIdentifier: undefined,
73
+ matrixAssetId: undefined,
74
+ damSystemIdentifier: undefined,
75
+ damObjectId: undefined,
76
+ damSystemType: undefined,
77
+ damAdditional: undefined,
78
+ };
79
+
80
+ if (resource?.source?.type === 'dam') {
81
+ const damResource = resource as DAMResource;
82
+ onChangeData = {
83
+ ...onChangeData,
84
+ damSystemIdentifier: resource.source.id,
85
+ damObjectId: resource.id,
86
+ damSystemType: (resource.source as DamResourceBrowserSource).configuration.externalType,
87
+ damAdditional: damResource.variant ? { variant: damResource.variant } : undefined,
88
+ url: resource.url,
89
+ };
90
+ }
91
+ if (resource?.source.type === 'matrix') {
92
+ onChangeData = {
93
+ ...onChangeData,
94
+ matrixIdentifier: resource?.source?.id,
95
+ matrixAssetId: resource?.id,
96
+ url: resource?.url,
97
+ };
98
+ }
99
+ onChange({ target: { value: onChangeData as T } });
100
+ },
101
+ [value],
102
+ );
103
+
29
104
  return (
30
105
  <InputContainer {...props}>
31
106
  <ResourceBrowser
32
107
  modalTitle={modalTitle}
33
108
  allowedTypes={allowedTypes}
34
- value={
35
- value && value.matrixIdentifier && value.matrixAssetId
36
- ? {
37
- sourceId: value.matrixIdentifier,
38
- resourceId: value.matrixAssetId,
39
- }
40
- : null
41
- }
42
- onChange={(resource: ResourceBrowserResource | null) => {
43
- onChange({
44
- target: {
45
- value: {
46
- ...value,
47
- matrixIdentifier: resource?.source?.id,
48
- matrixAssetId: resource?.id,
49
- url: resource?.url,
50
- } as T,
51
- },
52
- });
53
- }}
109
+ value={convertFormDataToResourceBrowserValue(value as T)}
110
+ onChange={handleResourceChange}
54
111
  />
55
112
  </InputContainer>
56
113
  );
@@ -288,4 +288,52 @@ export const squizOnlyNodeExamples: NodeExample[] = [
288
288
  ],
289
289
  },
290
290
  },
291
+ {
292
+ description: 'Link to DAM asset',
293
+ squizNode: [
294
+ {
295
+ type: 'tag',
296
+ tag: 'span',
297
+ children: [
298
+ {
299
+ type: 'link-to-dam-asset',
300
+ damObjectId: '123-456-789',
301
+ damSystemIdentifier: 'zzz-xxx-ccc',
302
+ damSystemType: 'bynder',
303
+ damAdditional: { variant: 'xyz' },
304
+ target: '_blank',
305
+ children: [
306
+ {
307
+ type: 'tag',
308
+ tag: 'span',
309
+ children: [
310
+ {
311
+ type: 'tag',
312
+ tag: 'span',
313
+ children: [{ type: 'text', value: 'Hello' }],
314
+ },
315
+ ],
316
+ },
317
+ ],
318
+ },
319
+ ],
320
+ },
321
+ ],
322
+ remirrorNode: {
323
+ type: 'text',
324
+ text: 'Hello',
325
+ marks: [
326
+ {
327
+ type: 'DAMLink',
328
+ attrs: {
329
+ target: '_blank',
330
+ damObjectId: '123-456-789',
331
+ damSystemIdentifier: 'zzz-xxx-ccc',
332
+ damSystemType: 'bynder',
333
+ damAdditional: JSON.stringify({ variant: 'xyz' }),
334
+ },
335
+ },
336
+ ],
337
+ },
338
+ },
291
339
  ];
@@ -1053,4 +1053,67 @@ describe('resolveNodeTag', () => {
1053
1053
  };
1054
1054
  expect(() => resolveNodeTag(node)).toThrow('Unexpected Remirror node encountered, cannot resolve tag.');
1055
1055
  });
1056
+
1057
+ it('should convert a DAMLink mark to a link-to-dam-asset node', async () => {
1058
+ const content: RemirrorJSON = {
1059
+ type: 'doc',
1060
+ content: [
1061
+ {
1062
+ type: 'paragraph',
1063
+ attrs: {
1064
+ nodeIndent: null,
1065
+ nodeTextAlignment: null,
1066
+ nodeLineHeight: null,
1067
+ style: '',
1068
+ },
1069
+ content: [
1070
+ {
1071
+ type: 'text',
1072
+ text: 'Click here for DAM asset',
1073
+ marks: [
1074
+ {
1075
+ type: 'DAMLink',
1076
+ attrs: {
1077
+ target: '_blank',
1078
+ damSystemType: 'bynder',
1079
+ damSystemIdentifier: 'idA',
1080
+ damObjectId: 'objA',
1081
+ damAdditional: { variant: 'primary' },
1082
+ },
1083
+ },
1084
+ ],
1085
+ },
1086
+ ],
1087
+ },
1088
+ ],
1089
+ };
1090
+
1091
+ const { editor } = await renderWithEditor(null, { content });
1092
+
1093
+ const expected: FormattedTextModels.v1.FormattedText = [
1094
+ {
1095
+ type: 'tag',
1096
+ tag: 'p',
1097
+ children: [
1098
+ {
1099
+ type: 'link-to-dam-asset',
1100
+ target: '_blank',
1101
+ damSystemType: 'bynder',
1102
+ damSystemIdentifier: 'idA',
1103
+ damObjectId: 'objA',
1104
+ damAdditional: { variant: 'primary' },
1105
+ children: [
1106
+ {
1107
+ type: 'text',
1108
+ value: 'Click here for DAM asset',
1109
+ },
1110
+ ],
1111
+ },
1112
+ ],
1113
+ },
1114
+ ];
1115
+
1116
+ const result = remirrorNodeToSquizNode(editor.doc);
1117
+ expect(result).toEqual(expected);
1118
+ });
1056
1119
  });
@@ -282,6 +282,16 @@ const transformMark = (mark: Mark, node: FormattedNode): FormattedNode => {
282
282
  matrixAssetId: mark.attrs.matrixAssetId,
283
283
  children: [],
284
284
  });
285
+ case 'DAMLink':
286
+ return wrapNodeIfNeeded(node, {
287
+ type: 'link-to-dam-asset',
288
+ target: mark.attrs.target,
289
+ damSystemType: mark.attrs.damSystemType,
290
+ damSystemIdentifier: mark.attrs.damSystemIdentifier,
291
+ damObjectId: mark.attrs.damObjectId,
292
+ damAdditional: mark.attrs.damAdditional,
293
+ children: [],
294
+ });
285
295
  }
286
296
 
287
297
  throw new Error(`Unsupported mark "${mark.type.name}" was applied to node.`);
@@ -12,6 +12,7 @@ const getNodeType = (node: FormattedNodes): string => {
12
12
  'link-to-matrix-asset': NodeName.Text,
13
13
  'matrix-image': NodeName.AssetImage,
14
14
  'dam-image': NodeName.DAMImage,
15
+ 'link-to-dam-asset': NodeName.Text,
15
16
  text: 'text',
16
17
  };
17
18
 
@@ -134,6 +135,17 @@ const getNodeMarks = (node: FormattedNodes): ObjectMark[] => {
134
135
  target: node.target,
135
136
  },
136
137
  });
138
+ } else if (node.type === 'link-to-dam-asset') {
139
+ marks.push({
140
+ type: MarkName.DAMLink,
141
+ attrs: {
142
+ damSystemType: node.damSystemType,
143
+ damSystemIdentifier: node.damSystemIdentifier,
144
+ damObjectId: node.damObjectId,
145
+ damAdditional: node.damAdditional ? JSON.stringify(node.damAdditional) : undefined,
146
+ target: node.target,
147
+ },
148
+ });
137
149
  } else if (node.type === 'tag' && node.tag === 'strong') {
138
150
  marks.push({ type: 'bold' });
139
151
  } else if (node.type === 'tag' && node.tag === 'em') {
@@ -15,6 +15,6 @@ describe('getMarkNamesGroup', () => {
15
15
  // Marks in the first array will be transformed to a paragraph when formatting is cleared.
16
16
  // Mark in the second array will be left as-is.
17
17
  expect(formattingMarkNames).toEqual(['bold', 'italic', 'underline']);
18
- expect(otherMarkNames).toEqual(['assetLink', 'link']);
18
+ expect(otherMarkNames).toEqual(['DAMLink', 'assetLink', 'link']);
19
19
  });
20
20
  });