@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.
Files changed (44) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/demo/App.tsx +7 -1
  3. package/demo/AppContext.tsx +49 -18
  4. package/demo/resources.json +44 -0
  5. package/demo/sources.json +4 -0
  6. package/lib/Editor/Editor.js +8 -3
  7. package/lib/Editor/EditorContext.d.ts +2 -0
  8. package/lib/Editor/EditorContext.js +3 -0
  9. package/lib/Extensions/Extensions.d.ts +3 -2
  10. package/lib/Extensions/Extensions.js +4 -2
  11. package/lib/Extensions/FetchUrlExtension/FetchUrlExtension.d.ts +2 -4
  12. package/lib/Extensions/FetchUrlExtension/FetchUrlExtension.js +7 -7
  13. package/lib/index.d.ts +2 -0
  14. package/lib/types.d.ts +4 -0
  15. package/lib/ui/Fields/MatrixAsset/MatrixAsset.js +7 -7
  16. package/lib/utils/converters/htmlToSquizNode/htmlToSquizNode.js +2 -9
  17. package/lib/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.js +19 -4
  18. package/lib/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.js +23 -0
  19. package/package.json +11 -10
  20. package/src/Editor/Editor.spec.tsx +14 -4
  21. package/src/Editor/Editor.tsx +9 -3
  22. package/src/Editor/EditorContext.spec.tsx +1 -0
  23. package/src/Editor/EditorContext.ts +5 -0
  24. package/src/EditorToolbar/Tools/Image/Form/ImageForm.spec.tsx +5 -3
  25. package/src/EditorToolbar/Tools/Image/ImageButton.spec.tsx +6 -0
  26. package/src/EditorToolbar/Tools/Link/Form/LinkForm.spec.tsx +19 -7
  27. package/src/EditorToolbar/Tools/Link/LinkButton.spec.tsx +7 -1
  28. package/src/EditorToolbar/Tools/Link/RemoveLinkButton.spec.tsx +3 -3
  29. package/src/Extensions/Extensions.ts +4 -3
  30. package/src/Extensions/FetchUrlExtension/FetchUrlExtension.ts +12 -17
  31. package/src/Extensions/UnsuportedExtension/UnsupportedNodeExtension.spec.ts +1 -1
  32. package/src/index.ts +2 -0
  33. package/src/types.ts +3 -0
  34. package/src/ui/Fields/MatrixAsset/MatrixAsset.spec.tsx +26 -9
  35. package/src/ui/Fields/MatrixAsset/MatrixAsset.tsx +8 -8
  36. package/src/utils/converters/htmlToSquizNode/htmlToSquizNode.ts +6 -16
  37. package/src/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.spec.ts +457 -0
  38. package/src/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.ts +24 -5
  39. package/src/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.spec.ts +210 -0
  40. package/src/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.ts +23 -0
  41. package/tests/mockResourceBrowserContext.tsx +48 -12
  42. package/tests/renderWithContext.tsx +31 -3
  43. package/tests/renderWithEditor.tsx +1 -3
  44. 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={`<p>Hello <a href="https://www.google.com"><strong>Mr Bean</strong></a>, nice to <a href="https://www.google.com">meet you</a>.<img src="https://media2.giphy.com/media/3o6ozsIxg5legYvggo/giphy.gif" height="150" width="200"/></p>`}
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
  >
@@ -1,29 +1,48 @@
1
1
  import React, { PropsWithChildren } from 'react';
2
- import { ResourceBrowserContext, Source, Resource, ResourceReference } from '@squiz/resource-browser';
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
- <ResourceBrowserContext.Provider
15
+ <ResourceBrowserContextProvider
11
16
  value={{
12
- onRequestSources: (): Promise<Source> => Promise.resolve(sources),
13
- onRequestChildren: (source: Source, resource: Resource | null): Promise<Resource[]> =>
14
- Promise.resolve(resource._children || resources),
15
- onRequestResource: (reference: ResourceReference): Promise<Resource | null> => {
16
- const flattenResources = (resources: unknown[]) => {
17
- return [
18
- ...resources,
19
- ...resources.flatMap((resource) => ('_children' in resource ? flattenResources(resource._children) : [])),
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
- return Promise.resolve(
24
- flattenResources(resources).find((resource) => resource.id === reference.resource) || null,
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
- </ResourceBrowserContext.Provider>
69
+ </ResourceBrowserContextProvider>
39
70
  );
@@ -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
@@ -16,6 +16,10 @@
16
16
  "status": {
17
17
  "code": "live",
18
18
  "name": "Live"
19
+ },
20
+ "source": {
21
+ "id": "1",
22
+ "type": "matrix"
19
23
  }
20
24
  }
21
25
  ]
@@ -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), (0, react_1.useContext)(resource_browser_1.ResourceBrowserContext)),
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, state: state, editable: editable, onChange: handleChange, placeholder: "Write something", label: "Text editor", attributes: attributes },
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, browserContext: ResourceBrowserContextProps) => () => Extension[];
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, browserContext) => {
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: browserContext.onRequestResource,
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?: (params: {
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.matrixAssetId, node.attrs.matrixIdentifier, (url) => {
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.matrixAssetId, assetLinkMark.attrs.matrixIdentifier, (url) => {
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(resource, source, onFetched) {
45
+ fetchAndReplace(nodeAttrs, onFetched) {
46
46
  return this.options
47
- .fetchUrl({ resource, source })
48
- .then((asset) => {
49
- onFetched(asset.url);
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.ResourceBrowserInput, { modalTitle: modalTitle, allowedTypes: allowedTypes, value: value && value.matrixIdentifier && value.matrixAssetId
12
+ react_1.default.createElement(resource_browser_1.ResourceBrowser, { modalTitle: modalTitle, allowedTypes: allowedTypes, value: value && value.matrixIdentifier && value.matrixAssetId
13
13
  ? {
14
- source: value.matrixIdentifier,
15
- resource: value.matrixAssetId,
14
+ sourceId: value.matrixIdentifier,
15
+ resourceId: value.matrixAssetId,
16
16
  }
17
- : null, onChange: (reference) => {
17
+ : null, onChange: (resource) => {
18
18
  onChange({
19
19
  target: {
20
20
  value: {
21
21
  ...value,
22
- matrixIdentifier: reference?.source?.id,
23
- matrixAssetId: reference?.resource?.id,
24
- url: reference?.resource?.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
- onRequestResource: () => {
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
- const attributes = node.type.name === Extensions_1.NodeName.Image || node.type.name === Extensions_1.NodeName.CodeBlock
79
- ? transformAttributes(node.attrs)
80
- : undefined;
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": "1.70.0",
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.11.16",
24
+ "@mui/icons-material": "5.15.18",
25
25
  "@remirror/extension-react-tables": "^2.2.19",
26
- "@remirror/react": "2.0.25",
26
+ "@remirror/react": "2.0.35",
27
27
  "@squiz/dx-json-schema-lib": "^1.65.1",
28
- "@squiz/resource-browser": "^1.66.3",
29
- "clsx": "1.2.1",
30
- "react-hook-form": "7.43.2",
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.26"
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.3",
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": "4.1.2",
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.0"
63
+ "vite": "^4.5.3"
63
64
  },
64
65
  "peerDependencies": {
65
66
  "@types/react": "^16.14.0 || ^17 || ^18",