@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.
- package/CHANGELOG.md +12 -0
- package/demo/App.tsx +15 -0
- package/lib/Editor/Editor.d.ts +2 -1
- package/lib/Editor/Editor.js +11 -3
- package/lib/EditorToolbar/Toolbar.d.ts +2 -1
- package/lib/EditorToolbar/Toolbar.js +4 -2
- package/lib/EditorToolbar/Tools/Table/TableButton.d.ts +3 -0
- package/lib/EditorToolbar/Tools/Table/TableButton.js +22 -0
- package/lib/Extensions/Extensions.d.ts +2 -0
- package/lib/Extensions/Extensions.js +6 -0
- package/lib/index.css +296 -0
- package/lib/utils/converters/remirrorNodeToSquizNode/remirrorNodeToSquizNode.js +19 -4
- package/lib/utils/converters/squizNodeToRemirrorNode/squizNodeToRemirrorNode.js +23 -0
- package/package.json +2 -1
- package/src/Editor/Editor.tsx +13 -2
- package/src/Editor/_editor.scss +365 -0
- package/src/EditorToolbar/Toolbar.tsx +4 -1
- package/src/EditorToolbar/Tools/Table/TableButton.spec.tsx +25 -0
- package/src/EditorToolbar/Tools/Table/TableButton.tsx +32 -0
- package/src/Extensions/Extensions.ts +7 -0
- 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/src/utils/getNodeNamesByGroup.spec.ts +5 -0
package/src/Editor/Editor.tsx
CHANGED
@@ -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
|
-
|
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>
|
package/src/Editor/_editor.scss
CHANGED
@@ -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
|
};
|