import {EditorBasicButtonDefinition, EditorButtonDefinition} from "../../framework/buttons"; import tableIcon from "@icons/editor/table.svg"; import deleteIcon from "@icons/editor/table-delete.svg"; import deleteColumnIcon from "@icons/editor/table-delete-column.svg"; import deleteRowIcon from "@icons/editor/table-delete-row.svg"; import insertColumnAfterIcon from "@icons/editor/table-insert-column-after.svg"; import insertColumnBeforeIcon from "@icons/editor/table-insert-column-before.svg"; import insertRowAboveIcon from "@icons/editor/table-insert-row-above.svg"; import insertRowBelowIcon from "@icons/editor/table-insert-row-below.svg"; import {EditorUiContext} from "../../framework/core"; import {$getSelection, BaseSelection} from "lexical"; import {$isCustomTableNode} from "../../../nodes/custom-table"; import { $deleteTableColumn__EXPERIMENTAL, $deleteTableRow__EXPERIMENTAL, $insertTableColumn__EXPERIMENTAL, $insertTableRow__EXPERIMENTAL, $isTableNode, $isTableSelection, $unmergeCell, TableCellNode, } from "@lexical/table"; import {$getNodeFromSelection, $selectionContainsNodeType} from "../../../utils/selection"; import {$getParentOfType} from "../../../utils/nodes"; import {$isCustomTableCellNode} from "../../../nodes/custom-table-cell"; import {$showCellPropertiesForm, $showRowPropertiesForm, $showTablePropertiesForm} from "../forms/tables"; import { $clearTableFormatting, $clearTableSizes, $getTableFromSelection, $getTableRowsFromSelection, $mergeTableCellsInSelection } from "../../../utils/tables"; import {$isCustomTableRowNode} from "../../../nodes/custom-table-row"; import { $copySelectedColumnsToClipboard, $copySelectedRowsToClipboard, $cutSelectedColumnsToClipboard, $cutSelectedRowsToClipboard, $pasteClipboardRowsBefore, $pasteClipboardRowsAfter, isColumnClipboardEmpty, isRowClipboardEmpty, $pasteClipboardColumnsBefore, $pasteClipboardColumnsAfter } from "../../../utils/table-copy-paste"; const neverActive = (): boolean => false; const cellNotSelected = (selection: BaseSelection|null) => !$selectionContainsNodeType(selection, $isCustomTableCellNode); export const table: EditorBasicButtonDefinition = { label: 'Table', icon: tableIcon, }; export const tableProperties: EditorButtonDefinition = { label: 'Table properties', icon: tableIcon, action(context: EditorUiContext) { context.editor.getEditorState().read(() => { const table = $getTableFromSelection($getSelection()); if ($isCustomTableNode(table)) { $showTablePropertiesForm(table, context); } }); }, isActive: neverActive, isDisabled: cellNotSelected, }; export const clearTableFormatting: EditorButtonDefinition = { label: 'Clear table formatting', format: 'long', action(context: EditorUiContext) { context.editor.update(() => { const cell = $getNodeFromSelection($getSelection(), $isCustomTableCellNode); if (!$isCustomTableCellNode(cell)) { return; } const table = $getParentOfType(cell, $isTableNode); if ($isCustomTableNode(table)) { $clearTableFormatting(table); } }); }, isActive: neverActive, isDisabled: cellNotSelected, }; export const resizeTableToContents: EditorButtonDefinition = { label: 'Resize to contents', format: 'long', action(context: EditorUiContext) { context.editor.update(() => { const cell = $getNodeFromSelection($getSelection(), $isCustomTableCellNode); if (!$isCustomTableCellNode(cell)) { return; } const table = $getParentOfType(cell, $isCustomTableNode); if ($isCustomTableNode(table)) { $clearTableSizes(table); } }); }, isActive: neverActive, isDisabled: cellNotSelected, }; export const deleteTable: EditorButtonDefinition = { label: 'Delete table', icon: deleteIcon, action(context: EditorUiContext) { context.editor.update(() => { const table = $getNodeFromSelection($getSelection(), $isCustomTableNode); if (table) { table.remove(); } }); }, isActive() { return false; } }; export const deleteTableMenuAction: EditorButtonDefinition = { ...deleteTable, format: 'long', isDisabled(selection) { return !$selectionContainsNodeType(selection, $isTableNode); }, }; export const insertRowAbove: EditorButtonDefinition = { label: 'Insert row before', icon: insertRowAboveIcon, action(context: EditorUiContext) { context.editor.update(() => { $insertTableRow__EXPERIMENTAL(false); }); }, isActive: neverActive, isDisabled: cellNotSelected, }; export const insertRowBelow: EditorButtonDefinition = { label: 'Insert row after', icon: insertRowBelowIcon, action(context: EditorUiContext) { context.editor.update(() => { $insertTableRow__EXPERIMENTAL(true); }); }, isActive: neverActive, isDisabled: cellNotSelected, }; export const deleteRow: EditorButtonDefinition = { label: 'Delete row', icon: deleteRowIcon, action(context: EditorUiContext) { context.editor.update(() => { $deleteTableRow__EXPERIMENTAL(); }); }, isActive: neverActive, isDisabled: cellNotSelected, }; export const rowProperties: EditorButtonDefinition = { label: 'Row properties', format: 'long', action(context: EditorUiContext) { context.editor.getEditorState().read(() => { const rows = $getTableRowsFromSelection($getSelection()); if ($isCustomTableRowNode(rows[0])) { $showRowPropertiesForm(rows[0], context); } }); }, isActive: neverActive, isDisabled: cellNotSelected, }; export const cutRow: EditorButtonDefinition = { label: 'Cut row', format: 'long', action(context: EditorUiContext) { context.editor.update(() => { try { $cutSelectedRowsToClipboard(); } catch (e: any) { context.error(e); } }); }, isActive: neverActive, isDisabled: cellNotSelected, }; export const copyRow: EditorButtonDefinition = { label: 'Copy row', format: 'long', action(context: EditorUiContext) { context.editor.getEditorState().read(() => { try { $copySelectedRowsToClipboard(); } catch (e: any) { context.error(e); } }); }, isActive: neverActive, isDisabled: cellNotSelected, }; export const pasteRowBefore: EditorButtonDefinition = { label: 'Paste row before', format: 'long', action(context: EditorUiContext) { context.editor.update(() => { try { $pasteClipboardRowsBefore(context.editor); } catch (e: any) { context.error(e); } }); }, isActive: neverActive, isDisabled: (selection) => cellNotSelected(selection) || isRowClipboardEmpty(), }; export const pasteRowAfter: EditorButtonDefinition = { label: 'Paste row after', format: 'long', action(context: EditorUiContext) { context.editor.update(() => { try { $pasteClipboardRowsAfter(context.editor); } catch (e: any) { context.error(e); } }); }, isActive: neverActive, isDisabled: (selection) => cellNotSelected(selection) || isRowClipboardEmpty(), }; export const cutColumn: EditorButtonDefinition = { label: 'Cut column', format: 'long', action(context: EditorUiContext) { context.editor.update(() => { try { $cutSelectedColumnsToClipboard(); } catch (e: any) { context.error(e); } }); }, isActive: neverActive, isDisabled: cellNotSelected, }; export const copyColumn: EditorButtonDefinition = { label: 'Copy column', format: 'long', action(context: EditorUiContext) { context.editor.getEditorState().read(() => { try { $copySelectedColumnsToClipboard(); } catch (e: any) { context.error(e); } }); }, isActive: neverActive, isDisabled: cellNotSelected, }; export const pasteColumnBefore: EditorButtonDefinition = { label: 'Paste column before', format: 'long', action(context: EditorUiContext) { context.editor.update(() => { try { $pasteClipboardColumnsBefore(context.editor); } catch (e: any) { context.error(e); } }); }, isActive: neverActive, isDisabled: (selection) => cellNotSelected(selection) || isColumnClipboardEmpty(), }; export const pasteColumnAfter: EditorButtonDefinition = { label: 'Paste column after', format: 'long', action(context: EditorUiContext) { context.editor.update(() => { try { $pasteClipboardColumnsAfter(context.editor); } catch (e: any) { context.error(e); } }); }, isActive: neverActive, isDisabled: (selection) => cellNotSelected(selection) || isColumnClipboardEmpty(), }; export const insertColumnBefore: EditorButtonDefinition = { label: 'Insert column before', icon: insertColumnBeforeIcon, action(context: EditorUiContext) { context.editor.update(() => { $insertTableColumn__EXPERIMENTAL(false); }); }, isActive() { return false; } }; export const insertColumnAfter: EditorButtonDefinition = { label: 'Insert column after', icon: insertColumnAfterIcon, action(context: EditorUiContext) { context.editor.update(() => { $insertTableColumn__EXPERIMENTAL(true); }); }, isActive() { return false; } }; export const deleteColumn: EditorButtonDefinition = { label: 'Delete column', icon: deleteColumnIcon, action(context: EditorUiContext) { context.editor.update(() => { $deleteTableColumn__EXPERIMENTAL(); }); }, isActive() { return false; } }; export const cellProperties: EditorButtonDefinition = { label: 'Cell properties', action(context: EditorUiContext) { context.editor.getEditorState().read(() => { const cell = $getNodeFromSelection($getSelection(), $isCustomTableCellNode); if ($isCustomTableCellNode(cell)) { $showCellPropertiesForm(cell, context); } }); }, isActive: neverActive, isDisabled: cellNotSelected, }; export const mergeCells: EditorButtonDefinition = { label: 'Merge cells', action(context: EditorUiContext) { context.editor.update(() => { const selection = $getSelection(); if ($isTableSelection(selection)) { $mergeTableCellsInSelection(selection); } }); }, isActive: neverActive, isDisabled(selection) { return !$isTableSelection(selection); } }; export const splitCell: EditorButtonDefinition = { label: 'Split cell', action(context: EditorUiContext) { context.editor.update(() => { $unmergeCell(); }); }, isActive: neverActive, isDisabled(selection) { const cell = $getNodeFromSelection(selection, $isCustomTableCellNode) as TableCellNode|null; if (cell) { const merged = cell.getRowSpan() > 1 || cell.getColSpan() > 1; return !merged; } return true; } };