]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/ui/defaults/buttons/tables.ts
Lexical: Linked row properties form up
[bookstack] / resources / js / wysiwyg / ui / defaults / buttons / tables.ts
1 import {EditorBasicButtonDefinition, EditorButtonDefinition} from "../../framework/buttons";
2 import tableIcon from "@icons/editor/table.svg";
3 import deleteIcon from "@icons/editor/table-delete.svg";
4 import deleteColumnIcon from "@icons/editor/table-delete-column.svg";
5 import deleteRowIcon from "@icons/editor/table-delete-row.svg";
6 import insertColumnAfterIcon from "@icons/editor/table-insert-column-after.svg";
7 import insertColumnBeforeIcon from "@icons/editor/table-insert-column-before.svg";
8 import insertRowAboveIcon from "@icons/editor/table-insert-row-above.svg";
9 import insertRowBelowIcon from "@icons/editor/table-insert-row-below.svg";
10 import {EditorUiContext} from "../../framework/core";
11 import {$getSelection, BaseSelection} from "lexical";
12 import {$isCustomTableNode} from "../../../nodes/custom-table";
13 import {
14     $deleteTableColumn__EXPERIMENTAL,
15     $deleteTableRow__EXPERIMENTAL,
16     $insertTableColumn__EXPERIMENTAL,
17     $insertTableRow__EXPERIMENTAL,
18     $isTableNode, $isTableRowNode, $isTableSelection, $unmergeCell, TableCellNode,
19 } from "@lexical/table";
20 import {$getNodeFromSelection, $selectionContainsNodeType} from "../../../utils/selection";
21 import {$getParentOfType} from "../../../utils/nodes";
22 import {$isCustomTableCellNode} from "../../../nodes/custom-table-cell";
23 import {$showCellPropertiesForm, $showRowPropertiesForm} from "../forms/tables";
24 import {$mergeTableCellsInSelection} from "../../../utils/tables";
25 import {$isCustomTableRowNode} from "../../../nodes/custom-table-row";
26
27 const neverActive = (): boolean => false;
28 const cellNotSelected = (selection: BaseSelection|null) => !$selectionContainsNodeType(selection, $isCustomTableCellNode);
29
30 export const table: EditorBasicButtonDefinition = {
31     label: 'Table',
32     icon: tableIcon,
33 };
34
35 export const tableProperties: EditorButtonDefinition = {
36     label: 'Table properties',
37     icon: tableIcon,
38     action(context: EditorUiContext) {
39         context.editor.getEditorState().read(() => {
40             const cell = $getNodeFromSelection($getSelection(), $isCustomTableCellNode);
41             if (!$isCustomTableCellNode(cell)) {
42                 return;
43             }
44
45             const table = $getParentOfType(cell, $isTableNode);
46             const modalForm = context.manager.createModal('table_properties');
47             modalForm.show({});
48             // TODO
49         });
50     },
51     isActive: neverActive,
52     isDisabled: cellNotSelected,
53 };
54
55 export const clearTableFormatting: EditorButtonDefinition = {
56     label: 'Clear table formatting',
57     format: 'long',
58     action(context: EditorUiContext) {
59         context.editor.getEditorState().read(() => {
60             const cell = $getNodeFromSelection($getSelection(), $isCustomTableCellNode);
61             if (!$isCustomTableCellNode(cell)) {
62                 return;
63             }
64
65             const table = $getParentOfType(cell, $isTableNode);
66             // TODO
67         });
68     },
69     isActive: neverActive,
70     isDisabled: cellNotSelected,
71 };
72
73 export const resizeTableToContents: EditorButtonDefinition = {
74     label: 'Resize to contents',
75     format: 'long',
76     action(context: EditorUiContext) {
77         context.editor.getEditorState().read(() => {
78             const cell = $getNodeFromSelection($getSelection(), $isCustomTableCellNode);
79             if (!$isCustomTableCellNode(cell)) {
80                 return;
81             }
82
83             const table = $getParentOfType(cell, $isCustomTableNode);
84             if (!$isCustomTableNode(table)) {
85                 return;
86             }
87
88             for (const row of table.getChildren()) {
89                 if ($isTableRowNode(row)) {
90                     // TODO - Come back later as this may depend on if we
91                     //   are using a custom table row
92                 }
93             }
94         });
95     },
96     isActive: neverActive,
97     isDisabled: cellNotSelected,
98 };
99
100 export const deleteTable: EditorButtonDefinition = {
101     label: 'Delete table',
102     icon: deleteIcon,
103     action(context: EditorUiContext) {
104         context.editor.update(() => {
105             const table = $getNodeFromSelection($getSelection(), $isCustomTableNode);
106             if (table) {
107                 table.remove();
108             }
109         });
110     },
111     isActive() {
112         return false;
113     }
114 };
115
116 export const deleteTableMenuAction: EditorButtonDefinition = {
117     ...deleteTable,
118     format: 'long',
119     isDisabled(selection) {
120         return !$selectionContainsNodeType(selection, $isTableNode);
121     },
122 };
123
124 export const insertRowAbove: EditorButtonDefinition = {
125     label: 'Insert row before',
126     icon: insertRowAboveIcon,
127     action(context: EditorUiContext) {
128         context.editor.update(() => {
129             $insertTableRow__EXPERIMENTAL(false);
130         });
131     },
132     isActive: neverActive,
133     isDisabled: cellNotSelected,
134 };
135
136 export const insertRowBelow: EditorButtonDefinition = {
137     label: 'Insert row after',
138     icon: insertRowBelowIcon,
139     action(context: EditorUiContext) {
140         context.editor.update(() => {
141             $insertTableRow__EXPERIMENTAL(true);
142         });
143     },
144     isActive: neverActive,
145     isDisabled: cellNotSelected,
146 };
147
148 export const deleteRow: EditorButtonDefinition = {
149     label: 'Delete row',
150     icon: deleteRowIcon,
151     action(context: EditorUiContext) {
152         context.editor.update(() => {
153             $deleteTableRow__EXPERIMENTAL();
154         });
155     },
156     isActive: neverActive,
157     isDisabled: cellNotSelected,
158 };
159
160 export const rowProperties: EditorButtonDefinition = {
161     label: 'Row properties',
162     format: 'long',
163     action(context: EditorUiContext) {
164         context.editor.getEditorState().read(() => {
165             const cell = $getNodeFromSelection($getSelection(), $isCustomTableCellNode);
166             if (!$isCustomTableCellNode(cell)) {
167                 return;
168             }
169
170             const row = $getParentOfType(cell, $isCustomTableRowNode);
171             if ($isCustomTableRowNode(row)) {
172                 $showRowPropertiesForm(row, context);
173             }
174         });
175     },
176     isActive: neverActive,
177     isDisabled: cellNotSelected,
178 };
179
180 export const cutRow: EditorButtonDefinition = {
181     label: 'Cut row',
182     format: 'long',
183     action(context: EditorUiContext) {
184         context.editor.getEditorState().read(() => {
185             // TODO
186         });
187     },
188     isActive: neverActive,
189     isDisabled: cellNotSelected,
190 };
191
192 export const copyRow: EditorButtonDefinition = {
193     label: 'Copy row',
194     format: 'long',
195     action(context: EditorUiContext) {
196         context.editor.getEditorState().read(() => {
197             // TODO
198         });
199     },
200     isActive: neverActive,
201     isDisabled: cellNotSelected,
202 };
203
204 export const pasteRowBefore: EditorButtonDefinition = {
205     label: 'Paste row before',
206     format: 'long',
207     action(context: EditorUiContext) {
208         context.editor.getEditorState().read(() => {
209             // TODO
210         });
211     },
212     isActive: neverActive,
213     isDisabled: cellNotSelected,
214 };
215
216 export const pasteRowAfter: EditorButtonDefinition = {
217     label: 'Paste row after',
218     format: 'long',
219     action(context: EditorUiContext) {
220         context.editor.getEditorState().read(() => {
221             // TODO
222         });
223     },
224     isActive: neverActive,
225     isDisabled: cellNotSelected,
226 };
227
228 export const cutColumn: EditorButtonDefinition = {
229     label: 'Cut column',
230     format: 'long',
231     action(context: EditorUiContext) {
232         context.editor.getEditorState().read(() => {
233             // TODO
234         });
235     },
236     isActive: neverActive,
237     isDisabled: cellNotSelected,
238 };
239
240 export const copyColumn: EditorButtonDefinition = {
241     label: 'Copy column',
242     format: 'long',
243     action(context: EditorUiContext) {
244         context.editor.getEditorState().read(() => {
245             // TODO
246         });
247     },
248     isActive: neverActive,
249     isDisabled: cellNotSelected,
250 };
251
252 export const pasteColumnBefore: EditorButtonDefinition = {
253     label: 'Paste column before',
254     format: 'long',
255     action(context: EditorUiContext) {
256         context.editor.getEditorState().read(() => {
257             // TODO
258         });
259     },
260     isActive: neverActive,
261     isDisabled: cellNotSelected,
262 };
263
264 export const pasteColumnAfter: EditorButtonDefinition = {
265     label: 'Paste column after',
266     format: 'long',
267     action(context: EditorUiContext) {
268         context.editor.getEditorState().read(() => {
269             // TODO
270         });
271     },
272     isActive: neverActive,
273     isDisabled: cellNotSelected,
274 };
275
276 export const insertColumnBefore: EditorButtonDefinition = {
277     label: 'Insert column before',
278     icon: insertColumnBeforeIcon,
279     action(context: EditorUiContext) {
280         context.editor.update(() => {
281             $insertTableColumn__EXPERIMENTAL(false);
282         });
283     },
284     isActive() {
285         return false;
286     }
287 };
288
289 export const insertColumnAfter: EditorButtonDefinition = {
290     label: 'Insert column after',
291     icon: insertColumnAfterIcon,
292     action(context: EditorUiContext) {
293         context.editor.update(() => {
294             $insertTableColumn__EXPERIMENTAL(true);
295         });
296     },
297     isActive() {
298         return false;
299     }
300 };
301
302 export const deleteColumn: EditorButtonDefinition = {
303     label: 'Delete column',
304     icon: deleteColumnIcon,
305     action(context: EditorUiContext) {
306         context.editor.update(() => {
307             $deleteTableColumn__EXPERIMENTAL();
308         });
309     },
310     isActive() {
311         return false;
312     }
313 };
314
315 export const cellProperties: EditorButtonDefinition = {
316     label: 'Cell properties',
317     action(context: EditorUiContext) {
318         context.editor.getEditorState().read(() => {
319             const cell = $getNodeFromSelection($getSelection(), $isCustomTableCellNode);
320             if ($isCustomTableCellNode(cell)) {
321                 $showCellPropertiesForm(cell, context);
322             }
323         });
324     },
325     isActive: neverActive,
326     isDisabled: cellNotSelected,
327 };
328
329 export const mergeCells: EditorButtonDefinition = {
330     label: 'Merge cells',
331     action(context: EditorUiContext) {
332         context.editor.update(() => {
333             const selection = $getSelection();
334             if ($isTableSelection(selection)) {
335                 $mergeTableCellsInSelection(selection);
336             }
337         });
338     },
339     isActive: neverActive,
340     isDisabled(selection) {
341         return !$isTableSelection(selection);
342     }
343 };
344
345 export const splitCell: EditorButtonDefinition = {
346     label: 'Split cell',
347     action(context: EditorUiContext) {
348         context.editor.update(() => {
349             $unmergeCell();
350         });
351     },
352     isActive: neverActive,
353     isDisabled(selection) {
354         const cell = $getNodeFromSelection(selection, $isCustomTableCellNode) as TableCellNode|null;
355         if (cell) {
356             const merged = cell.getRowSpan() > 1 || cell.getColSpan() > 1;
357             return !merged;
358         }
359
360         return true;
361     }
362 };