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";
14 $deleteTableColumn__EXPERIMENTAL,
15 $deleteTableRow__EXPERIMENTAL,
16 $insertTableColumn__EXPERIMENTAL,
17 $insertTableRow__EXPERIMENTAL,
18 $isTableNode, $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, $showTablePropertiesForm} from "../forms/tables";
25 $clearTableFormatting,
26 $clearTableSizes, $getTableFromSelection,
27 $getTableRowsFromSelection,
28 $mergeTableCellsInSelection
29 } from "../../../utils/tables";
30 import {$isCustomTableRowNode} from "../../../nodes/custom-table-row";
32 $copySelectedRowsToClipboard,
33 $cutSelectedRowsToClipboard,
34 $pasteClipboardRowsBefore, $pasteRowsAfter, isRowClipboardEmpty
35 } from "../../../utils/table-copy-paste";
37 const neverActive = (): boolean => false;
38 const cellNotSelected = (selection: BaseSelection|null) => !$selectionContainsNodeType(selection, $isCustomTableCellNode);
40 export const table: EditorBasicButtonDefinition = {
45 export const tableProperties: EditorButtonDefinition = {
46 label: 'Table properties',
48 action(context: EditorUiContext) {
49 context.editor.getEditorState().read(() => {
50 const table = $getTableFromSelection($getSelection());
51 if ($isCustomTableNode(table)) {
52 $showTablePropertiesForm(table, context);
56 isActive: neverActive,
57 isDisabled: cellNotSelected,
60 export const clearTableFormatting: EditorButtonDefinition = {
61 label: 'Clear table formatting',
63 action(context: EditorUiContext) {
64 context.editor.update(() => {
65 const cell = $getNodeFromSelection($getSelection(), $isCustomTableCellNode);
66 if (!$isCustomTableCellNode(cell)) {
70 const table = $getParentOfType(cell, $isTableNode);
71 if ($isCustomTableNode(table)) {
72 $clearTableFormatting(table);
76 isActive: neverActive,
77 isDisabled: cellNotSelected,
80 export const resizeTableToContents: EditorButtonDefinition = {
81 label: 'Resize to contents',
83 action(context: EditorUiContext) {
84 context.editor.update(() => {
85 const cell = $getNodeFromSelection($getSelection(), $isCustomTableCellNode);
86 if (!$isCustomTableCellNode(cell)) {
90 const table = $getParentOfType(cell, $isCustomTableNode);
91 if ($isCustomTableNode(table)) {
92 $clearTableSizes(table);
96 isActive: neverActive,
97 isDisabled: cellNotSelected,
100 export const deleteTable: EditorButtonDefinition = {
101 label: 'Delete table',
103 action(context: EditorUiContext) {
104 context.editor.update(() => {
105 const table = $getNodeFromSelection($getSelection(), $isCustomTableNode);
116 export const deleteTableMenuAction: EditorButtonDefinition = {
119 isDisabled(selection) {
120 return !$selectionContainsNodeType(selection, $isTableNode);
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);
132 isActive: neverActive,
133 isDisabled: cellNotSelected,
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);
144 isActive: neverActive,
145 isDisabled: cellNotSelected,
148 export const deleteRow: EditorButtonDefinition = {
151 action(context: EditorUiContext) {
152 context.editor.update(() => {
153 $deleteTableRow__EXPERIMENTAL();
156 isActive: neverActive,
157 isDisabled: cellNotSelected,
160 export const rowProperties: EditorButtonDefinition = {
161 label: 'Row properties',
163 action(context: EditorUiContext) {
164 context.editor.getEditorState().read(() => {
165 const rows = $getTableRowsFromSelection($getSelection());
166 if ($isCustomTableRowNode(rows[0])) {
167 $showRowPropertiesForm(rows[0], context);
171 isActive: neverActive,
172 isDisabled: cellNotSelected,
175 export const cutRow: EditorButtonDefinition = {
178 action(context: EditorUiContext) {
179 context.editor.update(() => {
181 $cutSelectedRowsToClipboard();
183 context.error(e.toString());
187 isActive: neverActive,
188 isDisabled: cellNotSelected,
191 export const copyRow: EditorButtonDefinition = {
194 action(context: EditorUiContext) {
195 context.editor.getEditorState().read(() => {
197 $copySelectedRowsToClipboard();
199 context.error(e.toString());
203 isActive: neverActive,
204 isDisabled: cellNotSelected,
207 export const pasteRowBefore: EditorButtonDefinition = {
208 label: 'Paste row before',
210 action(context: EditorUiContext) {
211 context.editor.update(() => {
213 $pasteClipboardRowsBefore(context.editor);
215 context.error(e.toString());
219 isActive: neverActive,
220 isDisabled: (selection) => cellNotSelected(selection) || isRowClipboardEmpty(),
223 export const pasteRowAfter: EditorButtonDefinition = {
224 label: 'Paste row after',
226 action(context: EditorUiContext) {
227 context.editor.update(() => {
229 $pasteRowsAfter(context.editor);
231 context.error(e.toString());
235 isActive: neverActive,
236 isDisabled: (selection) => cellNotSelected(selection) || isRowClipboardEmpty(),
239 export const cutColumn: EditorButtonDefinition = {
242 action(context: EditorUiContext) {
243 context.editor.getEditorState().read(() => {
247 isActive: neverActive,
248 isDisabled: cellNotSelected,
251 export const copyColumn: EditorButtonDefinition = {
252 label: 'Copy column',
254 action(context: EditorUiContext) {
255 context.editor.getEditorState().read(() => {
259 isActive: neverActive,
260 isDisabled: cellNotSelected,
263 export const pasteColumnBefore: EditorButtonDefinition = {
264 label: 'Paste column before',
266 action(context: EditorUiContext) {
267 context.editor.getEditorState().read(() => {
271 isActive: neverActive,
272 isDisabled: cellNotSelected,
275 export const pasteColumnAfter: EditorButtonDefinition = {
276 label: 'Paste column after',
278 action(context: EditorUiContext) {
279 context.editor.getEditorState().read(() => {
283 isActive: neverActive,
284 isDisabled: cellNotSelected,
287 export const insertColumnBefore: EditorButtonDefinition = {
288 label: 'Insert column before',
289 icon: insertColumnBeforeIcon,
290 action(context: EditorUiContext) {
291 context.editor.update(() => {
292 $insertTableColumn__EXPERIMENTAL(false);
300 export const insertColumnAfter: EditorButtonDefinition = {
301 label: 'Insert column after',
302 icon: insertColumnAfterIcon,
303 action(context: EditorUiContext) {
304 context.editor.update(() => {
305 $insertTableColumn__EXPERIMENTAL(true);
313 export const deleteColumn: EditorButtonDefinition = {
314 label: 'Delete column',
315 icon: deleteColumnIcon,
316 action(context: EditorUiContext) {
317 context.editor.update(() => {
318 $deleteTableColumn__EXPERIMENTAL();
326 export const cellProperties: EditorButtonDefinition = {
327 label: 'Cell properties',
328 action(context: EditorUiContext) {
329 context.editor.getEditorState().read(() => {
330 const cell = $getNodeFromSelection($getSelection(), $isCustomTableCellNode);
331 if ($isCustomTableCellNode(cell)) {
332 $showCellPropertiesForm(cell, context);
336 isActive: neverActive,
337 isDisabled: cellNotSelected,
340 export const mergeCells: EditorButtonDefinition = {
341 label: 'Merge cells',
342 action(context: EditorUiContext) {
343 context.editor.update(() => {
344 const selection = $getSelection();
345 if ($isTableSelection(selection)) {
346 $mergeTableCellsInSelection(selection);
350 isActive: neverActive,
351 isDisabled(selection) {
352 return !$isTableSelection(selection);
356 export const splitCell: EditorButtonDefinition = {
358 action(context: EditorUiContext) {
359 context.editor.update(() => {
363 isActive: neverActive,
364 isDisabled(selection) {
365 const cell = $getNodeFromSelection(selection, $isCustomTableCellNode) as TableCellNode|null;
367 const merged = cell.getRowSpan() > 1 || cell.getColSpan() > 1;