@plone/volto-slate 18.0.0-alpha.4

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 (183) hide show
  1. package/.eslintrc.js +6 -0
  2. package/.release-it.json +25 -0
  3. package/CHANGELOG.md +19 -0
  4. package/LICENSE.md +21 -0
  5. package/README.md +10 -0
  6. package/build/messages/src/blocks/Table/TableBlockEdit.json +90 -0
  7. package/build/messages/src/blocks/Text/DefaultTextBlockEditor.json +6 -0
  8. package/build/messages/src/blocks/Text/DetachedTextBlockEditor.json +6 -0
  9. package/build/messages/src/blocks/Text/SlashMenu.json +6 -0
  10. package/build/messages/src/editor/plugins/AdvancedLink/index.json +10 -0
  11. package/build/messages/src/editor/plugins/Link/index.json +10 -0
  12. package/build/messages/src/editor/plugins/Table/index.json +30 -0
  13. package/build/messages/src/elementEditor/messages.json +10 -0
  14. package/build/messages/src/widgets/HtmlSlateWidget.json +6 -0
  15. package/build/messages/src/widgets/RichTextWidgetView.json +6 -0
  16. package/locales/de/LC_MESSAGES/volto.po +148 -0
  17. package/locales/en/LC_MESSAGES/volto.po +148 -0
  18. package/locales/volto.pot +182 -0
  19. package/package.json +42 -0
  20. package/src/actions/content.js +30 -0
  21. package/src/actions/index.js +3 -0
  22. package/src/actions/plugins.js +9 -0
  23. package/src/actions/selection.js +22 -0
  24. package/src/blocks/Table/Cell.jsx +87 -0
  25. package/src/blocks/Table/Cell.test.js +54 -0
  26. package/src/blocks/Table/TableBlockEdit.jsx +694 -0
  27. package/src/blocks/Table/TableBlockEdit.test.js +40 -0
  28. package/src/blocks/Table/TableBlockView.jsx +150 -0
  29. package/src/blocks/Table/TableBlockView.test.js +49 -0
  30. package/src/blocks/Table/__snapshots__/Cell.test.js.snap +3 -0
  31. package/src/blocks/Table/__snapshots__/TableBlockEdit.test.js.snap +22 -0
  32. package/src/blocks/Table/__snapshots__/TableBlockView.test.js.snap +27 -0
  33. package/src/blocks/Table/deconstruct.js +113 -0
  34. package/src/blocks/Table/extensions/normalizeTable.js +5 -0
  35. package/src/blocks/Table/index.js +60 -0
  36. package/src/blocks/Table/schema.js +122 -0
  37. package/src/blocks/Text/DefaultTextBlockEditor.jsx +304 -0
  38. package/src/blocks/Text/DetachedTextBlockEditor.jsx +77 -0
  39. package/src/blocks/Text/MarkdownIntroduction.jsx +59 -0
  40. package/src/blocks/Text/PluginSidebar.jsx +18 -0
  41. package/src/blocks/Text/ShortcutListing.jsx +28 -0
  42. package/src/blocks/Text/SlashMenu.jsx +203 -0
  43. package/src/blocks/Text/TextBlockEdit.jsx +38 -0
  44. package/src/blocks/Text/TextBlockEdit.test.js +107 -0
  45. package/src/blocks/Text/TextBlockSchema.js +54 -0
  46. package/src/blocks/Text/TextBlockView.jsx +31 -0
  47. package/src/blocks/Text/__snapshots__/TextBlockEdit.test.js.snap +62 -0
  48. package/src/blocks/Text/css/editor.css +18 -0
  49. package/src/blocks/Text/extensions/Readme.md +49 -0
  50. package/src/blocks/Text/extensions/breakList.js +100 -0
  51. package/src/blocks/Text/extensions/index.js +6 -0
  52. package/src/blocks/Text/extensions/insertBreak.js +57 -0
  53. package/src/blocks/Text/extensions/isSelected.js +7 -0
  54. package/src/blocks/Text/extensions/normalizeExternalData.js +7 -0
  55. package/src/blocks/Text/extensions/withDeserializers.js +87 -0
  56. package/src/blocks/Text/extensions/withLists.js +5 -0
  57. package/src/blocks/Text/index.js +171 -0
  58. package/src/blocks/Text/keyboard/backspaceInList.js +58 -0
  59. package/src/blocks/Text/keyboard/breakBlocks.js +3 -0
  60. package/src/blocks/Text/keyboard/cancelEsc.js +7 -0
  61. package/src/blocks/Text/keyboard/indentListItems.js +240 -0
  62. package/src/blocks/Text/keyboard/index.js +52 -0
  63. package/src/blocks/Text/keyboard/joinBlocks.js +180 -0
  64. package/src/blocks/Text/keyboard/moveListItems.js +124 -0
  65. package/src/blocks/Text/keyboard/slashMenu.js +19 -0
  66. package/src/blocks/Text/keyboard/softBreak.js +7 -0
  67. package/src/blocks/Text/keyboard/traverseBlocks.js +81 -0
  68. package/src/blocks/Text/keyboard/unwrapEmptyString.js +26 -0
  69. package/src/blocks/Text/schema.js +39 -0
  70. package/src/constants.js +123 -0
  71. package/src/editor/EditorContext.jsx +5 -0
  72. package/src/editor/EditorReference.jsx +22 -0
  73. package/src/editor/SlateEditor.jsx +375 -0
  74. package/src/editor/config.jsx +344 -0
  75. package/src/editor/decorate.js +68 -0
  76. package/src/editor/deserialize.js +185 -0
  77. package/src/editor/extensions/index.js +6 -0
  78. package/src/editor/extensions/insertBreak.js +15 -0
  79. package/src/editor/extensions/insertData.js +161 -0
  80. package/src/editor/extensions/isInline.js +14 -0
  81. package/src/editor/extensions/normalizeExternalData.js +8 -0
  82. package/src/editor/extensions/normalizeNode.js +48 -0
  83. package/src/editor/extensions/withDeserializers.js +15 -0
  84. package/src/editor/extensions/withTestingFeatures.jsx +84 -0
  85. package/src/editor/index.js +14 -0
  86. package/src/editor/less/editor.less +173 -0
  87. package/src/editor/less/globals.less +18 -0
  88. package/src/editor/less/slate.less +28 -0
  89. package/src/editor/plugins/AdvancedLink/deserialize.js +90 -0
  90. package/src/editor/plugins/AdvancedLink/extensions.js +32 -0
  91. package/src/editor/plugins/AdvancedLink/index.js +50 -0
  92. package/src/editor/plugins/AdvancedLink/render.jsx +37 -0
  93. package/src/editor/plugins/AdvancedLink/schema.js +114 -0
  94. package/src/editor/plugins/AdvancedLink/styles.less +8 -0
  95. package/src/editor/plugins/Blockquote/index.js +30 -0
  96. package/src/editor/plugins/Callout/index.js +34 -0
  97. package/src/editor/plugins/Image/deconstruct.js +30 -0
  98. package/src/editor/plugins/Image/extensions.js +51 -0
  99. package/src/editor/plugins/Image/index.js +11 -0
  100. package/src/editor/plugins/Image/render.jsx +22 -0
  101. package/src/editor/plugins/Link/extensions.js +58 -0
  102. package/src/editor/plugins/Link/index.js +159 -0
  103. package/src/editor/plugins/Link/render.jsx +54 -0
  104. package/src/editor/plugins/Markdown/constants.js +81 -0
  105. package/src/editor/plugins/Markdown/extensions.js +336 -0
  106. package/src/editor/plugins/Markdown/index.js +28 -0
  107. package/src/editor/plugins/Markdown/utils.js +198 -0
  108. package/src/editor/plugins/StyleMenu/StyleMenu.jsx +153 -0
  109. package/src/editor/plugins/StyleMenu/index.js +19 -0
  110. package/src/editor/plugins/StyleMenu/style.less +29 -0
  111. package/src/editor/plugins/StyleMenu/utils.js +168 -0
  112. package/src/editor/plugins/Table/TableButton.jsx +142 -0
  113. package/src/editor/plugins/Table/TableCell.jsx +44 -0
  114. package/src/editor/plugins/Table/TableContainer.jsx +37 -0
  115. package/src/editor/plugins/Table/TableSizePicker.jsx +83 -0
  116. package/src/editor/plugins/Table/extensions.js +87 -0
  117. package/src/editor/plugins/Table/index.js +390 -0
  118. package/src/editor/plugins/Table/less/public.less +29 -0
  119. package/src/editor/plugins/Table/less/table.less +28 -0
  120. package/src/editor/plugins/Table/render.jsx +30 -0
  121. package/src/editor/plugins/index.js +19 -0
  122. package/src/editor/render.jsx +224 -0
  123. package/src/editor/ui/BasicToolbar.jsx +11 -0
  124. package/src/editor/ui/BlockButton.jsx +31 -0
  125. package/src/editor/ui/ClearFormattingButton.jsx +21 -0
  126. package/src/editor/ui/ExpandedToolbar.jsx +18 -0
  127. package/src/editor/ui/Expando.jsx +5 -0
  128. package/src/editor/ui/InlineToolbar.jsx +69 -0
  129. package/src/editor/ui/MarkButton.jsx +23 -0
  130. package/src/editor/ui/MarkElementButton.jsx +30 -0
  131. package/src/editor/ui/Menu.jsx +13 -0
  132. package/src/editor/ui/PositionedToolbar.jsx +32 -0
  133. package/src/editor/ui/Separator.jsx +7 -0
  134. package/src/editor/ui/SlateContextToolbar.jsx +13 -0
  135. package/src/editor/ui/SlateToolbar.jsx +96 -0
  136. package/src/editor/ui/Toolbar.jsx +103 -0
  137. package/src/editor/ui/ToolbarButton.jsx +33 -0
  138. package/src/editor/ui/ToolbarButton.test.js +25 -0
  139. package/src/editor/ui/__snapshots__/ToolbarButton.test.js.snap +16 -0
  140. package/src/editor/ui/index.js +15 -0
  141. package/src/editor/utils.js +248 -0
  142. package/src/elementEditor/ContextButtons.jsx +57 -0
  143. package/src/elementEditor/PluginEditor.jsx +124 -0
  144. package/src/elementEditor/Readme.md +6 -0
  145. package/src/elementEditor/SchemaProvider.jsx +4 -0
  146. package/src/elementEditor/SidebarEditor.jsx +46 -0
  147. package/src/elementEditor/ToolbarButton.jsx +44 -0
  148. package/src/elementEditor/index.js +5 -0
  149. package/src/elementEditor/makeInlineElementPlugin.js +100 -0
  150. package/src/elementEditor/messages.js +14 -0
  151. package/src/elementEditor/utils.js +227 -0
  152. package/src/hooks/index.js +3 -0
  153. package/src/hooks/useEditorContext.js +6 -0
  154. package/src/hooks/useIsomorphicLayoutEffect.js +7 -0
  155. package/src/hooks/useSelectionPosition.js +25 -0
  156. package/src/i18n.js +180 -0
  157. package/src/icons/hashlink.svg +57 -0
  158. package/src/index.js +61 -0
  159. package/src/reducers/content.js +74 -0
  160. package/src/reducers/index.js +3 -0
  161. package/src/reducers/plugins.js +17 -0
  162. package/src/reducers/selection.js +16 -0
  163. package/src/utils/blocks.js +379 -0
  164. package/src/utils/blocks.test.js +138 -0
  165. package/src/utils/editor.js +31 -0
  166. package/src/utils/image.js +25 -0
  167. package/src/utils/index.js +11 -0
  168. package/src/utils/internals.js +46 -0
  169. package/src/utils/lists.js +92 -0
  170. package/src/utils/marks.js +104 -0
  171. package/src/utils/mime-types.js +24 -0
  172. package/src/utils/nodes.js +4 -0
  173. package/src/utils/ops.js +20 -0
  174. package/src/utils/random.js +17 -0
  175. package/src/utils/selection.js +236 -0
  176. package/src/utils/slate-string-utils.js +409 -0
  177. package/src/utils/volto-blocks.js +314 -0
  178. package/src/widgets/ErrorBoundary.jsx +27 -0
  179. package/src/widgets/HtmlSlateWidget.jsx +138 -0
  180. package/src/widgets/ObjectByTypeWidget.jsx +49 -0
  181. package/src/widgets/RichTextWidget.jsx +72 -0
  182. package/src/widgets/RichTextWidgetView.jsx +36 -0
  183. package/src/widgets/style.css +21 -0
@@ -0,0 +1,87 @@
1
+ import { blockTagDeserializer } from '@plone/volto-slate/editor/deserialize';
2
+ import {
3
+ TABLE,
4
+ TR,
5
+ TD,
6
+ TFOOT,
7
+ THEAD,
8
+ TBODY,
9
+ TH,
10
+ } from '@plone/volto-slate/constants';
11
+ import { Editor, Point, Range } from 'slate';
12
+
13
+ export const withTable = (editor) => {
14
+ const { deleteBackward, deleteForward, insertBreak } = editor;
15
+
16
+ // paste support
17
+ editor.htmlTagsToSlate = {
18
+ ...editor.htmlTagsToSlate,
19
+ TABLE: blockTagDeserializer(TABLE),
20
+ THEAD: blockTagDeserializer(THEAD),
21
+ TFOOT: blockTagDeserializer(TFOOT),
22
+ TBODY: blockTagDeserializer(TBODY),
23
+ TR: blockTagDeserializer(TR),
24
+ TH: blockTagDeserializer(TH),
25
+ TD: blockTagDeserializer(TD),
26
+ };
27
+
28
+ editor.deleteBackward = (unit) => {
29
+ const { selection } = editor;
30
+
31
+ if (selection && Range.isCollapsed(selection)) {
32
+ const [cell] = Editor.nodes(editor, {
33
+ match: (n) => n.type === TD,
34
+ });
35
+
36
+ if (cell) {
37
+ const [, cellPath] = cell;
38
+ const start = Editor.start(editor, cellPath);
39
+
40
+ if (Point.equals(selection.anchor, start)) {
41
+ return;
42
+ }
43
+ }
44
+ }
45
+
46
+ deleteBackward(unit);
47
+ };
48
+
49
+ editor.deleteForward = (unit) => {
50
+ const { selection } = editor;
51
+
52
+ if (selection && Range.isCollapsed(selection)) {
53
+ const [cell] = Editor.nodes(editor, {
54
+ match: (n) => n.type === TD,
55
+ });
56
+
57
+ if (cell) {
58
+ const [, cellPath] = cell;
59
+ const end = Editor.end(editor, cellPath);
60
+
61
+ if (Point.equals(selection.anchor, end)) {
62
+ return;
63
+ }
64
+ }
65
+ }
66
+
67
+ deleteForward(unit);
68
+ };
69
+
70
+ editor.insertBreak = () => {
71
+ const { selection } = editor;
72
+
73
+ if (selection) {
74
+ const [table] = Editor.nodes(editor, {
75
+ match: (n) => n.type === TABLE,
76
+ });
77
+
78
+ if (table) {
79
+ return;
80
+ }
81
+ }
82
+
83
+ insertBreak();
84
+ };
85
+
86
+ return editor;
87
+ };
@@ -0,0 +1,390 @@
1
+ import React from 'react';
2
+ import { withTable } from './extensions';
3
+ import TableButton from './TableButton';
4
+ import { tableElements } from './render';
5
+ import './less/public.less';
6
+
7
+ import clearSVG from '@plone/volto/icons/delete.svg';
8
+ import rowBeforeSVG from '@plone/volto/icons/row-before.svg';
9
+ import rowAfterSVG from '@plone/volto/icons/row-after.svg';
10
+ import colBeforeSVG from '@plone/volto/icons/column-before.svg';
11
+ import colAfterSVG from '@plone/volto/icons/column-after.svg';
12
+ import rowDeleteSVG from '@plone/volto/icons/row-delete.svg';
13
+ import colDeleteSVG from '@plone/volto/icons/column-delete.svg';
14
+
15
+ import { ToolbarButton } from '@plone/volto-slate/editor/ui';
16
+ import { Range, Transforms, Editor, Path } from 'slate';
17
+ import { defineMessages, useIntl } from 'react-intl';
18
+ import { TABLE, TR, P, TD, TH } from '@plone/volto-slate/constants';
19
+
20
+ const messages = defineMessages({
21
+ deleteTable: {
22
+ id: 'Delete table',
23
+ defaultMessage: 'Delete table',
24
+ },
25
+ insertRowBefore: {
26
+ id: 'Insert row before',
27
+ defaultMessage: 'Insert row before',
28
+ },
29
+ insertRowAfter: {
30
+ id: 'Insert row after',
31
+ defaultMessage: 'Insert row after',
32
+ },
33
+ deleteRow: {
34
+ id: 'Delete row',
35
+ defaultMessage: 'Delete row',
36
+ },
37
+ insertColBefore: {
38
+ id: 'Insert col before',
39
+ defaultMessage: 'Insert col before',
40
+ },
41
+ insertColAfter: {
42
+ id: 'Insert col after',
43
+ defaultMessage: 'Insert col after',
44
+ },
45
+ deleteCol: {
46
+ id: 'Delete col',
47
+ defaultMessage: 'Delete col',
48
+ },
49
+ });
50
+
51
+ const unhangRange = (editor, options = {}) => {
52
+ const { at = editor.selection, voids, unhang = true } = options;
53
+
54
+ if (Range.isRange(at) && unhang) {
55
+ options.at = Editor.unhangRange(editor, at, { voids });
56
+ }
57
+ };
58
+
59
+ const getNodes = (editor, options = {}) => {
60
+ unhangRange(editor, options);
61
+
62
+ return Editor.nodes(editor, options);
63
+ };
64
+
65
+ const findNode = (editor, options = {}) => {
66
+ try {
67
+ const nodeEntries = getNodes(editor, {
68
+ at: editor.selection || editor.getSavedSelection() || [],
69
+ });
70
+
71
+ for (const [node, path] of nodeEntries) {
72
+ return [node, path];
73
+ }
74
+ } catch (error) {
75
+ return undefined;
76
+ }
77
+ };
78
+
79
+ const someNode = (editor, options) => {
80
+ return !!findNode(editor, options);
81
+ };
82
+
83
+ const getEmptyCellNode = (editor, { header }) => {
84
+ return {
85
+ type: header ? TH : TD,
86
+ children: [{ type: P, children: [{ text: '' }] }],
87
+ };
88
+ };
89
+
90
+ const getEmptyRowNode = (editor, { header, colCount }) => {
91
+ return {
92
+ type: TR,
93
+ children: Array(colCount)
94
+ .fill(colCount)
95
+ .map(() => getEmptyCellNode(editor, { header })),
96
+ };
97
+ };
98
+
99
+ const addRowBefore = (editor, { header } = {}) => {
100
+ if (someNode(editor, { match: (n) => n.type === TABLE })) {
101
+ const currentRowItem = Editor.above(editor, {
102
+ match: (n) => n.type === TR,
103
+ });
104
+ if (currentRowItem) {
105
+ const [currentRowElem, currentRowPath] = currentRowItem;
106
+ Transforms.insertNodes(
107
+ editor,
108
+ getEmptyRowNode(editor, {
109
+ header,
110
+ colCount: currentRowElem.children.length,
111
+ }),
112
+ {
113
+ at: currentRowPath,
114
+ select: true, // TODO: this and similar lines in the Table plugin do nothing currently, why?
115
+ },
116
+ );
117
+ }
118
+ }
119
+ };
120
+
121
+ const addRowAfter = (editor, { header } = {}) => {
122
+ if (someNode(editor, { match: (n) => n.type === TABLE })) {
123
+ const currentRowItem = Editor.above(editor, {
124
+ match: (n) => n.type === TR,
125
+ });
126
+ if (currentRowItem) {
127
+ const [currentRowElem, currentRowPath] = currentRowItem;
128
+ Transforms.insertNodes(
129
+ editor,
130
+ getEmptyRowNode(editor, {
131
+ header,
132
+ colCount: currentRowElem.children.length,
133
+ }),
134
+ {
135
+ at: Path.next(currentRowPath),
136
+ select: true,
137
+ },
138
+ );
139
+ }
140
+ }
141
+ };
142
+
143
+ const deleteRow = (editor) => {
144
+ if (someNode(editor, { match: (n) => n.type === TABLE })) {
145
+ const currentTableItem = Editor.above(editor, {
146
+ match: (n) => n.type === TABLE,
147
+ });
148
+ const currentRowItem = Editor.above(editor, {
149
+ match: (n) => n.type === TR,
150
+ });
151
+ if (
152
+ currentRowItem &&
153
+ currentTableItem &&
154
+ // Cannot delete the last row
155
+ // TODO: handle tfoot and thead Element types here:
156
+ currentTableItem[0].children[0].children.length > 1
157
+ ) {
158
+ Transforms.removeNodes(editor, { at: currentRowItem[1] });
159
+ }
160
+ }
161
+ };
162
+
163
+ const addColBefore = (editor, { header } = {}) => {
164
+ if (someNode(editor, { match: (n) => n.type === TABLE })) {
165
+ const currentCellItem = Editor.above(editor, {
166
+ match: (n) => n.type === TH || n.type === TD,
167
+ });
168
+ const currentTableItem = Editor.above(editor, {
169
+ match: (n) => n.type === TABLE,
170
+ });
171
+
172
+ if (currentCellItem && currentTableItem) {
173
+ const nextCellPath = currentCellItem[1];
174
+ const newCellPath = nextCellPath.slice();
175
+ const replacePathPos = newCellPath.length - 2;
176
+ const currentRowIdx = nextCellPath[replacePathPos];
177
+
178
+ // TODO: handle tfoot and thead too:
179
+ currentTableItem[0].children[0].children.forEach((row, rowIdx) => {
180
+ newCellPath[replacePathPos] = rowIdx;
181
+ const isHeaderRow =
182
+ header === undefined ? row.children[0].type === TH : header;
183
+
184
+ Transforms.insertNodes(
185
+ editor,
186
+ getEmptyCellNode(editor, { header: isHeaderRow }),
187
+ {
188
+ at: newCellPath,
189
+ select: rowIdx === currentRowIdx,
190
+ },
191
+ );
192
+ });
193
+ }
194
+ }
195
+ };
196
+
197
+ const addColAfter = (editor, { header } = {}) => {
198
+ if (someNode(editor, { match: (n) => n.type === TABLE })) {
199
+ const currentCellItem = Editor.above(editor, {
200
+ match: (n) => n.type === TH || n.type === TD,
201
+ });
202
+ const currentTableItem = Editor.above(editor, {
203
+ match: (n) => n.type === TABLE,
204
+ });
205
+
206
+ if (currentCellItem && currentTableItem) {
207
+ const nextCellPath = Path.next(currentCellItem[1]);
208
+ const newCellPath = nextCellPath.slice();
209
+ const replacePathPos = newCellPath.length - 2;
210
+ const currentRowIdx = nextCellPath[replacePathPos];
211
+
212
+ // TODO: handle tfoot and thead too:
213
+ currentTableItem[0].children[0].children.forEach((row, rowIdx) => {
214
+ newCellPath[replacePathPos] = rowIdx;
215
+ const isHeaderRow =
216
+ header === undefined ? row.children[0].type === TH : header;
217
+
218
+ Transforms.insertNodes(
219
+ editor,
220
+ getEmptyCellNode(editor, { header: isHeaderRow }),
221
+ {
222
+ at: newCellPath,
223
+ select: rowIdx === currentRowIdx,
224
+ },
225
+ );
226
+ });
227
+ }
228
+ }
229
+ };
230
+
231
+ const deleteCol = (editor) => {
232
+ if (someNode(editor, { match: (n) => n.type === TABLE })) {
233
+ const currentCellItem = Editor.above(editor, {
234
+ match: (n) => n.type === TD || n.type === TH,
235
+ });
236
+ const currentRowItem = Editor.above(editor, {
237
+ match: (n) => n.type === TR,
238
+ });
239
+ const currentTableItem = Editor.above(editor, {
240
+ match: (n) => n.type === TABLE,
241
+ });
242
+
243
+ if (
244
+ currentCellItem &&
245
+ currentRowItem &&
246
+ currentTableItem &&
247
+ // Cannot delete the last cell
248
+ currentRowItem[0].children.length > 1
249
+ ) {
250
+ const currentCellPath = currentCellItem[1];
251
+ const pathToDelete = currentCellPath.slice();
252
+ const replacePathPos = pathToDelete.length - 2;
253
+
254
+ // TODO: handle tfoot and thead too:
255
+ currentTableItem[0].children[0].children.forEach((row, rowIdx) => {
256
+ pathToDelete[replacePathPos] = rowIdx;
257
+
258
+ Transforms.removeNodes(editor, {
259
+ at: pathToDelete,
260
+ });
261
+ });
262
+ }
263
+ }
264
+ };
265
+
266
+ export default function install(config) {
267
+ const { slate } = config.settings;
268
+
269
+ slate.extensions = [...(slate.extensions || []), withTable];
270
+ slate.elements = {
271
+ ...slate.elements,
272
+ ...tableElements,
273
+ };
274
+ slate.elementToolbarButtons[TABLE] = [
275
+ ({ editor }) => {
276
+ const intl = useIntl();
277
+
278
+ return (
279
+ <ToolbarButton
280
+ title={intl.formatMessage(messages.deleteTable)}
281
+ icon={clearSVG}
282
+ aria-label={intl.formatMessage(messages.deleteTable)}
283
+ onMouseDown={() => {
284
+ Transforms.removeNodes(editor, {
285
+ at: editor.selection || editor.getSavedSelection(),
286
+ match: (n) => n.type === TABLE,
287
+ });
288
+ }}
289
+ />
290
+ );
291
+ },
292
+ ({ editor }) => {
293
+ const intl = useIntl();
294
+
295
+ return (
296
+ <ToolbarButton
297
+ title={intl.formatMessage(messages.insertRowBefore)}
298
+ icon={rowBeforeSVG}
299
+ aria-label={intl.formatMessage(messages.insertRowBefore)}
300
+ onMouseDown={() => {
301
+ addRowBefore(editor);
302
+ }}
303
+ />
304
+ );
305
+ },
306
+ ({ editor }) => {
307
+ const intl = useIntl();
308
+
309
+ return (
310
+ <ToolbarButton
311
+ title={intl.formatMessage(messages.insertRowAfter)}
312
+ icon={rowAfterSVG}
313
+ aria-label={intl.formatMessage(messages.insertRowAfter)}
314
+ onMouseDown={() => {
315
+ addRowAfter(editor, { header: false });
316
+ }}
317
+ />
318
+ );
319
+ },
320
+ ({ editor }) => {
321
+ const intl = useIntl();
322
+
323
+ return (
324
+ <ToolbarButton
325
+ title={intl.formatMessage(messages.deleteRow)}
326
+ icon={rowDeleteSVG}
327
+ aria-label={intl.formatMessage(messages.deleteRow)}
328
+ onMouseDown={() => {
329
+ deleteRow(editor);
330
+ }}
331
+ />
332
+ );
333
+ },
334
+ ({ editor }) => {
335
+ const intl = useIntl();
336
+
337
+ return (
338
+ <ToolbarButton
339
+ title={intl.formatMessage(messages.insertColBefore)}
340
+ icon={colBeforeSVG}
341
+ aria-label={intl.formatMessage(messages.insertColBefore)}
342
+ onMouseDown={() => {
343
+ addColBefore(editor);
344
+ }}
345
+ />
346
+ );
347
+ },
348
+ ({ editor }) => {
349
+ const intl = useIntl();
350
+
351
+ return (
352
+ <ToolbarButton
353
+ title={intl.formatMessage(messages.insertColAfter)}
354
+ icon={colAfterSVG}
355
+ aria-label={intl.formatMessage(messages.insertColAfter)}
356
+ onMouseDown={() => {
357
+ addColAfter(editor);
358
+ }}
359
+ />
360
+ );
361
+ },
362
+ ({ editor }) => {
363
+ const intl = useIntl();
364
+
365
+ return (
366
+ <ToolbarButton
367
+ title={intl.formatMessage(messages.deleteCol)}
368
+ icon={colDeleteSVG}
369
+ aria-label={intl.formatMessage(messages.deleteCol)}
370
+ onMouseDown={() => {
371
+ deleteCol(editor);
372
+ }}
373
+ />
374
+ );
375
+ },
376
+ ];
377
+
378
+ return config;
379
+ }
380
+
381
+ export const installTableButton = (config) => {
382
+ const { slate } = config.settings;
383
+ slate.buttons.table = (props) => <TableButton {...props} title="Table" />;
384
+ slate.toolbarButtons = [...(slate.toolbarButtons || []), 'table'];
385
+ slate.expandedToolbarButtons = [
386
+ ...(slate.expandedToolbarButtons || []),
387
+ 'table',
388
+ ];
389
+ return config;
390
+ };
@@ -0,0 +1,29 @@
1
+ @brown: #826a6a;
2
+
3
+ table.slate-table {
4
+ width: 100%;
5
+ border: 0.025rem solid @brown;
6
+ margin-top: 1rem;
7
+ margin-bottom: 1rem;
8
+ border-collapse: collapse;
9
+ border-spacing: 30px;
10
+
11
+ th,
12
+ td {
13
+ padding: 0.5rem;
14
+ border: 0.05rem solid @brown;
15
+ vertical-align: middle;
16
+ }
17
+
18
+ th {
19
+ border-bottom: 0.15rem solid @brown;
20
+ }
21
+ }
22
+
23
+ table.slate-table-block.sortable {
24
+ tr th > * {
25
+ // Header will contain both the slate and an icon when sorted
26
+ // so this will keep them on the same line.
27
+ display: inline-block;
28
+ }
29
+ }
@@ -0,0 +1,28 @@
1
+ @brown: #826a6a;
2
+
3
+ .slate-table-dropdown-button {
4
+ }
5
+
6
+ .slate-table-dropdown-menu {
7
+ p {
8
+ margin-top: 1rem;
9
+ font-size: small;
10
+ }
11
+
12
+ td {
13
+ border: 0.1rem solid #bbbbbb55;
14
+ border-radius: 0.1rem;
15
+ cursor: pointer;
16
+
17
+ & > button {
18
+ width: 100%;
19
+ height: 100%;
20
+ cursor: pointer;
21
+ opacity: 0;
22
+ }
23
+
24
+ &.active {
25
+ background-color: @brown;
26
+ }
27
+ }
28
+ }
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import {
3
+ TABLE,
4
+ THEAD,
5
+ TFOOT,
6
+ TBODY,
7
+ TR,
8
+ TD,
9
+ TH,
10
+ } from '@plone/volto-slate/constants';
11
+
12
+ export const tableElements = {
13
+ [TABLE]: ({ attributes, children }) => (
14
+ <table {...attributes} className="slate-table">
15
+ {children}
16
+ </table>
17
+ ),
18
+ [THEAD]: ({ attributes, children }) => (
19
+ <thead {...attributes}>{children}</thead>
20
+ ),
21
+ [TFOOT]: ({ attributes, children }) => (
22
+ <tfoot {...attributes}>{children}</tfoot>
23
+ ),
24
+ [TBODY]: ({ attributes, children }) => (
25
+ <tbody {...attributes}>{children}</tbody>
26
+ ),
27
+ [TR]: ({ attributes, children }) => <tr {...attributes}>{children}</tr>,
28
+ [TD]: ({ attributes, children }) => <td {...attributes}>{children}</td>,
29
+ [TH]: ({ attributes, children }) => <th {...attributes}>{children}</th>,
30
+ };
@@ -0,0 +1,19 @@
1
+ import installBlockQuotePlugin from './Blockquote';
2
+ import installCallout from './Callout';
3
+ import installImage from './Image';
4
+ import installLinkPlugin from './Link';
5
+ import installMarkdown from './Markdown';
6
+ import installTable from './Table';
7
+ import installStyleMenu from './StyleMenu';
8
+
9
+ export default function install(config) {
10
+ return [
11
+ installBlockQuotePlugin,
12
+ installCallout,
13
+ installLinkPlugin,
14
+ installMarkdown,
15
+ installImage,
16
+ installTable,
17
+ installStyleMenu,
18
+ ].reduce((acc, apply) => apply(acc), config);
19
+ }