@squiz/formatted-text-editor 1.21.1-alpha.19 → 1.21.1-alpha.20

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 (86) hide show
  1. package/demo/App.tsx +31 -10
  2. package/demo/index.scss +2 -7
  3. package/lib/Editor/Editor.js +26 -2
  4. package/lib/Editor/EditorContext.d.ts +10 -0
  5. package/lib/Editor/EditorContext.js +15 -0
  6. package/lib/EditorToolbar/FloatingToolbar.js +15 -16
  7. package/lib/EditorToolbar/Tools/Link/Form/LinkForm.d.ts +14 -5
  8. package/lib/EditorToolbar/Tools/Link/Form/LinkForm.js +66 -14
  9. package/lib/EditorToolbar/Tools/Link/LinkButton.js +11 -15
  10. package/lib/EditorToolbar/Tools/Link/LinkModal.js +12 -5
  11. package/lib/EditorToolbar/Tools/Link/RemoveLinkButton.js +1 -8
  12. package/lib/Extensions/CommandsExtension/CommandsExtension.d.ts +20 -0
  13. package/lib/Extensions/CommandsExtension/CommandsExtension.js +52 -0
  14. package/lib/Extensions/Extensions.d.ts +6 -1
  15. package/lib/Extensions/Extensions.js +31 -20
  16. package/lib/Extensions/LinkExtension/AssetLinkExtension.d.ts +26 -0
  17. package/lib/Extensions/LinkExtension/AssetLinkExtension.js +102 -0
  18. package/lib/Extensions/LinkExtension/LinkExtension.d.ts +21 -12
  19. package/lib/Extensions/LinkExtension/LinkExtension.js +63 -65
  20. package/lib/Extensions/LinkExtension/common.d.ts +7 -0
  21. package/lib/Extensions/LinkExtension/common.js +14 -0
  22. package/lib/hooks/index.d.ts +1 -0
  23. package/lib/hooks/index.js +1 -0
  24. package/lib/hooks/useExpandedSelection.d.ts +23 -0
  25. package/lib/hooks/useExpandedSelection.js +37 -0
  26. package/lib/index.css +15 -3
  27. package/lib/index.d.ts +3 -2
  28. package/lib/index.js +5 -3
  29. package/lib/types.d.ts +3 -0
  30. package/lib/types.js +2 -0
  31. package/lib/ui/Button/Button.js +2 -3
  32. package/lib/ui/Fields/Input/Input.d.ts +1 -0
  33. package/lib/ui/Fields/Input/Input.js +8 -3
  34. package/lib/ui/Modal/Modal.js +2 -1
  35. package/lib/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.d.ts +1 -2
  36. package/lib/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.js +110 -105
  37. package/lib/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.js +93 -69
  38. package/lib/utils/undefinedIfEmpty.d.ts +1 -0
  39. package/lib/utils/undefinedIfEmpty.js +7 -0
  40. package/package.json +3 -2
  41. package/src/Editor/Editor.spec.tsx +0 -26
  42. package/src/Editor/Editor.tsx +4 -3
  43. package/src/Editor/EditorContext.spec.tsx +26 -0
  44. package/src/Editor/EditorContext.ts +19 -0
  45. package/src/EditorToolbar/FloatingToolbar.tsx +19 -18
  46. package/src/EditorToolbar/Tools/Link/Form/LinkForm.spec.tsx +37 -9
  47. package/src/EditorToolbar/Tools/Link/Form/LinkForm.tsx +96 -26
  48. package/src/EditorToolbar/Tools/Link/LinkButton.spec.tsx +103 -25
  49. package/src/EditorToolbar/Tools/Link/LinkButton.tsx +16 -19
  50. package/src/EditorToolbar/Tools/Link/LinkModal.tsx +13 -6
  51. package/src/EditorToolbar/Tools/Link/RemoveLinkButton.spec.tsx +26 -26
  52. package/src/EditorToolbar/Tools/Link/RemoveLinkButton.tsx +2 -10
  53. package/src/EditorToolbar/Tools/Undo/UndoButton.spec.tsx +22 -1
  54. package/src/Extensions/CommandsExtension/CommandsExtension.ts +54 -0
  55. package/src/Extensions/Extensions.ts +31 -19
  56. package/src/Extensions/LinkExtension/AssetLinkExtension.spec.ts +104 -0
  57. package/src/Extensions/LinkExtension/AssetLinkExtension.ts +128 -0
  58. package/src/Extensions/LinkExtension/LinkExtension.spec.ts +68 -0
  59. package/src/Extensions/LinkExtension/LinkExtension.ts +88 -82
  60. package/src/Extensions/LinkExtension/common.ts +10 -0
  61. package/src/hooks/index.ts +1 -0
  62. package/src/hooks/useExpandedSelection.ts +44 -0
  63. package/src/index.ts +3 -2
  64. package/src/types.ts +5 -0
  65. package/src/ui/Button/Button.tsx +2 -4
  66. package/src/ui/Fields/Input/Input.tsx +18 -4
  67. package/src/ui/Modal/Modal.tsx +2 -1
  68. package/src/ui/_forms.scss +14 -0
  69. package/src/utils/converters/mocks/squizNodeJson.mock.ts +177 -0
  70. package/src/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.spec.ts +41 -6
  71. package/src/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.ts +124 -113
  72. package/src/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.spec.ts +56 -34
  73. package/src/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.ts +107 -79
  74. package/src/utils/undefinedIfEmpty.spec.ts +12 -0
  75. package/src/utils/undefinedIfEmpty.ts +3 -0
  76. package/tailwind.config.cjs +3 -0
  77. package/tests/renderWithEditor.tsx +21 -12
  78. package/lib/FormattedTextEditor.d.ts +0 -2
  79. package/lib/FormattedTextEditor.js +0 -7
  80. package/lib/utils/converters/validNodeTypes.d.ts +0 -2
  81. package/lib/utils/converters/validNodeTypes.js +0 -21
  82. package/src/Editor/Editor.mock.tsx +0 -43
  83. package/src/FormattedTextEditor.spec.tsx +0 -10
  84. package/src/FormattedTextEditor.tsx +0 -3
  85. package/src/utils/converters/validNodeTypes.spec.ts +0 -33
  86. package/src/utils/converters/validNodeTypes.ts +0 -21
@@ -1,7 +1,12 @@
1
1
  import { FORMATTED_TEXT_MODELS as FormattedTextModels } from '@squiz/dx-json-schema-lib';
2
2
  import { RemirrorJSON } from '@remirror/core';
3
3
  import { squizNodeToRemirrorNode } from './squizNodeToRemirrorNode';
4
- import { mockSquizNodeJson, mockSquizNodeTextJson } from '../mocks/squizNodeJson.mock';
4
+ import {
5
+ mockSquizNodeJson,
6
+ mockSquizNodeTextJson,
7
+ sharedNodeExamples,
8
+ squizOnlyNodeExamples,
9
+ } from '../mocks/squizNodeJson.mock';
5
10
 
6
11
  type FormattedText = FormattedTextModels.v1.FormattedText;
7
12
 
@@ -84,19 +89,12 @@ describe('squizNodeToRemirrorNode', () => {
84
89
  expect(squizNodeToRemirrorNode(mockSquizNodeTextJson)).toEqual({
85
90
  content: [
86
91
  {
87
- attrs: { nodeIndent: null, nodeLineHeight: null, nodeTextAlignment: null, style: '' },
88
92
  type: 'paragraph',
89
93
  content: [
90
94
  {
91
95
  type: 'text',
92
96
  text: 'Hello world!',
93
97
  },
94
- ],
95
- },
96
- {
97
- attrs: { nodeIndent: null, nodeLineHeight: null, nodeTextAlignment: null, style: '' },
98
- type: 'paragraph',
99
- content: [
100
98
  {
101
99
  type: 'text',
102
100
  text: 'Another one...',
@@ -129,32 +127,40 @@ describe('squizNodeToRemirrorNode', () => {
129
127
  });
130
128
  });
131
129
 
132
- it('should throw an error for non supported node types', () => {
133
- const squizComponentJSON: FormattedText = [
134
- {
135
- children: [
136
- {
137
- type: 'text',
138
- value: 'Hello world!',
139
- },
140
- ],
141
- type: 'tag',
142
- tag: 'p',
143
- },
144
- // This should be filtered out, as we don't currently support <code> tags
145
- {
146
- children: [
147
- {
148
- type: 'text',
149
- value: 'Should be filtered out...',
150
- },
151
- ],
152
- type: 'tag',
153
- tag: 'code',
154
- },
155
- ];
156
-
157
- expect(() => squizNodeToRemirrorNode(squizComponentJSON)).toThrow(`Unsupported node type provided: code`);
130
+ it.each([
131
+ [
132
+ 'Unsupported DOM tag',
133
+ [
134
+ {
135
+ children: [
136
+ {
137
+ type: 'text',
138
+ value: 'Should throw an error.',
139
+ },
140
+ ],
141
+ type: 'tag',
142
+ tag: 'code',
143
+ },
144
+ ],
145
+ 'Unsupported node type provided: tag (tag: code)',
146
+ ],
147
+ [
148
+ 'Unsupported node type',
149
+ [
150
+ {
151
+ children: [
152
+ {
153
+ type: 'text',
154
+ value: 'Should throw an error.',
155
+ },
156
+ ],
157
+ type: 'unsupported-type',
158
+ },
159
+ ],
160
+ 'Unsupported node type provided: unsupported-type',
161
+ ],
162
+ ])('should throw an error for non supported node types', (description: string, node: any, expectedError: string) => {
163
+ expect(() => squizNodeToRemirrorNode(node)).toThrow(expectedError);
158
164
  });
159
165
 
160
166
  it('should handle pre formatted text', () => {
@@ -304,4 +310,20 @@ describe('squizNodeToRemirrorNode', () => {
304
310
  const result = squizNodeToRemirrorNode(squizComponentJSON);
305
311
  expect(result).toEqual(expected);
306
312
  });
313
+
314
+ it.each([...sharedNodeExamples, ...squizOnlyNodeExamples])(
315
+ 'should convert a Squiz node to the expected Remirror representation - $description',
316
+ async ({ remirrorNode, squizNode }: any) => {
317
+ const result = squizNodeToRemirrorNode(squizNode);
318
+ expect(result).toEqual({
319
+ type: 'doc',
320
+ content: [
321
+ {
322
+ type: 'paragraph',
323
+ content: [remirrorNode],
324
+ },
325
+ ],
326
+ });
327
+ },
328
+ );
307
329
  });
@@ -1,12 +1,18 @@
1
- import { RemirrorJSON, Literal, ObjectMark } from '@remirror/core';
1
+ import { RemirrorJSON, ObjectMark } from '@remirror/core';
2
+ import { Attrs } from 'prosemirror-model';
2
3
  import { FORMATTED_TEXT_MODELS as FormattedTextModels } from '@squiz/dx-json-schema-lib';
4
+ import { undefinedIfEmpty } from '../../undefinedIfEmpty';
3
5
 
4
6
  type FormattedText = FormattedTextModels.v1.FormattedText;
5
- type FormattedTextTag = FormattedTextModels.v1.FormattedTextTag;
6
7
  type FormattedNodes = FormattedTextModels.v1.FormattedNodes;
7
8
 
8
- const getNodeType = (node: FormattedTextTag): string => {
9
- const nodeTypeMap: Record<string, string> = {
9
+ const getNodeType = (node: FormattedNodes): string => {
10
+ const typeMap: Record<string, string> = {
11
+ 'link-to-matrix-asset': 'text',
12
+ text: 'text',
13
+ };
14
+
15
+ const tagMap: Record<string, string> = {
10
16
  h1: 'heading',
11
17
  h2: 'heading',
12
18
  h3: 'heading',
@@ -16,97 +22,112 @@ const getNodeType = (node: FormattedTextTag): string => {
16
22
  img: 'image',
17
23
  pre: 'preformatted',
18
24
  p: 'paragraph',
19
- text: 'paragraph',
25
+ a: 'text',
26
+ span: 'text',
20
27
  };
21
28
 
22
- const nodeType = nodeTypeMap[node.tag || node.type];
29
+ if (typeMap[node.type]) {
30
+ return typeMap[node.type];
31
+ }
23
32
 
24
- // Unsupported node type
25
- if (!nodeType) throw new Error(`Unsupported node type provided: ${node.tag}`);
33
+ if (node.type === 'tag' && tagMap[node.tag]) {
34
+ return tagMap[node.tag];
35
+ }
26
36
 
27
- return nodeType;
37
+ // Unsupported node type
38
+ throw new Error(
39
+ node.type === 'tag'
40
+ ? `Unsupported node type provided: ${node.type} (tag: ${node.tag})`
41
+ : `Unsupported node type provided: ${node.type}`,
42
+ );
28
43
  };
29
44
 
30
- const getNodeAttributes = (node: FormattedTextTag): Record<string, Literal> => {
31
- const { alignment } = node.formattingOptions || {};
32
- return {
33
- nodeIndent: null,
34
- nodeTextAlignment: alignment ?? null,
35
- nodeLineHeight: null,
36
- style: '',
37
- level: node.tag?.startsWith('h') ? parseInt(node.tag.substring(1)) : undefined,
38
- };
45
+ const getNodeAttributes = (node: FormattedNodes): Attrs => {
46
+ if (node.type === 'tag' && node.tag === 'img') {
47
+ return {
48
+ alt: node.attributes?.alt,
49
+ height: node.attributes?.height,
50
+ width: node.attributes?.width,
51
+ src: node.attributes?.src,
52
+ title: node.attributes?.title,
53
+ };
54
+ } else if (node.type === 'tag') {
55
+ return {
56
+ nodeIndent: null,
57
+ nodeTextAlignment: node.formattingOptions?.alignment || null,
58
+ nodeLineHeight: null,
59
+ style: '',
60
+ level: node.tag?.startsWith('h') ? parseInt(node.tag.substring(1)) : undefined,
61
+ };
62
+ }
63
+
64
+ return {};
39
65
  };
40
66
 
41
- const resolveChild = (child: FormattedNodes): RemirrorJSON => {
42
- if (child.type === 'text') {
43
- return { type: 'text', text: child.value };
67
+ const getNodeMarks = (node: FormattedNodes): ObjectMark[] => {
68
+ const marks: ObjectMark[] = [];
69
+
70
+ if (node.type === 'tag' && node.tag === 'a') {
71
+ marks.push({
72
+ type: 'link',
73
+ attrs: {
74
+ href: node.attributes?.href,
75
+ target: node.attributes?.target ?? null,
76
+ auto: false,
77
+ title: node.attributes?.title ?? null,
78
+ },
79
+ });
80
+ } else if (node.type === 'link-to-matrix-asset') {
81
+ marks.push({
82
+ type: 'assetLink',
83
+ attrs: {
84
+ matrixAssetId: node.matrixAssetId,
85
+ matrixDomain: node.matrixDomain,
86
+ matrixIdentifier: node.matrixIdentifier,
87
+ target: node.target,
88
+ },
89
+ });
44
90
  }
45
91
 
46
- let text = '';
47
- const marks: ObjectMark[] = [];
92
+ // Handle font formatting
93
+ if ('font' in node) {
94
+ node.font?.bold && marks.push({ type: 'bold' });
95
+ node.font?.italics && marks.push({ type: 'italic' });
96
+ node.font?.underline && marks.push({ type: 'underline' });
97
+ }
98
+
99
+ return marks;
100
+ };
48
101
 
49
- if (child.type === 'tag') {
50
- // Handle link type
51
- if (child.tag === 'a') {
52
- marks.push({
53
- type: 'link',
54
- attrs: {
55
- href: child.attributes?.href,
56
- target: child.attributes?.target ?? null,
57
- auto: false,
58
- title: child.attributes?.title ?? null,
59
- },
60
- });
61
- }
62
-
63
- // Handle image type
64
- if (child.tag === 'img') {
102
+ const unwrapNodeIfNeeded = (node: RemirrorJSON): RemirrorJSON[] => {
103
+ if (node.type === 'text' && node.content?.length) {
104
+ return node.content.map((child) => {
65
105
  return {
66
- type: 'image',
67
- attrs: {
68
- alt: child.attributes?.alt,
69
- height: child.attributes?.height,
70
- width: child.attributes?.width,
71
- src: child.attributes?.src,
72
- title: child.attributes?.title,
73
- },
106
+ ...child,
107
+ marks: [...(child.marks || []), ...(node.marks || [])],
74
108
  };
75
- }
76
-
77
- // Handle font formatting
78
- child.font?.bold && marks.push({ type: 'bold' });
79
- child.font?.italics && marks.push({ type: 'italic' });
80
- child.font?.underline && marks.push({ type: 'underline' });
81
-
82
- // For now all children types should be "text"
83
- text = child.children[0].type === 'text' ? child.children[0].value : '';
109
+ });
84
110
  }
85
111
 
86
- return { type: 'text', marks, text };
112
+ return [node];
87
113
  };
88
114
 
89
- const formatNode = (node: FormattedNodes): RemirrorJSON => {
90
- let content: RemirrorJSON[] | undefined;
91
-
92
- if (node.type === 'tag') {
93
- content = node.children.length ? node.children.map((child: FormattedNodes) => resolveChild(child)) : undefined;
94
- }
115
+ const formatNode = (node: FormattedNodes): RemirrorJSON[] => {
116
+ const children: RemirrorJSON[] = [];
95
117
 
96
- if (node.type === 'text') {
97
- content = [
98
- {
99
- type: 'text',
100
- text: node.value,
101
- },
102
- ];
118
+ if ('children' in node) {
119
+ node.children.forEach((child: FormattedNodes) => {
120
+ children.push(...formatNode(child));
121
+ });
103
122
  }
104
123
 
105
- return {
106
- type: getNodeType(node as FormattedTextTag),
107
- attrs: getNodeAttributes(node as FormattedTextTag),
108
- content,
109
- };
124
+ return unwrapNodeIfNeeded({
125
+ type: getNodeType(node),
126
+ attrs: undefinedIfEmpty(getNodeAttributes(node)),
127
+ marks: undefinedIfEmpty(getNodeMarks(node)),
128
+ text: node.type === 'text' ? node.value : undefined,
129
+ content: undefinedIfEmpty(children),
130
+ });
110
131
  };
111
132
 
112
133
  /**
@@ -116,8 +137,15 @@ const formatNode = (node: FormattedNodes): RemirrorJSON => {
116
137
  * @returns {RemirrorJSON} The converted Remirror JSON.
117
138
  */
118
139
  export const squizNodeToRemirrorNode = (nodes: FormattedText): RemirrorJSON => {
119
- return {
120
- type: 'doc',
121
- content: nodes.filter((node: FormattedNodes) => getNodeType(node as FormattedTextTag)).map(formatNode),
122
- };
140
+ let children: RemirrorJSON[] = [];
141
+
142
+ nodes.forEach((node) => {
143
+ children.push(...formatNode(node));
144
+ });
145
+
146
+ if (children.find((child) => child.type === 'text')) {
147
+ children = [{ type: 'paragraph', content: children }];
148
+ }
149
+
150
+ return { type: 'doc', content: children };
123
151
  };
@@ -0,0 +1,12 @@
1
+ import { undefinedIfEmpty } from './undefinedIfEmpty';
2
+
3
+ describe('undefinedIfEmpty', () => {
4
+ it.each([
5
+ ['empty object', {}, undefined],
6
+ ['non-empty object', { a: 'not empty' }, { a: 'not empty' }],
7
+ ['empty array', [], undefined],
8
+ ['non-empty array', ['not empty'], ['not empty']],
9
+ ])('Returns expected for %s', (description: string, object: object, expected: object | undefined) => {
10
+ expect(undefinedIfEmpty(object)).toEqual(expected);
11
+ });
12
+ });
@@ -0,0 +1,3 @@
1
+ export const undefinedIfEmpty = <T extends object>(object: T): T | undefined => {
2
+ return Object.keys(object).length > 0 ? object : undefined;
3
+ };
@@ -75,6 +75,9 @@ module.exports = {
75
75
  300: '#0774d2',
76
76
  400: '#044985',
77
77
  },
78
+ red: {
79
+ 300: '#d72321',
80
+ },
78
81
  },
79
82
  },
80
83
  },
@@ -1,17 +1,22 @@
1
- import React, { ReactElement, useEffect } from 'react';
1
+ import React, { ReactElement, useContext, useEffect } from 'react';
2
2
  import { render, RenderOptions } from '@testing-library/react';
3
3
  import { Extension, RemirrorContentType, RemirrorManager } from '@remirror/core';
4
4
  import { CorePreset } from '@remirror/preset-core';
5
5
  import { BuiltinPreset } from 'remirror';
6
6
  import { EditorComponent, Remirror, useRemirror } from '@remirror/react';
7
- import { Extensions } from '../src/Extensions/Extensions';
8
7
  import { RemirrorTestChain } from 'jest-remirror';
8
+ import merge from 'deepmerge';
9
+ import { createExtensions } from '../src/Extensions/Extensions';
10
+ import { EditorContext } from '../src/Editor/EditorContext';
9
11
  import { FloatingToolbar } from '../src/EditorToolbar/FloatingToolbar';
12
+ import { defaultEditorContext, EditorContextOptions } from '../src/Editor/EditorContext';
13
+ import { DeepPartial } from '../src/types';
10
14
 
11
15
  export type EditorRenderOptions = RenderOptions & {
12
16
  content?: RemirrorContentType;
13
17
  editable?: boolean;
14
18
  extensions?: Extension[];
19
+ context?: DeepPartial<EditorContextOptions>;
15
20
  };
16
21
 
17
22
  type TestEditorProps = EditorRenderOptions & {
@@ -30,8 +35,9 @@ type EditorRenderResult = {
30
35
  };
31
36
 
32
37
  const TestEditor = ({ children, extensions, content, onReady, editable }: TestEditorProps) => {
38
+ const context = useContext(EditorContext);
33
39
  const { manager, state, setState } = useRemirror({
34
- extensions: () => extensions || Extensions(),
40
+ extensions: () => extensions || createExtensions(context)(),
35
41
  content: content,
36
42
  selection: 'start',
37
43
  stringHandler: 'html',
@@ -83,6 +89,7 @@ export const renderWithEditor = async (
83
89
  ui: ReactElement | null,
84
90
  options?: EditorRenderOptions,
85
91
  ): Promise<EditorRenderResult> => {
92
+ const context = merge(defaultEditorContext, options?.context || {}) as EditorContextOptions;
86
93
  const result: Partial<EditorRenderResult> = {
87
94
  getHtmlContent: () => document.querySelector('.remirror-editor')?.innerHTML,
88
95
  getJsonContent: () => result.editor?.state.doc.content.child(0).toJSON(),
@@ -91,15 +98,17 @@ export const renderWithEditor = async (
91
98
  let isReady = false;
92
99
 
93
100
  const { container } = render(
94
- <TestEditor
95
- onReady={(manager) => {
96
- result.editor = RemirrorTestChain.create(manager);
97
- isReady = true;
98
- }}
99
- {...options}
100
- >
101
- {ui}
102
- </TestEditor>,
101
+ <EditorContext.Provider value={context}>
102
+ <TestEditor
103
+ onReady={(manager) => {
104
+ result.editor = RemirrorTestChain.create(manager);
105
+ isReady = true;
106
+ }}
107
+ {...options}
108
+ >
109
+ {ui}
110
+ </TestEditor>
111
+ </EditorContext.Provider>,
103
112
  );
104
113
 
105
114
  if (!isReady) {
@@ -1,2 +0,0 @@
1
- import Editor from './Editor/Editor';
2
- export default Editor;
@@ -1,7 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const Editor_1 = __importDefault(require("./Editor/Editor"));
7
- exports.default = Editor_1.default;
@@ -1,2 +0,0 @@
1
- import { ProsemirrorNode } from 'remirror';
2
- export declare const validRemirrorNode: (node: ProsemirrorNode) => boolean;
@@ -1,21 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validRemirrorNode = void 0;
4
- const Extensions_1 = require("../../Extensions/Extensions");
5
- const validRemirrorNode = (node) => {
6
- if (!node)
7
- return false;
8
- const nodeType = node.type.name;
9
- const nodeMarks = node.marks;
10
- // This is pulling in the currently supported extensions, this works for now...
11
- // Could also just hard code these in as we go, but this should make it easier as we add more extensions
12
- const supportedNodes = [...(0, Extensions_1.Extensions)().map((extension) => extension.name), 'doc', 'text'];
13
- if (!supportedNodes.includes(nodeType))
14
- return false;
15
- for (let i = 0; i < nodeMarks.length; i++) {
16
- if (!supportedNodes.includes(nodeMarks[i].type.name))
17
- return false;
18
- }
19
- return true;
20
- };
21
- exports.validRemirrorNode = validRemirrorNode;
@@ -1,43 +0,0 @@
1
- import { Remirror, useRemirror, useRemirrorContext } from '@remirror/react';
2
- import React from 'react';
3
- import { Toolbar, FloatingToolbar } from '../EditorToolbar';
4
- import { Extensions } from '../Extensions/Extensions';
5
-
6
- type MockEditorProps = {
7
- setContent?: any;
8
- };
9
-
10
- /**
11
- * @deprecated Use "renderWithEditor" and render the specific component being tested instead.
12
- */
13
- export const MockEditor = ({ setContent }: MockEditorProps) => {
14
- const { manager, state, setState } = useRemirror({
15
- extensions: Extensions,
16
- selection: 'start',
17
- stringHandler: 'html',
18
- });
19
-
20
- const Component = () => {
21
- setContent && setContent.mockImplementation(useRemirrorContext().setContent);
22
- return null;
23
- };
24
-
25
- const handleChange = (parameter: { state: any }) => {
26
- setState(parameter.state);
27
- };
28
-
29
- return (
30
- <Remirror
31
- manager={manager}
32
- onChange={handleChange}
33
- placeholder="Write something"
34
- label="Text editor"
35
- state={state}
36
- autoRender="start"
37
- >
38
- <Toolbar />
39
- <Component />
40
- <FloatingToolbar />
41
- </Remirror>
42
- );
43
- };
@@ -1,10 +0,0 @@
1
- import { render } from '@testing-library/react';
2
- import { FormattedTextEditor } from './';
3
- import React from 'react';
4
-
5
- describe('<FormattedTextEditor />', () => {
6
- it('should render "<FormattedTextEditor />" component', () => {
7
- const { baseElement } = render(<FormattedTextEditor />);
8
- expect(baseElement).toBeTruthy();
9
- });
10
- });
@@ -1,3 +0,0 @@
1
- import Editor from './Editor/Editor';
2
-
3
- export default Editor;
@@ -1,33 +0,0 @@
1
- import { validRemirrorNode } from './validNodeTypes';
2
-
3
- describe('validRemirrorNode', () => {
4
- it('returns false for null input', () => {
5
- expect(validRemirrorNode(null as any)).toBe(false);
6
- });
7
-
8
- it('returns false for unsupported node type', () => {
9
- const node = { type: { name: 'unsupported' }, marks: [] };
10
- expect(validRemirrorNode(node as any)).toBe(false);
11
- });
12
-
13
- it('returns false for unsupported mark type', () => {
14
- const node = {
15
- type: { name: 'doc' },
16
- marks: [{ type: { name: 'unsupported' } }],
17
- };
18
- expect(validRemirrorNode(node as any)).toBe(false);
19
- });
20
-
21
- it('returns true for supported node type with no marks', () => {
22
- const node = { type: { name: 'doc' }, marks: [] };
23
- expect(validRemirrorNode(node as any)).toBe(true);
24
- });
25
-
26
- it('returns true for supported node type with supported mark type', () => {
27
- const node = {
28
- type: { name: 'doc' },
29
- marks: [{ type: { name: 'bold' } }],
30
- };
31
- expect(validRemirrorNode(node as any)).toBe(true);
32
- });
33
- });
@@ -1,21 +0,0 @@
1
- import { ProsemirrorNode } from 'remirror';
2
- import { Extensions } from '../../Extensions/Extensions';
3
-
4
- export const validRemirrorNode = (node: ProsemirrorNode): boolean => {
5
- if (!node) return false;
6
-
7
- const nodeType = node.type.name;
8
- const nodeMarks = node.marks;
9
-
10
- // This is pulling in the currently supported extensions, this works for now...
11
- // Could also just hard code these in as we go, but this should make it easier as we add more extensions
12
- const supportedNodes: Array<string> = [...Extensions().map((extension: any) => extension.name), 'doc', 'text'];
13
-
14
- if (!supportedNodes.includes(nodeType)) return false;
15
-
16
- for (let i = 0; i < nodeMarks.length; i++) {
17
- if (!supportedNodes.includes(nodeMarks[i].type.name)) return false;
18
- }
19
-
20
- return true;
21
- };