@squiz/formatted-text-editor 1.69.0 → 1.71.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.
@@ -8,6 +8,7 @@ import { EditorContext } from './EditorContext';
8
8
  import { createExtensions } from '../Extensions/Extensions';
9
9
  import useFocus from '../hooks/useFocus';
10
10
  import { ResourceBrowserContext } from '@squiz/resource-browser';
11
+ import { TableComponents } from '@remirror/extension-react-tables';
11
12
 
12
13
  type EditorProps = {
13
14
  className?: string;
@@ -19,6 +20,7 @@ type EditorProps = {
19
20
  isFocused?: boolean;
20
21
  label?: string;
21
22
  attributes?: Record<string, string>;
23
+ enableTableTool?: boolean;
22
24
  };
23
25
 
24
26
  const WrappedEditor = () => {
@@ -51,6 +53,7 @@ const Editor = ({
51
53
  children,
52
54
  isFocused,
53
55
  attributes,
56
+ enableTableTool = false,
54
57
  }: EditorProps) => {
55
58
  const { manager, state, setState } = useRemirror({
56
59
  extensions: createExtensions(useContext(EditorContext), useContext(ResourceBrowserContext)),
@@ -71,6 +74,13 @@ const Editor = ({
71
74
  if (isFocused) {
72
75
  manager.view.dom.focus();
73
76
  }
77
+
78
+ // TODO: May want to come back to this and see if there's a better solution
79
+ // We have to add a type button attribute to the delete buttons so they don't cause a submit by accident.
80
+ const tableDeleteButtons = document.querySelectorAll('.remirror-table-delete-inner-button');
81
+ tableDeleteButtons.forEach((button) => {
82
+ button.setAttribute('type', 'button');
83
+ });
74
84
  }, []);
75
85
 
76
86
  return (
@@ -88,16 +98,17 @@ const Editor = ({
88
98
  >
89
99
  <Remirror
90
100
  manager={manager}
91
- state={state}
101
+ initialContent={state}
92
102
  editable={editable}
93
103
  onChange={handleChange}
94
104
  placeholder="Write something"
95
105
  label="Text editor"
96
106
  attributes={attributes}
97
107
  >
98
- {editable && <Toolbar isVisible={isVisible} />}
108
+ {editable && <Toolbar isVisible={isVisible} enableTableTool={enableTableTool} />}
99
109
  {children && <div className="squiz-fte-scope__editor__children">{children}</div>}
100
110
  <WrappedEditor />
111
+ {enableTableTool && <TableComponents enableTableCellMenu={false} />}
101
112
  {editable && isVisible && <FloatingToolbar />}
102
113
  </Remirror>
103
114
  </div>
@@ -3,6 +3,10 @@
3
3
  font-family: 'Open Sans' !important;
4
4
  @apply bg-white rounded border-gray-300;
5
5
 
6
+ .squiz-fte-scope__floating-popover {
7
+ z-index: 999; // ensure table styles don't hide this menu
8
+ }
9
+
6
10
  &:has(&__children) {
7
11
  /* The children replace the space taken up by top padding of the editor when present. */
8
12
  @apply w-full min-h-[2rem];
@@ -27,6 +31,10 @@
27
31
  /* Make sure content aligned with "text-align: justify" is justified */
28
32
  @apply block;
29
33
  }
34
+
35
+ &-wrapper {
36
+ position: relative;
37
+ }
30
38
  }
31
39
 
32
40
  &--bordered {
@@ -62,4 +70,361 @@
62
70
  &:has(.show-toolbar) {
63
71
  @apply shadow-md border-0;
64
72
  }
73
+
74
+ // Tables
75
+ .remirror-table {
76
+ &-container {
77
+ @apply m-8;
78
+ }
79
+
80
+ width: 100%;
81
+
82
+ tbody {
83
+ th,
84
+ td {
85
+ @apply p-2;
86
+ }
87
+
88
+ p {
89
+ margin: 0; // everything is by default a paragraph, inside the table that does not make sense so remove the margin
90
+ }
91
+ }
92
+ }
93
+ }
94
+
95
+ // TODO: work through this nonsense and see which bits are necessary for functionality
96
+ :root {
97
+ --rmr-color-table-default-border: #e0e0e0;
98
+ --rmr-color-table-selected-cell: transparent;
99
+ --rmr-color-table-selected-border: #0774d2;
100
+ --rmr-color-table-selected-controller: #0774d2;
101
+ --rmr-hue-blue-7: #0774d2;
102
+ --rmr-color-table-mark: #f5f5f5;
103
+ --rmr-color-table-default-controller: #f7f7f7;
104
+ --rmr-color-table-predelete-cell: transparent;
105
+ --rmr-color-table-predelete-border: #d72321;
106
+ --rmr-color-table-predelete-controller: #d72321;
107
+ }
108
+
109
+ //remirror styles
110
+ .remirror-positioner {
111
+ cursor: none;
112
+ min-height: 1px;
113
+ min-width: 1px;
114
+ pointer-events: none;
115
+ position: absolute;
116
+ -webkit-user-select: none;
117
+ -moz-user-select: none;
118
+ -ms-user-select: none;
119
+ user-select: none;
120
+ z-index: -1;
121
+ }
122
+
123
+ .remirror-positioner-widget {
124
+ height: 0;
125
+ position: absolute;
126
+ width: 0;
127
+ }
128
+
129
+ .remirror-editor.ProseMirror .tableWrapper {
130
+ overflow-x: auto;
131
+ }
132
+
133
+ .remirror-editor.ProseMirror table {
134
+ border-collapse: collapse;
135
+ overflow: hidden;
136
+ table-layout: fixed;
137
+ width: 100%;
138
+ }
139
+
140
+ .remirror-editor.ProseMirror td,
141
+ .remirror-editor.ProseMirror th {
142
+ border-color: var(--rmr-color-table-default-border);
143
+ border-style: solid;
144
+ border-width: 1px;
145
+ box-sizing: border-box;
146
+ position: relative;
147
+ vertical-align: top;
148
+ }
149
+
150
+ .remirror-editor.ProseMirror .column-resize-handle {
151
+ background-color: var(--rmr-hue-blue-7);
152
+ bottom: 0;
153
+ pointer-events: none;
154
+ position: absolute;
155
+ right: -2px;
156
+ top: 0;
157
+ width: 4px;
158
+ z-index: 40;
159
+ }
160
+
161
+ .remirror-editor.ProseMirror.resize-cursor {
162
+ cursor: ew-resize;
163
+ cursor: col-resize;
164
+ }
165
+
166
+ .remirror-editor.ProseMirror td.selectedCell,
167
+ .remirror-editor.ProseMirror th.selectedCell {
168
+ background-color: var(--rmr-color-table-selected-cell);
169
+ border-color: var(--rmr-color-table-selected-border);
170
+ border-style: double;
171
+ }
172
+
173
+ .remirror-table-colgroup > col:first-of-type {
174
+ overflow: visible;
175
+ width: 13px;
176
+ }
177
+
178
+ .remirror-controllers-toggle {
179
+ visibility: hidden;
180
+ }
181
+
182
+ .remirror-table-show-controllers .remirror-controllers-toggle {
183
+ visibility: visible;
184
+ }
185
+
186
+ .remirror-table-insert-button {
187
+ background-color: #dcdcdc;
188
+ border-radius: 4px;
189
+ cursor: pointer;
190
+ height: 18px;
191
+ position: absolute;
192
+ transition: background-color 0.15s ease;
193
+ width: 18px;
194
+ z-index: 25;
195
+ }
196
+
197
+ .remirror-table-insert-button svg {
198
+ fill: #fff;
199
+ }
200
+
201
+ .remirror-table-insert-button:hover {
202
+ background-color: #136bda;
203
+ }
204
+
205
+ .remirror-table-insert-button:hover svg {
206
+ fill: #fff;
207
+ }
208
+
209
+ .remirror-table-delete-inner-button {
210
+ background-color: #cecece;
211
+ border: none;
212
+ border-radius: 4px;
213
+ cursor: pointer;
214
+ height: 18px;
215
+ padding: 0;
216
+ position: absolute;
217
+ transition: background-color 0.15s ease;
218
+ width: 18px;
219
+ z-index: 30;
220
+ }
221
+
222
+ .remirror-table-delete-inner-button:hover {
223
+ background-color: #ff7884;
224
+ }
225
+
226
+ .remirror-table-delete-table-inner-button {
227
+ left: calc(var(--remirror-table-delete-button-x) - 9px);
228
+ top: calc(var(--remirror-table-delete-button-y) - 9px);
229
+ }
230
+
231
+ .remirror-table-delete-row-column-inner-button {
232
+ left: calc(var(--remirror-table-delete-row-column-button-x) - 9px);
233
+ top: calc(var(--remirror-table-delete-row-column-button-y) - 9px);
234
+ }
235
+
236
+ .remirror-table-with-controllers {
237
+ height: 1px;
238
+ margin-bottom: 40px;
239
+ margin-top: 40px;
240
+ }
241
+
242
+ .ProseMirror table.remirror-table-with-controllers {
243
+ overflow: visible;
244
+ }
245
+
246
+ .remirror-table-waitting-controllers {
247
+ display: none;
248
+ }
249
+
250
+ .remirror-table-tbody-with-controllers > tr:first-of-type {
251
+ height: 12px;
252
+ overflow: visible;
253
+ }
254
+
255
+ .remirror-table-tbody-with-controllers > tr:first-of-type th:first-of-type {
256
+ cursor: pointer;
257
+ height: 12px;
258
+ overflow: visible;
259
+ padding: 0;
260
+ position: relative;
261
+ width: 12px;
262
+ z-index: 15;
263
+ }
264
+
265
+ .remirror-table-tbody-with-controllers > tr:first-of-type th:first-of-type div.remirror-table-controller-wrapper {
266
+ align-items: flex-end;
267
+ display: flex;
268
+ height: 12px;
269
+ justify-content: flex-end;
270
+ overflow: visible;
271
+ width: 12px;
272
+ }
273
+
274
+ .remirror-table-tbody-with-controllers > tr:first-of-type th:first-of-type div.remirror-table-controller-trigger-area {
275
+ display: none;
276
+ flex: 1;
277
+ position: relative;
278
+ z-index: 10;
279
+ }
280
+
281
+ .remirror-table-tbody-with-controllers
282
+ > tr:first-of-type
283
+ th:first-of-type
284
+ div.remirror-table-controller-mark-row-corner {
285
+ border-color: var(--rmr-color-table-mark);
286
+ border-radius: 50%;
287
+ border-style: solid;
288
+ border-width: 2px;
289
+ bottom: -2px;
290
+ height: 0;
291
+ left: -12px;
292
+ position: absolute;
293
+ width: 0;
294
+ }
295
+
296
+ .remirror-table-tbody-with-controllers
297
+ > tr:first-of-type
298
+ th:first-of-type
299
+ div.remirror-table-controller-mark-column-corner {
300
+ border-color: var(--rmr-color-table-mark);
301
+ border-radius: 50%;
302
+ border-style: solid;
303
+ border-width: 2px;
304
+ height: 0;
305
+ position: absolute;
306
+ right: -2px;
307
+ top: -12px;
308
+ width: 0;
309
+ }
310
+
311
+ .remirror-table-tbody-with-controllers > tr:first-of-type th:nth-of-type(n + 2) {
312
+ cursor: pointer;
313
+ height: 12px;
314
+ overflow: visible;
315
+ padding: 0;
316
+ position: relative;
317
+ z-index: 15;
318
+ }
319
+
320
+ .remirror-table-tbody-with-controllers > tr:first-of-type th:nth-of-type(n + 2) div.remirror-table-controller-wrapper {
321
+ align-items: flex-end;
322
+ display: flex;
323
+ flex-direction: row;
324
+ height: 12px;
325
+ justify-content: flex-end;
326
+ overflow: visible;
327
+ width: 100%;
328
+ }
329
+
330
+ .remirror-table-tbody-with-controllers
331
+ > tr:first-of-type
332
+ th:nth-of-type(n + 2)
333
+ div.remirror-table-controller-trigger-area {
334
+ flex: 1;
335
+ height: 36px;
336
+ position: relative;
337
+ z-index: 10;
338
+ }
339
+
340
+ .remirror-table-tbody-with-controllers
341
+ > tr:first-of-type
342
+ th:nth-of-type(n + 2)
343
+ div.remirror-table-controller-mark-row-corner {
344
+ display: none;
345
+ }
346
+
347
+ .remirror-table-tbody-with-controllers
348
+ > tr:first-of-type
349
+ th:nth-of-type(n + 2)
350
+ div.remirror-table-controller-mark-column-corner {
351
+ border-color: var(--rmr-color-table-mark);
352
+ border-radius: 50%;
353
+ border-style: solid;
354
+ border-width: 2px;
355
+ height: 0;
356
+ position: absolute;
357
+ right: -2px;
358
+ top: -12px;
359
+ width: 0;
360
+ }
361
+
362
+ .remirror-table-tbody-with-controllers > tr:nth-of-type(n + 2) th {
363
+ cursor: pointer;
364
+ overflow: visible;
365
+ padding: 0;
366
+ position: relative;
367
+ width: 12px;
368
+ z-index: 15;
369
+ }
370
+
371
+ .remirror-table-tbody-with-controllers > tr:nth-of-type(n + 2) th div.remirror-table-controller-wrapper {
372
+ align-items: flex-end;
373
+ display: flex;
374
+ flex-direction: column;
375
+ height: 100%;
376
+ justify-content: flex-end;
377
+ overflow: visible;
378
+ width: 12px;
379
+ }
380
+
381
+ .remirror-table-tbody-with-controllers > tr:nth-of-type(n + 2) th div.remirror-table-controller-trigger-area {
382
+ flex: 1;
383
+ position: relative;
384
+ width: 36px;
385
+ z-index: 10;
386
+ }
387
+
388
+ .remirror-table-tbody-with-controllers > tr:nth-of-type(n + 2) th div.remirror-table-controller-mark-row-corner {
389
+ border-color: var(--rmr-color-table-mark);
390
+ border-radius: 50%;
391
+ border-style: solid;
392
+ border-width: 2px;
393
+ bottom: -2px;
394
+ height: 0;
395
+ left: -12px;
396
+ position: absolute;
397
+ width: 0;
398
+ }
399
+
400
+ .remirror-table-tbody-with-controllers > tr:nth-of-type(n + 2) th div.remirror-table-controller-mark-column-corner {
401
+ display: none;
402
+ }
403
+
404
+ .remirror-table-tbody-with-controllers th.remirror-table-controller {
405
+ background-color: var(--rmr-color-table-default-controller);
406
+ }
407
+
408
+ .remirror-table-tbody-with-controllers th.selectedCell.remirror-table-controller {
409
+ background-color: var(--rmr-color-table-selected-controller);
410
+ }
411
+
412
+ .remirror-table-show-predelete td.selectedCell,
413
+ .remirror-table-show-predelete th.selectedCell.remirror-table-controller {
414
+ background-color: var(--rmr-color-table-predelete-cell) !important;
415
+ border-color: var(--rmr-color-table-predelete-border) !important;
416
+ }
417
+
418
+ .remirror-table-show-predelete th.selectedCell.remirror-table-controller {
419
+ background-color: var(--rmr-color-table-predelete-controller) !important;
420
+ }
421
+
422
+ .remirror-table-show-predelete.remirror-table-preselect-all td,
423
+ .remirror-table-show-predelete.remirror-table-preselect-all th.remirror-table-controller {
424
+ background-color: var(--rmr-color-table-predelete-cell) !important;
425
+ border-color: var(--rmr-color-table-predelete-border) !important;
426
+ }
427
+
428
+ .remirror-table-show-predelete.remirror-table-preselect-all th.remirror-table-controller {
429
+ background-color: var(--rmr-color-table-predelete-controller) !important;
65
430
  }
@@ -14,12 +14,14 @@ import RemoveLinkButton from './Tools/Link/RemoveLinkButton';
14
14
  import ClearFormattingButton from './Tools/ClearFormatting/ClearFormattingButton';
15
15
  import ListButtons from './Tools/Lists/ListButtons';
16
16
  import HorizontalLineButton from './Tools/HorizontalLine/HorizontalLineButton';
17
+ import TableButton from './Tools/Table/TableButton';
17
18
  import { useExtensionNames } from '../hooks';
18
19
 
19
20
  type ToolbarProps = {
20
21
  isVisible: boolean;
22
+ enableTableTool: boolean;
21
23
  };
22
- export const Toolbar = ({ isVisible }: ToolbarProps) => {
24
+ export const Toolbar = ({ isVisible, enableTableTool }: ToolbarProps) => {
23
25
  const extensionNames = useExtensionNames();
24
26
 
25
27
  return (
@@ -51,6 +53,7 @@ export const Toolbar = ({ isVisible }: ToolbarProps) => {
51
53
  )}
52
54
  {extensionNames.image && <ImageButton />}
53
55
  {extensionNames.clearFormatting && <ClearFormattingButton />}
56
+ {enableTableTool && extensionNames.table && <TableButton />}
54
57
  </div>
55
58
  </RemirrorToolbar>
56
59
  );
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import '@testing-library/jest-dom';
3
+ import { screen, fireEvent } from '@testing-library/react';
4
+ import { renderWithEditor } from '../../../../tests';
5
+ import TableButton from './TableButton';
6
+
7
+ const defaultTableMarkup = `<div class="remirror-table-show-controllers"><table class="remirror-table remirror-table-with-controllers" data-controllers-injected="" style="min-width: 40px;"><colgroup class="remirror-table-colgroup"><col><col><col><col></colgroup><tbody class="remirror-table-tbody-with-controllers"><tr><th contenteditable="false" class="remirror-table-controller remirror-controllers-toggle selectedCell" data-controller-cell=""><div contenteditable="false" class="remirror-table-controller-wrapper"><div contenteditable="false"></div><div class="remirror-table-controller-trigger-area"></div><div class="remirror-table-controller-trigger-area"></div><div class="remirror-table-controller-mark-row-corner"></div><div class="remirror-table-controller-mark-column-corner"></div></div></th><th contenteditable="false" class="remirror-table-controller remirror-controllers-toggle" data-controller-cell=""><div contenteditable="false" class="remirror-table-controller-wrapper"><div contenteditable="false"></div><div class="remirror-table-controller-trigger-area"></div><div class="remirror-table-controller-trigger-area"></div><div class="remirror-table-controller-mark-row-corner"></div><div class="remirror-table-controller-mark-column-corner"></div></div></th><th contenteditable="false" class="remirror-table-controller remirror-controllers-toggle" data-controller-cell=""><div contenteditable="false" class="remirror-table-controller-wrapper"><div contenteditable="false"></div><div class="remirror-table-controller-trigger-area"></div><div class="remirror-table-controller-trigger-area"></div><div class="remirror-table-controller-mark-row-corner"></div><div class="remirror-table-controller-mark-column-corner"></div></div></th><th contenteditable="false" class="remirror-table-controller remirror-controllers-toggle" data-controller-cell=""><div contenteditable="false" class="remirror-table-controller-wrapper"><div contenteditable="false"></div><div class="remirror-table-controller-trigger-area"></div><div class="remirror-table-controller-trigger-area"></div><div class="remirror-table-controller-mark-row-corner"></div><div class="remirror-table-controller-mark-column-corner"></div></div></th></tr><tr><th contenteditable="false" class="remirror-table-controller remirror-controllers-toggle" data-controller-cell=""><div contenteditable="false" class="remirror-table-controller-wrapper"><div contenteditable="false"></div><div class="remirror-table-controller-trigger-area"></div><div class="remirror-table-controller-trigger-area"></div><div class="remirror-table-controller-mark-row-corner"></div><div class="remirror-table-controller-mark-column-corner"></div></div></th><td><p style=""><br class="ProseMirror-trailingBreak"></p></td><td><p style=""><br class="ProseMirror-trailingBreak"></p></td><td><p style=""><br class="ProseMirror-trailingBreak"></p></td></tr><tr><th contenteditable="false" class="remirror-table-controller remirror-controllers-toggle" data-controller-cell=""><div contenteditable="false" class="remirror-table-controller-wrapper"><div contenteditable="false"></div><div class="remirror-table-controller-trigger-area"></div><div class="remirror-table-controller-trigger-area"></div><div class="remirror-table-controller-mark-row-corner"></div><div class="remirror-table-controller-mark-column-corner"></div></div></th><td><p style=""><br class="ProseMirror-trailingBreak"></p></td><td><p style=""><br class="ProseMirror-trailingBreak"></p></td><td><p style=""><br class="ProseMirror-trailingBreak"></p></td></tr><tr><th contenteditable="false" class="remirror-table-controller remirror-controllers-toggle" data-controller-cell=""><div contenteditable="false" class="remirror-table-controller-wrapper"><div contenteditable="false"></div><div class="remirror-table-controller-trigger-area"></div><div class="remirror-table-controller-trigger-area"></div><div class="remirror-table-controller-mark-row-corner"></div><div class="remirror-table-controller-mark-column-corner"></div></div></th><td><p style=""><br class="ProseMirror-trailingBreak"></p></td><td><p style=""><br class="ProseMirror-trailingBreak"></p></td><td><p style=""><br class="ProseMirror-trailingBreak"></p></td></tr><tr><th contenteditable="false" class="remirror-table-controller remirror-controllers-toggle" data-controller-cell=""><div contenteditable="false" class="remirror-table-controller-wrapper"><div contenteditable="false"></div><div class="remirror-table-controller-trigger-area"></div><div class="remirror-table-controller-trigger-area"></div><div class="remirror-table-controller-mark-row-corner"></div><div class="remirror-table-controller-mark-column-corner"></div></div></th><td><p style=""><br class="ProseMirror-trailingBreak"></p></td><td><p style=""><br class="ProseMirror-trailingBreak"></p></td><td><p style=""><br class="ProseMirror-trailingBreak"></p></td></tr></tbody></table><div></div></div>`;
8
+
9
+ describe('Table button', () => {
10
+ it('Renders the table button', async () => {
11
+ await renderWithEditor(<TableButton />, { content: 'Some nonsense content here' });
12
+ expect(screen.getByRole('button', { name: 'Insert table' })).toBeInTheDocument();
13
+ });
14
+
15
+ it('Inserts a table into the editor content after clicking button', async () => {
16
+ const { getHtmlContent } = await renderWithEditor(<TableButton />, {
17
+ content: '<p>Hello Mr Goat</p>',
18
+ });
19
+
20
+ const horizontalLine = screen.getByRole('button', { name: 'Insert table' });
21
+ fireEvent.click(horizontalLine);
22
+
23
+ expect(getHtmlContent()).toBe(defaultTableMarkup + '<p style="">Hello Mr Goat</p>');
24
+ });
25
+ });
@@ -0,0 +1,32 @@
1
+ import React from 'react';
2
+ import { useCommands, useActive } from '@remirror/react';
3
+ import { VerticalDivider } from '@remirror/react-components';
4
+ import { TableExtension } from '@remirror/extension-react-tables';
5
+ import Button from '../../../ui/Button/Button';
6
+ import TableViewRoundedIcon from '@mui/icons-material/TableViewRounded';
7
+
8
+ const TableButton = () => {
9
+ const { createTable } = useCommands();
10
+
11
+ const active = useActive<TableExtension>();
12
+ const enabled = createTable.enabled();
13
+
14
+ const handleSelect = () => {
15
+ createTable({ rowsCount: 4, columnsCount: 3, withHeaderRow: false });
16
+ };
17
+
18
+ return (
19
+ <>
20
+ <Button
21
+ handleOnClick={handleSelect}
22
+ isDisabled={!enabled}
23
+ isActive={active.table()}
24
+ icon={<TableViewRoundedIcon />}
25
+ label="Insert table"
26
+ />
27
+ <VerticalDivider />
28
+ </>
29
+ );
30
+ };
31
+
32
+ export default TableButton;
@@ -28,11 +28,16 @@ import { ClearFormattingExtension } from './ClearFormattingExtension/ClearFormat
28
28
  import { UnsupportedNodeExtension } from './UnsuportedExtension/UnsupportedNodeExtension';
29
29
  import { ResourceBrowserContextProps } from '@squiz/resource-browser';
30
30
  import { FetchUrlExtension } from './FetchUrlExtension/FetchUrlExtension';
31
+ import { TableExtension } from '@remirror/extension-react-tables';
32
+ import { ReactComponentExtension } from '@remirror/extension-react-component';
33
+
31
34
  export enum NodeName {
32
35
  Image = 'image',
33
36
  CodeBlock = 'codeBlock',
34
37
  AssetImage = 'assetImage',
35
38
  Text = 'text',
39
+ TableControllerCell = 'tableControllerCell',
40
+ tableCell = 'tableCell',
36
41
  hardBreak = 'hardBreak',
37
42
  Unsupported = 'unsupportedNode',
38
43
  }
@@ -77,6 +82,8 @@ export const createExtensions = (context: EditorContextOptions, browserContext:
77
82
  fetchUrl: browserContext.onRequestResource,
78
83
  }),
79
84
  new TextExtension(),
85
+ new TableExtension(),
86
+ new ReactComponentExtension(),
80
87
  ];
81
88
  };
82
89
  };