@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.
- package/demo/App.tsx +9 -2
- package/lib/Editor/EditorContext.d.ts +6 -1
- package/lib/Editor/EditorContext.js +1 -1
- package/lib/EditorToolbar/FloatingToolbar.js +1 -1
- package/lib/EditorToolbar/Tools/Image/Form/ImageForm.d.ts +9 -8
- package/lib/EditorToolbar/Tools/Image/Form/ImageForm.js +71 -43
- package/lib/EditorToolbar/Tools/Image/ImageButton.js +13 -15
- package/lib/EditorToolbar/Tools/Image/ImageModal.js +7 -1
- package/lib/EditorToolbar/Tools/Link/Form/LinkForm.js +1 -1
- package/lib/Extensions/Extensions.d.ts +5 -0
- package/lib/Extensions/Extensions.js +12 -1
- package/lib/Extensions/ImageExtension/AssetImageExtension.d.ts +17 -0
- package/lib/Extensions/ImageExtension/AssetImageExtension.js +92 -0
- package/lib/Extensions/ImageExtension/ImageExtension.d.ts +1 -4
- package/lib/Extensions/ImageExtension/ImageExtension.js +4 -78
- package/lib/Extensions/LinkExtension/AssetLinkExtension.js +3 -3
- package/lib/Extensions/LinkExtension/LinkExtension.d.ts +1 -3
- package/lib/Extensions/LinkExtension/LinkExtension.js +1 -9
- package/lib/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.js +12 -3
- package/lib/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.js +14 -5
- package/lib/utils/resolveMatrixAssetUrl.d.ts +1 -0
- package/lib/utils/resolveMatrixAssetUrl.js +10 -0
- package/package.json +3 -3
- package/src/Editor/EditorContext.spec.tsx +3 -3
- package/src/Editor/EditorContext.ts +9 -2
- package/src/EditorToolbar/FloatingToolbar.spec.tsx +24 -4
- package/src/EditorToolbar/FloatingToolbar.tsx +1 -1
- package/src/EditorToolbar/Tools/Image/Form/ImageForm.spec.tsx +26 -5
- package/src/EditorToolbar/Tools/Image/Form/ImageForm.tsx +145 -96
- package/src/EditorToolbar/Tools/Image/ImageButton.spec.tsx +128 -7
- package/src/EditorToolbar/Tools/Image/ImageButton.tsx +15 -17
- package/src/EditorToolbar/Tools/Image/ImageModal.tsx +7 -1
- package/src/EditorToolbar/Tools/Link/Form/LinkForm.tsx +1 -1
- package/src/EditorToolbar/Tools/Link/LinkButton.spec.tsx +17 -5
- package/src/EditorToolbar/Tools/Link/RemoveLinkButton.spec.tsx +1 -0
- package/src/Extensions/Extensions.ts +11 -0
- package/src/Extensions/ImageExtension/AssetImageExtension.spec.ts +76 -0
- package/src/Extensions/ImageExtension/AssetImageExtension.ts +111 -0
- package/src/Extensions/ImageExtension/ImageExtension.ts +6 -99
- package/src/Extensions/LinkExtension/AssetLinkExtension.spec.ts +1 -1
- package/src/Extensions/LinkExtension/AssetLinkExtension.ts +3 -3
- package/src/Extensions/LinkExtension/LinkExtension.ts +2 -22
- package/src/utils/converters/mocks/squizNodeJson.mock.ts +19 -0
- package/src/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.ts +13 -3
- package/src/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.spec.ts +13 -1
- package/src/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.ts +13 -5
- package/src/utils/resolveMatrixAssetUrl.spec.ts +26 -0
- 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:
|
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
|
-
|
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:
|
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 ===
|
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 !==
|
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 ===
|
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(
|
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':
|
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:
|
26
|
-
span:
|
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:
|
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:
|
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
|
+
};
|