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";
13 $deleteTableColumn__EXPERIMENTAL,
14 $deleteTableRow__EXPERIMENTAL,
15 $insertTableColumn__EXPERIMENTAL,
16 $insertTableRow__EXPERIMENTAL, $isTableCellNode,
17 $isTableNode, $isTableRowNode, $isTableSelection, $unmergeCell, TableCellNode,
18 } from "@lexical/table";
19 import {$getNodeFromSelection, $selectionContainsNodeType} from "../../../utils/selection";
20 import {$getParentOfType} from "../../../utils/nodes";
21 import {$showCellPropertiesForm, $showRowPropertiesForm, $showTablePropertiesForm} from "../forms/tables";
23 $clearTableFormatting,
24 $clearTableSizes, $getTableFromSelection,
25 $getTableRowsFromSelection,
26 $mergeTableCellsInSelection
27 } from "../../../utils/tables";
29 $copySelectedColumnsToClipboard,
30 $copySelectedRowsToClipboard,
31 $cutSelectedColumnsToClipboard,
32 $cutSelectedRowsToClipboard,
33 $pasteClipboardRowsBefore,
34 $pasteClipboardRowsAfter,
35 isColumnClipboardEmpty,
37 $pasteClipboardColumnsBefore, $pasteClipboardColumnsAfter
38 } from "../../../utils/table-copy-paste";
40 const neverActive = (): boolean => false;
41 const cellNotSelected = (selection: BaseSelection|null) => !$selectionContainsNodeType(selection, $isTableCellNode);
43 export const table: EditorBasicButtonDefinition = {
48 export const tableProperties: EditorButtonDefinition = {
49 label: 'Table properties',
51 action(context: EditorUiContext) {
52 context.editor.getEditorState().read(() => {
53 const table = $getTableFromSelection($getSelection());
54 if ($isTableNode(table)) {
55 $showTablePropertiesForm(table, context);
59 isActive: neverActive,
60 isDisabled: cellNotSelected,
63 export const clearTableFormatting: EditorButtonDefinition = {
64 label: 'Clear table formatting',
66 action(context: EditorUiContext) {
67 context.editor.update(() => {
68 const cell = $getNodeFromSelection($getSelection(), $isTableCellNode);
69 if (!$isTableCellNode(cell)) {
73 const table = $getParentOfType(cell, $isTableNode);
74 if ($isTableNode(table)) {
75 $clearTableFormatting(table);
79 isActive: neverActive,
80 isDisabled: cellNotSelected,
83 export const resizeTableToContents: EditorButtonDefinition = {
84 label: 'Resize to contents',
86 action(context: EditorUiContext) {
87 context.editor.update(() => {
88 const cell = $getNodeFromSelection($getSelection(), $isTableCellNode);
89 if (!$isTableCellNode(cell)) {
93 const table = $getParentOfType(cell, $isTableNode);
94 if ($isTableNode(table)) {
95 $clearTableSizes(table);
99 isActive: neverActive,
100 isDisabled: cellNotSelected,
103 export const deleteTable: EditorButtonDefinition = {
104 label: 'Delete table',
106 action(context: EditorUiContext) {
107 context.editor.update(() => {
108 const table = $getNodeFromSelection($getSelection(), $isTableNode);
119 export const deleteTableMenuAction: EditorButtonDefinition = {
122 isDisabled(selection) {
123 return !$selectionContainsNodeType(selection, $isTableNode);
127 export const insertRowAbove: EditorButtonDefinition = {
128 label: 'Insert row before',
129 icon: insertRowAboveIcon,
130 action(context: EditorUiContext) {
131 context.editor.update(() => {
132 $insertTableRow__EXPERIMENTAL(false);
135 isActive: neverActive,
136 isDisabled: cellNotSelected,
139 export const insertRowBelow: EditorButtonDefinition = {
140 label: 'Insert row after',
141 icon: insertRowBelowIcon,
142 action(context: EditorUiContext) {
143 context.editor.update(() => {
144 $insertTableRow__EXPERIMENTAL(true);
147 isActive: neverActive,
148 isDisabled: cellNotSelected,
151 export const deleteRow: EditorButtonDefinition = {
154 action(context: EditorUiContext) {
155 context.editor.update(() => {
156 $deleteTableRow__EXPERIMENTAL();
159 isActive: neverActive,
160 isDisabled: cellNotSelected,
163 export const rowProperties: EditorButtonDefinition = {
164 label: 'Row properties',
166 action(context: EditorUiContext) {
167 context.editor.getEditorState().read(() => {
168 const rows = $getTableRowsFromSelection($getSelection());
169 if ($isTableRowNode(rows[0])) {
170 $showRowPropertiesForm(rows[0], context);
174 isActive: neverActive,
175 isDisabled: cellNotSelected,
178 export const cutRow: EditorButtonDefinition = {
181 action(context: EditorUiContext) {
182 context.editor.update(() => {
184 $cutSelectedRowsToClipboard();
190 isActive: neverActive,
191 isDisabled: cellNotSelected,
194 export const copyRow: EditorButtonDefinition = {
197 action(context: EditorUiContext) {
198 context.editor.getEditorState().read(() => {
200 $copySelectedRowsToClipboard();
206 isActive: neverActive,
207 isDisabled: cellNotSelected,
210 export const pasteRowBefore: EditorButtonDefinition = {
211 label: 'Paste row before',
213 action(context: EditorUiContext) {
214 context.editor.update(() => {
216 $pasteClipboardRowsBefore(context.editor);
222 isActive: neverActive,
223 isDisabled: (selection) => cellNotSelected(selection) || isRowClipboardEmpty(),
226 export const pasteRowAfter: EditorButtonDefinition = {
227 label: 'Paste row after',
229 action(context: EditorUiContext) {
230 context.editor.update(() => {
232 $pasteClipboardRowsAfter(context.editor);
238 isActive: neverActive,
239 isDisabled: (selection) => cellNotSelected(selection) || isRowClipboardEmpty(),
242 export const cutColumn: EditorButtonDefinition = {
245 action(context: EditorUiContext) {
246 context.editor.update(() => {
248 $cutSelectedColumnsToClipboard();
254 isActive: neverActive,
255 isDisabled: cellNotSelected,
258 export const copyColumn: EditorButtonDefinition = {
259 label: 'Copy column',
261 action(context: EditorUiContext) {
262 context.editor.getEditorState().read(() => {
264 $copySelectedColumnsToClipboard();
270 isActive: neverActive,
271 isDisabled: cellNotSelected,
274 export const pasteColumnBefore: EditorButtonDefinition = {
275 label: 'Paste column before',
277 action(context: EditorUiContext) {
278 context.editor.update(() => {
280 $pasteClipboardColumnsBefore(context.editor);
286 isActive: neverActive,
287 isDisabled: (selection) => cellNotSelected(selection) || isColumnClipboardEmpty(),
290 export const pasteColumnAfter: EditorButtonDefinition = {
291 label: 'Paste column after',
293 action(context: EditorUiContext) {
294 context.editor.update(() => {
296 $pasteClipboardColumnsAfter(context.editor);
302 isActive: neverActive,
303 isDisabled: (selection) => cellNotSelected(selection) || isColumnClipboardEmpty(),
306 export const insertColumnBefore: EditorButtonDefinition = {
307 label: 'Insert column before',
308 icon: insertColumnBeforeIcon,
309 action(context: EditorUiContext) {
310 context.editor.update(() => {
311 $insertTableColumn__EXPERIMENTAL(false);
319 export const insertColumnAfter: EditorButtonDefinition = {
320 label: 'Insert column after',
321 icon: insertColumnAfterIcon,
322 action(context: EditorUiContext) {
323 context.editor.update(() => {
324 $insertTableColumn__EXPERIMENTAL(true);
332 export const deleteColumn: EditorButtonDefinition = {
333 label: 'Delete column',
334 icon: deleteColumnIcon,
335 action(context: EditorUiContext) {
336 context.editor.update(() => {
337 $deleteTableColumn__EXPERIMENTAL();
345 export const cellProperties: EditorButtonDefinition = {
346 label: 'Cell properties',
348 action(context: EditorUiContext) {
349 context.editor.getEditorState().read(() => {
350 const cell = $getNodeFromSelection($getSelection(), $isTableCellNode);
351 if ($isTableCellNode(cell)) {
352 $showCellPropertiesForm(cell, context);
356 isActive: neverActive,
357 isDisabled: cellNotSelected,
360 export const mergeCells: EditorButtonDefinition = {
361 label: 'Merge cells',
363 action(context: EditorUiContext) {
364 context.editor.update(() => {
365 const selection = $getSelection();
366 if ($isTableSelection(selection)) {
367 $mergeTableCellsInSelection(selection);
371 isActive: neverActive,
372 isDisabled(selection) {
373 return !$isTableSelection(selection);
377 export const splitCell: EditorButtonDefinition = {
380 action(context: EditorUiContext) {
381 context.editor.update(() => {
385 isActive: neverActive,
386 isDisabled(selection) {
387 const cell = $getNodeFromSelection(selection, $isTableCellNode) as TableCellNode|null;
389 const merged = cell.getRowSpan() > 1 || cell.getColSpan() > 1;