@squiz/formatted-text-editor 1.21.1-alpha.35 → 1.21.1-alpha.39

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 (48) hide show
  1. package/demo/App.tsx +9 -2
  2. package/lib/Editor/EditorContext.d.ts +6 -1
  3. package/lib/Editor/EditorContext.js +1 -1
  4. package/lib/EditorToolbar/FloatingToolbar.js +1 -1
  5. package/lib/EditorToolbar/Tools/Image/Form/ImageForm.d.ts +9 -8
  6. package/lib/EditorToolbar/Tools/Image/Form/ImageForm.js +71 -43
  7. package/lib/EditorToolbar/Tools/Image/ImageButton.js +13 -15
  8. package/lib/EditorToolbar/Tools/Image/ImageModal.js +7 -1
  9. package/lib/EditorToolbar/Tools/Link/Form/LinkForm.js +1 -1
  10. package/lib/Extensions/Extensions.d.ts +5 -0
  11. package/lib/Extensions/Extensions.js +12 -1
  12. package/lib/Extensions/ImageExtension/AssetImageExtension.d.ts +17 -0
  13. package/lib/Extensions/ImageExtension/AssetImageExtension.js +92 -0
  14. package/lib/Extensions/ImageExtension/ImageExtension.d.ts +1 -4
  15. package/lib/Extensions/ImageExtension/ImageExtension.js +4 -78
  16. package/lib/Extensions/LinkExtension/AssetLinkExtension.js +3 -3
  17. package/lib/Extensions/LinkExtension/LinkExtension.d.ts +1 -3
  18. package/lib/Extensions/LinkExtension/LinkExtension.js +1 -9
  19. package/lib/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.js +12 -3
  20. package/lib/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.js +14 -5
  21. package/lib/utils/resolveMatrixAssetUrl.d.ts +1 -0
  22. package/lib/utils/resolveMatrixAssetUrl.js +10 -0
  23. package/package.json +3 -3
  24. package/src/Editor/EditorContext.spec.tsx +3 -3
  25. package/src/Editor/EditorContext.ts +9 -2
  26. package/src/EditorToolbar/FloatingToolbar.spec.tsx +24 -4
  27. package/src/EditorToolbar/FloatingToolbar.tsx +1 -1
  28. package/src/EditorToolbar/Tools/Image/Form/ImageForm.spec.tsx +26 -5
  29. package/src/EditorToolbar/Tools/Image/Form/ImageForm.tsx +145 -96
  30. package/src/EditorToolbar/Tools/Image/ImageButton.spec.tsx +128 -7
  31. package/src/EditorToolbar/Tools/Image/ImageButton.tsx +15 -17
  32. package/src/EditorToolbar/Tools/Image/ImageModal.tsx +7 -1
  33. package/src/EditorToolbar/Tools/Link/Form/LinkForm.tsx +1 -1
  34. package/src/EditorToolbar/Tools/Link/LinkButton.spec.tsx +17 -5
  35. package/src/EditorToolbar/Tools/Link/RemoveLinkButton.spec.tsx +1 -0
  36. package/src/Extensions/Extensions.ts +11 -0
  37. package/src/Extensions/ImageExtension/AssetImageExtension.spec.ts +76 -0
  38. package/src/Extensions/ImageExtension/AssetImageExtension.ts +111 -0
  39. package/src/Extensions/ImageExtension/ImageExtension.ts +6 -99
  40. package/src/Extensions/LinkExtension/AssetLinkExtension.spec.ts +1 -1
  41. package/src/Extensions/LinkExtension/AssetLinkExtension.ts +3 -3
  42. package/src/Extensions/LinkExtension/LinkExtension.ts +2 -22
  43. package/src/utils/converters/mocks/squizNodeJson.mock.ts +19 -0
  44. package/src/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.ts +13 -3
  45. package/src/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.spec.ts +13 -1
  46. package/src/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.ts +13 -5
  47. package/src/utils/resolveMatrixAssetUrl.spec.ts +26 -0
  48. package/src/utils/resolveMatrixAssetUrl.ts +7 -0
@@ -10,6 +10,7 @@ import { command, CommandFunction, extension, MarkExtension, omitExtraAttributes
10
10
  import { LinkTarget, validateTarget } from './common';
11
11
  import { CommandsExtension } from '../CommandsExtension/CommandsExtension';
12
12
  import { MarkName } from '../Extensions';
13
+ import { resolveMatrixAssetUrl } from '../../utils/resolveMatrixAssetUrl';
13
14
 
14
15
  export type AssetLinkAttributes = {
15
16
  matrixAssetId: string;
@@ -48,7 +49,7 @@ export class AssetLinkExtension extends MarkExtension<AssetLinkOptions> {
48
49
  createMarkSpec(extra: ApplySchemaAttributes, override: MarkSpecOverride): MarkExtensionSpec {
49
50
  return {
50
51
  inclusive: false,
51
- excludes: 'link',
52
+ excludes: MarkName.Link,
52
53
  ...override,
53
54
  attrs: {
54
55
  ...extra.defaults(),
@@ -97,8 +98,7 @@ export class AssetLinkExtension extends MarkExtension<AssetLinkOptions> {
97
98
  ...extra.dom(node),
98
99
  ...rest,
99
100
  rel,
100
- // TODO: this won't be acceptable if/when we get to rendering outside of Matrix.
101
- href: `/?a=${matrixAssetId}`,
101
+ href: resolveMatrixAssetUrl(String(matrixAssetId), String(matrixDomain)),
102
102
  target: validateTarget(target, this.options.supportedTargets, this.options.defaultTarget),
103
103
  'data-matrix-asset-id': matrixAssetId,
104
104
  'data-matrix-identifier': matrixIdentifier,
@@ -6,18 +6,7 @@ import {
6
6
  MarkExtensionSpec,
7
7
  MarkSpecOverride,
8
8
  } from 'remirror';
9
- import {
10
- command,
11
- CommandFunction,
12
- extension,
13
- Handler,
14
- keyBinding,
15
- KeyBindingProps,
16
- MarkExtension,
17
- NamedShortcut,
18
- omitExtraAttributes,
19
- removeMark,
20
- } from '@remirror/core';
9
+ import { command, CommandFunction, extension, MarkExtension, omitExtraAttributes, removeMark } from '@remirror/core';
21
10
  import { LinkTarget, validateTarget } from './common';
22
11
  import { CommandsExtension } from '../CommandsExtension/CommandsExtension';
23
12
  import { MarkName } from '../Extensions';
@@ -31,7 +20,6 @@ export type LinkAttributes = {
31
20
  export type LinkOptions = {
32
21
  defaultTarget?: LinkTarget;
33
22
  supportedTargets?: LinkTarget[];
34
- onShortcut?: Handler<() => void>;
35
23
  };
36
24
 
37
25
  export type UpdateLinkProps = {
@@ -45,7 +33,6 @@ export type UpdateLinkProps = {
45
33
  defaultTarget: LinkTarget.Self,
46
34
  supportedTargets: [LinkTarget.Self, LinkTarget.Blank],
47
35
  },
48
- handlerKeys: ['onShortcut'],
49
36
  defaultPriority: ExtensionPriority.Medium,
50
37
  })
51
38
  export class LinkExtension extends MarkExtension<LinkOptions> {
@@ -56,7 +43,7 @@ export class LinkExtension extends MarkExtension<LinkOptions> {
56
43
  createMarkSpec(extra: ApplySchemaAttributes, override: MarkSpecOverride): MarkExtensionSpec {
57
44
  return {
58
45
  inclusive: false,
59
- excludes: 'assetLink',
46
+ excludes: MarkName.AssetLink,
60
47
  ...override,
61
48
  attrs: {
62
49
  ...extra.defaults(),
@@ -100,13 +87,6 @@ export class LinkExtension extends MarkExtension<LinkOptions> {
100
87
  };
101
88
  }
102
89
 
103
- @keyBinding({ shortcut: NamedShortcut.InsertLink })
104
- shortcut(_: KeyBindingProps): boolean {
105
- this.options.onShortcut();
106
-
107
- return true;
108
- }
109
-
110
90
  @command()
111
91
  updateLink({ text, attrs, range }: UpdateLinkProps): CommandFunction {
112
92
  return this.store.getExtension(CommandsExtension).updateMark({
@@ -146,6 +146,25 @@ export const sharedNodeExamples: NodeExample[] = [
146
146
  },
147
147
  ],
148
148
  },
149
+ {
150
+ description: 'Asset image',
151
+ remirrorNode: {
152
+ type: 'assetImage',
153
+ attrs: {
154
+ matrixAssetId: '123',
155
+ matrixDomain: 'https://my-matrix.squiz.net',
156
+ matrixIdentifier: 'matrix-api-identifier',
157
+ },
158
+ },
159
+ squizNode: [
160
+ {
161
+ type: 'matrix-image',
162
+ matrixAssetId: '123',
163
+ matrixDomain: 'https://my-matrix.squiz.net',
164
+ matrixIdentifier: 'matrix-api-identifier',
165
+ },
166
+ ],
167
+ },
149
168
  ];
150
169
 
151
170
  export const squizOnlyNodeExamples: NodeExample[] = [
@@ -2,6 +2,7 @@ import { ProsemirrorNode, Fragment as ProsemirrorFragment, Mark } from 'remirror
2
2
  import { Attrs } from 'prosemirror-model';
3
3
  import { FORMATTED_TEXT_MODELS as FormattedTextModels } from '@squiz/dx-json-schema-lib';
4
4
  import { undefinedIfEmpty } from '../../undefinedIfEmpty';
5
+ import { NodeName } from '../../../Extensions/Extensions';
5
6
 
6
7
  type Fragment = ProsemirrorFragment & {
7
8
  content?: Fragment[];
@@ -91,7 +92,7 @@ const transformFragment = (fragment: Fragment): FormattedText => {
91
92
  };
92
93
 
93
94
  const transformNode = (node: ProsemirrorNode): FormattedNode => {
94
- const attributes = node.type.name === 'image' ? transformAttributes(node.attrs) : undefined;
95
+ const attributes = node.type.name === NodeName.Image ? transformAttributes(node.attrs) : undefined;
95
96
  const formattingOptions = undefinedIfEmpty(resolveFormattingOptions(node));
96
97
  const font = undefinedIfEmpty(resolveFontOptions(node));
97
98
  let transformedNode: FormattedNode = { type: 'text', value: node.text || '' };
@@ -101,17 +102,26 @@ const transformNode = (node: ProsemirrorNode): FormattedNode => {
101
102
  // If the node isn't a text type assume it is a tag type and wrap in a tag.
102
103
  // If we pick the wrong tag here it will be corrected later as part of looping through the
103
104
  // non-font marks.
104
- if (node.type.name !== 'text' || attributes || formattingOptions || font) {
105
+ if (node.type.name !== NodeName.Text || attributes || formattingOptions || font) {
105
106
  transformedNode = {
106
107
  type: 'tag',
107
108
  tag: resolveNodeTag(node),
108
- children: node.type.name === 'text' ? [transformedNode] : transformFragment(node.content),
109
+ children: node.type.name === NodeName.Text ? [transformedNode] : transformFragment(node.content),
109
110
  attributes,
110
111
  formattingOptions,
111
112
  font,
112
113
  };
113
114
  }
114
115
 
116
+ if (node.type.name === NodeName.AssetImage) {
117
+ transformedNode = {
118
+ type: 'matrix-image',
119
+ matrixAssetId: node.attrs.matrixAssetId,
120
+ matrixIdentifier: node.attrs.matrixIdentifier,
121
+ matrixDomain: node.attrs.matrixDomain,
122
+ };
123
+ }
124
+
115
125
  node.marks.forEach((mark) => {
116
126
  switch (mark.type.name) {
117
127
  case 'bold':
@@ -314,12 +314,24 @@ describe('squizNodeToRemirrorNode', () => {
314
314
  it.each([...sharedNodeExamples, ...squizOnlyNodeExamples])(
315
315
  'should convert a Squiz node to the expected Remirror representation - $description',
316
316
  async ({ remirrorNode, squizNode }: any) => {
317
- const result = squizNodeToRemirrorNode(squizNode);
317
+ const result = squizNodeToRemirrorNode([
318
+ {
319
+ type: 'tag',
320
+ tag: 'p',
321
+ children: squizNode,
322
+ },
323
+ ]);
318
324
  expect(result).toEqual({
319
325
  type: 'doc',
320
326
  content: [
321
327
  {
322
328
  type: 'paragraph',
329
+ attrs: {
330
+ nodeIndent: null,
331
+ nodeLineHeight: null,
332
+ nodeTextAlignment: null,
333
+ style: '',
334
+ },
323
335
  content: [remirrorNode],
324
336
  },
325
337
  ],
@@ -2,13 +2,15 @@ import { RemirrorJSON, ObjectMark } from '@remirror/core';
2
2
  import { Attrs } from 'prosemirror-model';
3
3
  import { FORMATTED_TEXT_MODELS as FormattedTextModels } from '@squiz/dx-json-schema-lib';
4
4
  import { undefinedIfEmpty } from '../../undefinedIfEmpty';
5
+ import { MarkName, NodeName } from '../../../Extensions/Extensions';
5
6
 
6
7
  type FormattedText = FormattedTextModels.v1.FormattedText;
7
8
  type FormattedNodes = FormattedTextModels.v1.FormattedNodes;
8
9
 
9
10
  const getNodeType = (node: FormattedNodes): string => {
10
11
  const typeMap: Record<string, string> = {
11
- 'link-to-matrix-asset': 'text',
12
+ 'link-to-matrix-asset': NodeName.Text,
13
+ 'matrix-image': NodeName.AssetImage,
12
14
  text: 'text',
13
15
  };
14
16
 
@@ -22,8 +24,8 @@ const getNodeType = (node: FormattedNodes): string => {
22
24
  img: 'image',
23
25
  pre: 'preformatted',
24
26
  p: 'paragraph',
25
- a: 'text',
26
- span: 'text',
27
+ a: NodeName.Text,
28
+ span: NodeName.Text,
27
29
  };
28
30
 
29
31
  if (typeMap[node.type]) {
@@ -51,6 +53,12 @@ const getNodeAttributes = (node: FormattedNodes): Attrs => {
51
53
  src: node.attributes?.src,
52
54
  title: node.attributes?.title,
53
55
  };
56
+ } else if (node.type === 'matrix-image') {
57
+ return {
58
+ matrixAssetId: node.matrixAssetId,
59
+ matrixDomain: node.matrixDomain,
60
+ matrixIdentifier: node.matrixIdentifier,
61
+ };
54
62
  } else if (node.type === 'tag') {
55
63
  return {
56
64
  nodeIndent: null,
@@ -69,7 +77,7 @@ const getNodeMarks = (node: FormattedNodes): ObjectMark[] => {
69
77
 
70
78
  if (node.type === 'tag' && node.tag === 'a') {
71
79
  marks.push({
72
- type: 'link',
80
+ type: MarkName.Link,
73
81
  attrs: {
74
82
  href: node.attributes?.href,
75
83
  target: node.attributes?.target ?? null,
@@ -79,7 +87,7 @@ const getNodeMarks = (node: FormattedNodes): ObjectMark[] => {
79
87
  });
80
88
  } else if (node.type === 'link-to-matrix-asset') {
81
89
  marks.push({
82
- type: 'assetLink',
90
+ type: MarkName.AssetLink,
83
91
  attrs: {
84
92
  matrixAssetId: node.matrixAssetId,
85
93
  matrixDomain: node.matrixDomain,
@@ -0,0 +1,26 @@
1
+ import { resolveMatrixAssetUrl } from './resolveMatrixAssetUrl';
2
+
3
+ describe('resolveMatrixAssetUrl', () => {
4
+ it.each([
5
+ [
6
+ 'domain with no scheme',
7
+ '123:hello?.txt',
8
+ 'matrix.labs.squiz.test',
9
+ 'http://matrix.labs.squiz.test/_nocache?a=123%3Ahello%3F.txt',
10
+ ],
11
+ [
12
+ 'domain with scheme',
13
+ '123:hello?.txt',
14
+ 'https://matrix.labs.squiz.test',
15
+ 'https://matrix.labs.squiz.test/_nocache?a=123%3Ahello%3F.txt',
16
+ ],
17
+ [
18
+ 'domain with path',
19
+ '123:hello?.txt',
20
+ 'https://matrix.labs.squiz.test/site-1',
21
+ 'https://matrix.labs.squiz.test/_nocache?a=123%3Ahello%3F.txt',
22
+ ],
23
+ ])('Resolves to expected URL for %s', (description: string, id: string, matrixDomain: string, expected: string) => {
24
+ expect(resolveMatrixAssetUrl(id, matrixDomain)).toBe(expected);
25
+ });
26
+ });
@@ -0,0 +1,7 @@
1
+ export const resolveMatrixAssetUrl = (id: string, matrixDomain: string): string => {
2
+ if (matrixDomain.indexOf('://') < 0) {
3
+ matrixDomain = `${window.location.protocol}//${matrixDomain}`;
4
+ }
5
+
6
+ return new URL(`/_nocache?a=${encodeURIComponent(id)}`, matrixDomain).toString();
7
+ };