@squiz/formatted-text-editor 1.70.0 → 2.0.0
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 +18 -0
- package/demo/App.tsx +7 -1
- package/demo/AppContext.tsx +49 -18
- package/demo/resources.json +44 -0
- package/demo/sources.json +4 -0
- package/lib/Editor/Editor.js +8 -3
- package/lib/Editor/EditorContext.d.ts +2 -0
- package/lib/Editor/EditorContext.js +3 -0
- package/lib/Extensions/Extensions.d.ts +3 -2
- package/lib/Extensions/Extensions.js +4 -2
- package/lib/Extensions/FetchUrlExtension/FetchUrlExtension.d.ts +2 -4
- package/lib/Extensions/FetchUrlExtension/FetchUrlExtension.js +7 -7
- package/lib/index.d.ts +2 -0
- package/lib/types.d.ts +4 -0
- package/lib/ui/Fields/MatrixAsset/MatrixAsset.js +7 -7
- package/lib/utils/converters/htmlToSquizNode/htmlToSquizNode.js +2 -9
- package/lib/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.js +19 -4
- package/lib/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.js +23 -0
- package/package.json +11 -10
- package/src/Editor/Editor.spec.tsx +14 -4
- package/src/Editor/Editor.tsx +9 -3
- package/src/Editor/EditorContext.spec.tsx +1 -0
- package/src/Editor/EditorContext.ts +5 -0
- package/src/EditorToolbar/Tools/Image/Form/ImageForm.spec.tsx +5 -3
- package/src/EditorToolbar/Tools/Image/ImageButton.spec.tsx +6 -0
- package/src/EditorToolbar/Tools/Link/Form/LinkForm.spec.tsx +19 -7
- package/src/EditorToolbar/Tools/Link/LinkButton.spec.tsx +7 -1
- package/src/EditorToolbar/Tools/Link/RemoveLinkButton.spec.tsx +3 -3
- package/src/Extensions/Extensions.ts +4 -3
- package/src/Extensions/FetchUrlExtension/FetchUrlExtension.ts +12 -17
- package/src/Extensions/UnsuportedExtension/UnsupportedNodeExtension.spec.ts +1 -1
- package/src/index.ts +2 -0
- package/src/types.ts +3 -0
- package/src/ui/Fields/MatrixAsset/MatrixAsset.spec.tsx +26 -9
- package/src/ui/Fields/MatrixAsset/MatrixAsset.tsx +8 -8
- package/src/utils/converters/htmlToSquizNode/htmlToSquizNode.ts +6 -16
- package/src/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.spec.ts +457 -0
- package/src/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.ts +24 -5
- package/src/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.spec.ts +210 -0
- package/src/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.ts +23 -0
- package/tests/mockResourceBrowserContext.tsx +48 -12
- package/tests/renderWithContext.tsx +31 -3
- package/tests/renderWithEditor.tsx +1 -3
- package/vite.config.ts +2 -2
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,23 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 2.0.0
|
4
|
+
|
5
|
+
### Major Changes
|
6
|
+
|
7
|
+
- f7279c6: Migration to resource-browser 2.x.x and use of plugin model. Alterations to data fetching for url resolution for FTE due to changes in RB2.
|
8
|
+
|
9
|
+
Breaking change: change to resource-browser 2.x.x requires a different context wrapper to version 1.x.x which the component editing ui and the formatted text editor relies upon to render the resource picker when selecting a resource; making the internal update to RB2 incompatible with 1.x.x usages of these packages.
|
10
|
+
|
11
|
+
This change was made to expand the support the resource browser had for data sources other than Matrix.
|
12
|
+
|
13
|
+
Consumers need to update usages of ResourceBrowserContext.provider with ResourceBrowserContextProvider and provide plugins e.g. @squiz/matrix-resource-browser-plugin or @squiz/dam-resource-browser-plugin to the context interface. Consumers also need to provide a new url fetcher to the FTE EditorContext.Provider `resolveNodeToUrl` to resolve MatrixAsset nodes to a url form; previously this relied upon exposed parts of the ResourceBrowser which are no longer exposed outside the RB itself.
|
14
|
+
|
15
|
+
## 1.71.0
|
16
|
+
|
17
|
+
### Minor Changes
|
18
|
+
|
19
|
+
- 882fb82: Added table transormation support between Squiz & Remirror models (allowing saving of tables)
|
20
|
+
|
3
21
|
## 1.70.0
|
4
22
|
|
5
23
|
### Minor Changes
|
package/demo/App.tsx
CHANGED
@@ -76,7 +76,13 @@ function App() {
|
|
76
76
|
<Editor
|
77
77
|
editable={editable}
|
78
78
|
border={border}
|
79
|
-
content={
|
79
|
+
content={`
|
80
|
+
<p>Hello
|
81
|
+
<a href="https://www.google.com"><strong>Mr Bean</strong></a>, nice to <a href="https://www.google.com">meet you</a>.
|
82
|
+
<img src="https://media2.giphy.com/media/3o6ozsIxg5legYvggo/giphy.gif" height="150" width="200"/>
|
83
|
+
<img data-matrix-asset-id="1" data-matrix-identifier="matrixIdentifier" data-matrix-domain="https://matrix-domain.squiz.net">
|
84
|
+
</p>
|
85
|
+
`}
|
80
86
|
onChange={handleEditorChange}
|
81
87
|
enableTableTool={enableTableTool}
|
82
88
|
>
|
package/demo/AppContext.tsx
CHANGED
@@ -1,29 +1,48 @@
|
|
1
1
|
import React, { PropsWithChildren } from 'react';
|
2
|
-
import {
|
2
|
+
import { ResourceBrowserSource, ResourceBrowserContextProvider } from '@squiz/resource-browser';
|
3
|
+
import MatrixResourceBrowserPlugin, {
|
4
|
+
Source,
|
5
|
+
Resource,
|
6
|
+
ResourceReference,
|
7
|
+
} from '@squiz/matrix-resource-browser-plugin';
|
3
8
|
import { EditorContext } from '../src';
|
4
9
|
import resources from './resources.json';
|
5
10
|
import sources from './sources.json';
|
11
|
+
import { ResolveNodeType } from '../src/types';
|
6
12
|
|
7
13
|
export type AppContextProps = PropsWithChildren;
|
8
|
-
|
9
14
|
export const AppContext = ({ children }: AppContextProps) => (
|
10
|
-
<
|
15
|
+
<ResourceBrowserContextProvider
|
11
16
|
value={{
|
12
|
-
onRequestSources: (): Promise<
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
onRequestSources: (): Promise<ResourceBrowserSource[]> =>
|
18
|
+
Promise.resolve([
|
19
|
+
{
|
20
|
+
name: 'Matrix',
|
21
|
+
id: 'matrixIdentifier',
|
22
|
+
type: 'matrix',
|
23
|
+
},
|
24
|
+
]),
|
25
|
+
plugins: [
|
26
|
+
MatrixResourceBrowserPlugin({
|
27
|
+
onRequestSources: (): Promise<Source> => Promise.resolve(sources),
|
28
|
+
onRequestChildren: (source: Source, resource: Resource | null): Promise<Resource[]> =>
|
29
|
+
Promise.resolve(resource._children || resources),
|
30
|
+
onRequestResource: (reference: ResourceReference): Promise<Resource | null> => {
|
31
|
+
const flattenResources = (resources: unknown[]) => {
|
32
|
+
return [
|
33
|
+
...resources,
|
34
|
+
...resources.flatMap((resource) =>
|
35
|
+
'_children' in resource ? flattenResources(resource._children) : [],
|
36
|
+
),
|
37
|
+
];
|
38
|
+
};
|
22
39
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
40
|
+
return Promise.resolve(
|
41
|
+
flattenResources(resources).find((resource) => resource.id === reference.resource) || null,
|
42
|
+
);
|
43
|
+
},
|
44
|
+
}),
|
45
|
+
],
|
27
46
|
}}
|
28
47
|
>
|
29
48
|
<EditorContext.Provider
|
@@ -31,9 +50,21 @@ export const AppContext = ({ children }: AppContextProps) => (
|
|
31
50
|
matrix: {
|
32
51
|
matrixDomain: 'https://matrix-domain.squiz.net',
|
33
52
|
},
|
53
|
+
resolveNodeToUrl: (node: ResolveNodeType): Promise<string> => {
|
54
|
+
const nodeResource = node.matrixAssetId;
|
55
|
+
const flattenResources = (resources: unknown[]) => {
|
56
|
+
return [
|
57
|
+
...resources,
|
58
|
+
...resources.flatMap((resource) => ('_children' in resource ? flattenResources(resource._children) : [])),
|
59
|
+
];
|
60
|
+
};
|
61
|
+
|
62
|
+
const resource = flattenResources(resources).find((resource) => resource.id === nodeResource);
|
63
|
+
return Promise.resolve(resource.url || '');
|
64
|
+
},
|
34
65
|
}}
|
35
66
|
>
|
36
67
|
{children}
|
37
68
|
</EditorContext.Provider>
|
38
|
-
</
|
69
|
+
</ResourceBrowserContextProvider>
|
39
70
|
);
|
package/demo/resources.json
CHANGED
@@ -9,6 +9,10 @@
|
|
9
9
|
"code": "live",
|
10
10
|
"name": "Live"
|
11
11
|
},
|
12
|
+
"source": {
|
13
|
+
"id": "1",
|
14
|
+
"type": "matrix"
|
15
|
+
},
|
12
16
|
"name": "Example image one",
|
13
17
|
"childCount": 0,
|
14
18
|
"url": "https://picsum.photos/200/300"
|
@@ -23,6 +27,10 @@
|
|
23
27
|
"code": "live",
|
24
28
|
"name": "Live"
|
25
29
|
},
|
30
|
+
"source": {
|
31
|
+
"id": "1",
|
32
|
+
"type": "matrix"
|
33
|
+
},
|
26
34
|
"name": "Example image two",
|
27
35
|
"childCount": 0,
|
28
36
|
"url": "https://picsum.photos/200/300"
|
@@ -37,6 +45,10 @@
|
|
37
45
|
"code": "live",
|
38
46
|
"name": "Live"
|
39
47
|
},
|
48
|
+
"source": {
|
49
|
+
"id": "1",
|
50
|
+
"type": "matrix"
|
51
|
+
},
|
40
52
|
"name": "Example page",
|
41
53
|
"childCount": 0,
|
42
54
|
"url": "https://picsum.photos/200/300"
|
@@ -51,6 +63,10 @@
|
|
51
63
|
"code": "live",
|
52
64
|
"name": "Live"
|
53
65
|
},
|
66
|
+
"source": {
|
67
|
+
"id": "1",
|
68
|
+
"type": "matrix"
|
69
|
+
},
|
54
70
|
"name": "Example folder",
|
55
71
|
"childCount": 10,
|
56
72
|
"url": "",
|
@@ -65,6 +81,10 @@
|
|
65
81
|
"code": "live",
|
66
82
|
"name": "Live"
|
67
83
|
},
|
84
|
+
"source": {
|
85
|
+
"id": "1",
|
86
|
+
"type": "matrix"
|
87
|
+
},
|
68
88
|
"name": "Example image one #2",
|
69
89
|
"childCount": 0,
|
70
90
|
"url": "https://picsum.photos/200/300"
|
@@ -79,6 +99,10 @@
|
|
79
99
|
"code": "live",
|
80
100
|
"name": "Live"
|
81
101
|
},
|
102
|
+
"source": {
|
103
|
+
"id": "1",
|
104
|
+
"type": "matrix"
|
105
|
+
},
|
82
106
|
"name": "Example image two #2",
|
83
107
|
"childCount": 0,
|
84
108
|
"url": "https://picsum.photos/200/300"
|
@@ -93,6 +117,10 @@
|
|
93
117
|
"code": "live",
|
94
118
|
"name": "Live"
|
95
119
|
},
|
120
|
+
"source": {
|
121
|
+
"id": "1",
|
122
|
+
"type": "matrix"
|
123
|
+
},
|
96
124
|
"name": "Example page #2",
|
97
125
|
"childCount": 0,
|
98
126
|
"url": "https://picsum.photos/200/300"
|
@@ -107,6 +135,10 @@
|
|
107
135
|
"code": "live",
|
108
136
|
"name": "Live"
|
109
137
|
},
|
138
|
+
"source": {
|
139
|
+
"id": "1",
|
140
|
+
"type": "matrix"
|
141
|
+
},
|
110
142
|
"name": "Example folder #2",
|
111
143
|
"childCount": 10,
|
112
144
|
"url": "",
|
@@ -121,6 +153,10 @@
|
|
121
153
|
"code": "live",
|
122
154
|
"name": "Live"
|
123
155
|
},
|
156
|
+
"source": {
|
157
|
+
"id": "1",
|
158
|
+
"type": "matrix"
|
159
|
+
},
|
124
160
|
"name": "Example image one #3",
|
125
161
|
"childCount": 0,
|
126
162
|
"url": "https://picsum.photos/200/300"
|
@@ -135,6 +171,10 @@
|
|
135
171
|
"code": "live",
|
136
172
|
"name": "Live"
|
137
173
|
},
|
174
|
+
"source": {
|
175
|
+
"id": "1",
|
176
|
+
"type": "matrix"
|
177
|
+
},
|
138
178
|
"name": "Example image two #3",
|
139
179
|
"childCount": 0,
|
140
180
|
"url": "https://picsum.photos/200/300"
|
@@ -149,6 +189,10 @@
|
|
149
189
|
"code": "live",
|
150
190
|
"name": "Live"
|
151
191
|
},
|
192
|
+
"source": {
|
193
|
+
"id": "1",
|
194
|
+
"type": "matrix"
|
195
|
+
},
|
152
196
|
"name": "Example page #3",
|
153
197
|
"childCount": 0,
|
154
198
|
"url": "https://picsum.photos/200/300"
|
package/demo/sources.json
CHANGED
package/lib/Editor/Editor.js
CHANGED
@@ -33,7 +33,6 @@ const EditorToolbar_1 = require("../EditorToolbar");
|
|
33
33
|
const EditorContext_1 = require("./EditorContext");
|
34
34
|
const Extensions_1 = require("../Extensions/Extensions");
|
35
35
|
const useFocus_1 = __importDefault(require("../hooks/useFocus"));
|
36
|
-
const resource_browser_1 = require("@squiz/resource-browser");
|
37
36
|
const extension_react_tables_1 = require("@remirror/extension-react-tables");
|
38
37
|
const WrappedEditor = () => {
|
39
38
|
const preventImagePaste = (0, react_1.useCallback)((event) => {
|
@@ -53,7 +52,7 @@ const WrappedEditor = () => {
|
|
53
52
|
};
|
54
53
|
const Editor = ({ content, className, border = true, editable = true, onChange, children, isFocused, attributes, enableTableTool = false, }) => {
|
55
54
|
const { manager, state, setState } = (0, react_2.useRemirror)({
|
56
|
-
extensions: (0, Extensions_1.createExtensions)((0, react_1.useContext)(EditorContext_1.EditorContext)
|
55
|
+
extensions: (0, Extensions_1.createExtensions)((0, react_1.useContext)(EditorContext_1.EditorContext)),
|
57
56
|
content,
|
58
57
|
selection: 'start',
|
59
58
|
stringHandler: 'html',
|
@@ -68,9 +67,15 @@ const Editor = ({ content, className, border = true, editable = true, onChange,
|
|
68
67
|
if (isFocused) {
|
69
68
|
manager.view.dom.focus();
|
70
69
|
}
|
70
|
+
// TODO: May want to come back to this and see if there's a better solution
|
71
|
+
// We have to add a type button attribute to the delete buttons so they don't cause a submit by accident.
|
72
|
+
const tableDeleteButtons = document.querySelectorAll('.remirror-table-delete-inner-button');
|
73
|
+
tableDeleteButtons.forEach((button) => {
|
74
|
+
button.setAttribute('type', 'button');
|
75
|
+
});
|
71
76
|
}, []);
|
72
77
|
return (react_1.default.createElement("div", { ref: wrapperRef, onBlur: handleBlur, onFocusCapture: handleFocus, className: (0, clsx_1.default)('squiz-fte-scope', 'squiz-fte-scope__editor', !editable && 'squiz-fte-scope__editor--is-disabled', border && 'squiz-fte-scope__editor--bordered', className) },
|
73
|
-
react_1.default.createElement(react_2.Remirror, { manager: manager,
|
78
|
+
react_1.default.createElement(react_2.Remirror, { manager: manager, initialContent: state, editable: editable, onChange: handleChange, placeholder: "Write something", label: "Text editor", attributes: attributes },
|
74
79
|
editable && react_1.default.createElement(EditorToolbar_1.Toolbar, { isVisible: isVisible, enableTableTool: enableTableTool }),
|
75
80
|
children && react_1.default.createElement("div", { className: "squiz-fte-scope__editor__children" }, children),
|
76
81
|
react_1.default.createElement(WrappedEditor, null),
|
@@ -1,8 +1,10 @@
|
|
1
1
|
import React from 'react';
|
2
|
+
import { ResolveNodeToUrl } from '../types';
|
2
3
|
export type EditorContextOptions = {
|
3
4
|
matrix: {
|
4
5
|
matrixDomain: string;
|
5
6
|
};
|
7
|
+
resolveNodeToUrl: ResolveNodeToUrl;
|
6
8
|
};
|
7
9
|
export declare const defaultEditorContext: EditorContextOptions;
|
8
10
|
export declare const EditorContext: React.Context<EditorContextOptions>;
|
@@ -9,5 +9,8 @@ exports.defaultEditorContext = {
|
|
9
9
|
matrix: {
|
10
10
|
matrixDomain: '',
|
11
11
|
},
|
12
|
+
resolveNodeToUrl: () => {
|
13
|
+
throw new Error('resolveNodeToUrl has not been configured.');
|
14
|
+
},
|
12
15
|
};
|
13
16
|
exports.EditorContext = react_1.default.createContext(exports.defaultEditorContext);
|
@@ -1,11 +1,12 @@
|
|
1
1
|
import { Extension } from '@remirror/core';
|
2
2
|
import { EditorContextOptions } from '../Editor/EditorContext';
|
3
|
-
import { ResourceBrowserContextProps } from '@squiz/resource-browser';
|
4
3
|
export declare enum NodeName {
|
5
4
|
Image = "image",
|
6
5
|
CodeBlock = "codeBlock",
|
7
6
|
AssetImage = "assetImage",
|
8
7
|
Text = "text",
|
8
|
+
TableControllerCell = "tableControllerCell",
|
9
|
+
tableCell = "tableCell",
|
9
10
|
hardBreak = "hardBreak",
|
10
11
|
Unsupported = "unsupportedNode"
|
11
12
|
}
|
@@ -13,4 +14,4 @@ export declare enum MarkName {
|
|
13
14
|
Link = "link",
|
14
15
|
AssetLink = "assetLink"
|
15
16
|
}
|
16
|
-
export declare const createExtensions: (context: EditorContextOptions
|
17
|
+
export declare const createExtensions: (context: EditorContextOptions) => () => Extension[];
|
@@ -20,6 +20,8 @@ var NodeName;
|
|
20
20
|
NodeName["CodeBlock"] = "codeBlock";
|
21
21
|
NodeName["AssetImage"] = "assetImage";
|
22
22
|
NodeName["Text"] = "text";
|
23
|
+
NodeName["TableControllerCell"] = "tableControllerCell";
|
24
|
+
NodeName["tableCell"] = "tableCell";
|
23
25
|
NodeName["hardBreak"] = "hardBreak";
|
24
26
|
NodeName["Unsupported"] = "unsupportedNode";
|
25
27
|
})(NodeName = exports.NodeName || (exports.NodeName = {}));
|
@@ -28,7 +30,7 @@ var MarkName;
|
|
28
30
|
MarkName["Link"] = "link";
|
29
31
|
MarkName["AssetLink"] = "assetLink";
|
30
32
|
})(MarkName = exports.MarkName || (exports.MarkName = {}));
|
31
|
-
const createExtensions = (context
|
33
|
+
const createExtensions = (context) => {
|
32
34
|
return () => {
|
33
35
|
return [
|
34
36
|
new CommandsExtension_1.CommandsExtension(),
|
@@ -60,7 +62,7 @@ const createExtensions = (context, browserContext) => {
|
|
60
62
|
new extensions_1.HorizontalRuleExtension(),
|
61
63
|
new extensions_1.PlaceholderExtension(),
|
62
64
|
new FetchUrlExtension_1.FetchUrlExtension({
|
63
|
-
fetchUrl:
|
65
|
+
fetchUrl: context.resolveNodeToUrl,
|
64
66
|
}),
|
65
67
|
new extensions_1.TextExtension(),
|
66
68
|
new extension_react_tables_1.TableExtension(),
|
@@ -1,10 +1,8 @@
|
|
1
1
|
import { PlainExtension } from '@remirror/core';
|
2
2
|
import { Dispose, EditorView } from '@remirror/core-types';
|
3
|
+
import { ResolveNodeToUrl } from '../../types';
|
3
4
|
export type FetchUrlOptions = {
|
4
|
-
fetchUrl?:
|
5
|
-
resource: string;
|
6
|
-
source: string;
|
7
|
-
}) => Promise<any>;
|
5
|
+
fetchUrl?: ResolveNodeToUrl;
|
8
6
|
};
|
9
7
|
export declare class FetchUrlExtension extends PlainExtension<FetchUrlOptions> {
|
10
8
|
get name(): string;
|
@@ -20,14 +20,14 @@ let FetchUrlExtension = class FetchUrlExtension extends core_1.PlainExtension {
|
|
20
20
|
const promises = [];
|
21
21
|
state.doc.descendants((node, pos) => {
|
22
22
|
if (node.type.name === Extensions_1.NodeName.AssetImage && node.attrs.src === '') {
|
23
|
-
promises.push(this.fetchAndReplace(node.attrs
|
23
|
+
promises.push(this.fetchAndReplace(node.attrs, (url) => {
|
24
24
|
const newNode = state.schema.nodes[Extensions_1.NodeName.AssetImage].create({ ...node.attrs, src: url });
|
25
25
|
tr.replaceWith(pos, pos + node.nodeSize, newNode);
|
26
26
|
}));
|
27
27
|
}
|
28
28
|
const assetLinkMark = this.findAssetLinkMark(node.marks);
|
29
29
|
if (node.type.name === 'text' && assetLinkMark) {
|
30
|
-
promises.push(this.fetchAndReplace(assetLinkMark.attrs
|
30
|
+
promises.push(this.fetchAndReplace(assetLinkMark.attrs, (url) => {
|
31
31
|
const updatedMark = assetLinkMark.type.create({ ...assetLinkMark.attrs, href: url });
|
32
32
|
tr.addMark(pos, pos + node.nodeSize, updatedMark);
|
33
33
|
}));
|
@@ -42,11 +42,11 @@ let FetchUrlExtension = class FetchUrlExtension extends core_1.PlainExtension {
|
|
42
42
|
findAssetLinkMark(marks) {
|
43
43
|
return marks.find((mark) => mark.type.name === Extensions_1.MarkName.AssetLink && mark.attrs.href === '');
|
44
44
|
}
|
45
|
-
fetchAndReplace(
|
45
|
+
fetchAndReplace(nodeAttrs, onFetched) {
|
46
46
|
return this.options
|
47
|
-
.fetchUrl(
|
48
|
-
.then((
|
49
|
-
onFetched(
|
47
|
+
.fetchUrl(nodeAttrs)
|
48
|
+
.then((url) => {
|
49
|
+
onFetched(url);
|
50
50
|
})
|
51
51
|
.catch((error) => {
|
52
52
|
console.error('Error fetching URL:', error);
|
@@ -56,7 +56,7 @@ let FetchUrlExtension = class FetchUrlExtension extends core_1.PlainExtension {
|
|
56
56
|
FetchUrlExtension = __decorate([
|
57
57
|
(0, core_1.extension)({
|
58
58
|
defaultOptions: {
|
59
|
-
fetchUrl: () => Promise.resolve(),
|
59
|
+
fetchUrl: () => Promise.resolve(''),
|
60
60
|
},
|
61
61
|
})
|
62
62
|
], FetchUrlExtension);
|
package/lib/index.d.ts
CHANGED
@@ -3,4 +3,6 @@ import { EditorContext } from './Editor/EditorContext';
|
|
3
3
|
import { remirrorNodeToSquizNode } from './utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode';
|
4
4
|
import { squizNodeToRemirrorNode } from './utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode';
|
5
5
|
import { htmlToSquizNode } from './utils/converters/htmlToSquizNode/htmlToSquizNode';
|
6
|
+
import { ResolveNodeType, ResolveNodeToUrl } from './types';
|
6
7
|
export { Editor, EditorContext, remirrorNodeToSquizNode, squizNodeToRemirrorNode, htmlToSquizNode };
|
8
|
+
export type { ResolveNodeType, ResolveNodeToUrl };
|
package/lib/types.d.ts
CHANGED
@@ -1,3 +1,7 @@
|
|
1
1
|
export type DeepPartial<T> = {
|
2
2
|
[P in keyof T]?: T[P] extends Array<infer U> ? Array<DeepPartial<U>> : T[P] extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>> : DeepPartial<T[P]>;
|
3
3
|
};
|
4
|
+
export type ResolveNodeType = {
|
5
|
+
[attr: string]: any;
|
6
|
+
};
|
7
|
+
export type ResolveNodeToUrl = (node: ResolveNodeType) => Promise<string>;
|
@@ -9,19 +9,19 @@ const resource_browser_1 = require("@squiz/resource-browser");
|
|
9
9
|
const InputContainer_1 = require("../InputContainer/InputContainer");
|
10
10
|
const MatrixAsset = ({ modalTitle, allowedTypes, value, onChange, ...props }) => {
|
11
11
|
return (react_1.default.createElement(InputContainer_1.InputContainer, { ...props },
|
12
|
-
react_1.default.createElement(resource_browser_1.
|
12
|
+
react_1.default.createElement(resource_browser_1.ResourceBrowser, { modalTitle: modalTitle, allowedTypes: allowedTypes, value: value && value.matrixIdentifier && value.matrixAssetId
|
13
13
|
? {
|
14
|
-
|
15
|
-
|
14
|
+
sourceId: value.matrixIdentifier,
|
15
|
+
resourceId: value.matrixAssetId,
|
16
16
|
}
|
17
|
-
: null, onChange: (
|
17
|
+
: null, onChange: (resource) => {
|
18
18
|
onChange({
|
19
19
|
target: {
|
20
20
|
value: {
|
21
21
|
...value,
|
22
|
-
matrixIdentifier:
|
23
|
-
matrixAssetId:
|
24
|
-
url:
|
22
|
+
matrixIdentifier: resource?.source?.id,
|
23
|
+
matrixAssetId: resource?.id,
|
24
|
+
url: resource?.url,
|
25
25
|
},
|
26
26
|
},
|
27
27
|
});
|
@@ -10,15 +10,8 @@ const htmlToSquizNode = ({ content }) => {
|
|
10
10
|
matrix: {
|
11
11
|
matrixDomain: 'unsupported',
|
12
12
|
},
|
13
|
-
|
14
|
-
|
15
|
-
throw new Error('Resolving Matrix assets is not supported.');
|
16
|
-
},
|
17
|
-
onRequestSources: () => {
|
18
|
-
throw new Error('Resolving Matrix assets is not supported.');
|
19
|
-
},
|
20
|
-
onRequestChildren: () => {
|
21
|
-
throw new Error('Resolving Matrix assets is not supported.');
|
13
|
+
resolveNodeToUrl: () => {
|
14
|
+
throw new Error('Resolving Url is not supported.');
|
22
15
|
},
|
23
16
|
});
|
24
17
|
const manager = core_1.RemirrorManager.create(extensions);
|
@@ -55,7 +55,7 @@ const resolveFontOptions = (node) => {
|
|
55
55
|
});
|
56
56
|
return fontOptions;
|
57
57
|
};
|
58
|
-
const transformAttributes = (attributes) => {
|
58
|
+
const transformAttributes = (attributes, nodeType) => {
|
59
59
|
const transformed = {};
|
60
60
|
Object.keys(attributes).forEach((key) => {
|
61
61
|
// Component service requires attributes to be a string, cast as needed.
|
@@ -63,6 +63,17 @@ const transformAttributes = (attributes) => {
|
|
63
63
|
transformed[key] = String(attributes[key]);
|
64
64
|
}
|
65
65
|
});
|
66
|
+
// We assign an attribute here for table controller cells as we need to differentiate
|
67
|
+
// between them and regular table headers (th)
|
68
|
+
if (nodeType === Extensions_1.NodeName.TableControllerCell) {
|
69
|
+
transformed[nodeType] = 'true';
|
70
|
+
}
|
71
|
+
// Another check here for more specific attributes for tables (column widths)
|
72
|
+
if (nodeType === Extensions_1.NodeName.TableControllerCell || nodeType === Extensions_1.NodeName.tableCell) {
|
73
|
+
if (Array.isArray(attributes.colwidth) && attributes.colwidth[0]) {
|
74
|
+
transformed.colwidth = String(attributes.colwidth[0]);
|
75
|
+
}
|
76
|
+
}
|
66
77
|
return transformed;
|
67
78
|
};
|
68
79
|
const transformFragment = (fragment) => {
|
@@ -75,9 +86,13 @@ const transformFragment = (fragment) => {
|
|
75
86
|
const transformNode = (node) => {
|
76
87
|
const formattingOptions = (0, undefinedIfEmpty_1.undefinedIfEmpty)(resolveFormattingOptions(node));
|
77
88
|
const font = (0, undefinedIfEmpty_1.undefinedIfEmpty)(resolveFontOptions(node));
|
78
|
-
|
79
|
-
|
80
|
-
|
89
|
+
let attributes;
|
90
|
+
if (node.type.name === Extensions_1.NodeName.Image ||
|
91
|
+
node.type.name === Extensions_1.NodeName.CodeBlock ||
|
92
|
+
node.type.name === Extensions_1.NodeName.TableControllerCell ||
|
93
|
+
node.type.name === Extensions_1.NodeName.tableCell) {
|
94
|
+
attributes = transformAttributes(node.attrs, node.type.name);
|
95
|
+
}
|
81
96
|
let transformedNode = { type: 'text', value: node.text || '' };
|
82
97
|
// Squiz "text" nodes can't have formatting/font options but Remirror "text" nodes can.
|
83
98
|
// If the node has formatting options wrap in a tag.
|
@@ -23,6 +23,10 @@ const getNodeType = (node) => {
|
|
23
23
|
li: 'listItem',
|
24
24
|
ul: 'bulletList',
|
25
25
|
hr: 'horizontalRule',
|
26
|
+
table: 'table',
|
27
|
+
tr: 'tableRow',
|
28
|
+
th: 'tableHeaderCell',
|
29
|
+
td: 'tableCell',
|
26
30
|
a: Extensions_1.NodeName.Text,
|
27
31
|
em: Extensions_1.NodeName.Text,
|
28
32
|
span: Extensions_1.NodeName.Text,
|
@@ -34,6 +38,12 @@ const getNodeType = (node) => {
|
|
34
38
|
return typeMap[node.type];
|
35
39
|
}
|
36
40
|
if (node.type === 'tag' && tagMap[node.tag]) {
|
41
|
+
// This is a specific check case for tables as there are some <th> tags which need to be returned
|
42
|
+
// as table controller cells.
|
43
|
+
if (node.attributes?.tableControllerCell) {
|
44
|
+
return 'tableControllerCell';
|
45
|
+
}
|
46
|
+
// Return regular tag for everything else
|
37
47
|
return tagMap[node.tag];
|
38
48
|
}
|
39
49
|
// Unsupported node type
|
@@ -42,6 +52,19 @@ const getNodeType = (node) => {
|
|
42
52
|
: `Unsupported node type provided: ${node.type}`);
|
43
53
|
};
|
44
54
|
const getNodeAttributes = (node) => {
|
55
|
+
if (node.type === 'tag' && node.tag === 'table') {
|
56
|
+
return {
|
57
|
+
isControllersInjected: true,
|
58
|
+
};
|
59
|
+
}
|
60
|
+
if (node.type === 'tag' && (node.tag === 'th' || node.tag === 'td')) {
|
61
|
+
return {
|
62
|
+
colspan: parseInt(node.attributes?.colspan ?? '1'),
|
63
|
+
rowspan: parseInt(node.attributes?.rowspan ?? '1'),
|
64
|
+
colwidth: node.attributes?.colwidth ? [parseInt(node.attributes.colwidth)] : null,
|
65
|
+
background: null,
|
66
|
+
};
|
67
|
+
}
|
45
68
|
if (node.type === 'tag' && node.tag === 'img') {
|
46
69
|
return {
|
47
70
|
alt: node.attributes?.alt,
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@squiz/formatted-text-editor",
|
3
|
-
"version": "
|
3
|
+
"version": "2.0.0",
|
4
4
|
"main": "lib/index.js",
|
5
5
|
"types": "lib/index.d.ts",
|
6
6
|
"private": false,
|
@@ -21,15 +21,16 @@
|
|
21
21
|
},
|
22
22
|
"dependencies": {
|
23
23
|
"@headlessui/react": "1.7.11",
|
24
|
-
"@mui/icons-material": "5.
|
24
|
+
"@mui/icons-material": "5.15.18",
|
25
25
|
"@remirror/extension-react-tables": "^2.2.19",
|
26
|
-
"@remirror/react": "2.0.
|
26
|
+
"@remirror/react": "2.0.35",
|
27
27
|
"@squiz/dx-json-schema-lib": "^1.65.1",
|
28
|
-
"@squiz/resource-browser": "^
|
29
|
-
"
|
30
|
-
"
|
28
|
+
"@squiz/matrix-resource-browser-plugin": "^2.0.0",
|
29
|
+
"@squiz/resource-browser": "^2.0.0",
|
30
|
+
"clsx": "2.1.1",
|
31
|
+
"react-hook-form": "7.51.4",
|
31
32
|
"react-image-size": "2.0.0",
|
32
|
-
"remirror": "2.0.
|
33
|
+
"remirror": "2.0.39"
|
33
34
|
},
|
34
35
|
"devDependencies": {
|
35
36
|
"@testing-library/cypress": "9.0.0",
|
@@ -48,18 +49,18 @@
|
|
48
49
|
"eslint-plugin-react": "7.32.2",
|
49
50
|
"jest": "29.4.1",
|
50
51
|
"jest-environment-jsdom": "29.4.1",
|
51
|
-
"jest-remirror": "2.1.
|
52
|
+
"jest-remirror": "2.1.5",
|
52
53
|
"postcss": "8.4.31",
|
53
54
|
"postcss-nested": "6.0.0",
|
54
55
|
"postcss-prefix-selector": "1.16.0",
|
55
56
|
"react": "18.2.0",
|
56
57
|
"react-diff-viewer-continued": "3.2.6",
|
57
58
|
"react-dom": "18.2.0",
|
58
|
-
"rimraf": "
|
59
|
+
"rimraf": "5.0.7",
|
59
60
|
"tailwindcss": "3.2.6",
|
60
61
|
"ts-jest": "29.0.5",
|
61
62
|
"typescript": "4.9.3",
|
62
|
-
"vite": "^4.5.
|
63
|
+
"vite": "^4.5.3"
|
63
64
|
},
|
64
65
|
"peerDependencies": {
|
65
66
|
"@types/react": "^16.14.0 || ^17 || ^18",
|