2024-07-21 22:11:24 +08:00
|
|
|
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";
|
2024-08-04 01:01:54 +08:00
|
|
|
import {$getSelection, BaseSelection} from "lexical";
|
2024-08-02 18:16:54 +08:00
|
|
|
import {$isCustomTableNode} from "../../../nodes/custom-table";
|
2024-07-21 22:11:24 +08:00
|
|
|
import {
|
2024-08-04 01:01:54 +08:00
|
|
|
$createTableRowNode,
|
2024-08-02 18:16:54 +08:00
|
|
|
$deleteTableColumn__EXPERIMENTAL,
|
2024-07-21 22:11:24 +08:00
|
|
|
$deleteTableRow__EXPERIMENTAL,
|
2024-08-02 18:16:54 +08:00
|
|
|
$insertTableColumn__EXPERIMENTAL,
|
2024-08-02 22:28:54 +08:00
|
|
|
$insertTableRow__EXPERIMENTAL, $isTableCellNode,
|
2024-08-04 01:01:54 +08:00
|
|
|
$isTableNode, $isTableRowNode, $isTableSelection, $unmergeCell, TableCellNode, TableNode,
|
2024-07-21 22:11:24 +08:00
|
|
|
} from "@lexical/table";
|
2024-08-04 01:14:01 +08:00
|
|
|
import {$getNodeFromSelection, $selectionContainsNodeType} from "../../../utils/selection";
|
|
|
|
import {$getParentOfType} from "../../../utils/nodes";
|
2024-07-21 22:11:24 +08:00
|
|
|
|
2024-08-04 01:01:54 +08:00
|
|
|
const neverActive = (): boolean => false;
|
|
|
|
const cellNotSelected = (selection: BaseSelection|null) => !$selectionContainsNodeType(selection, $isTableCellNode);
|
2024-07-21 22:11:24 +08:00
|
|
|
|
|
|
|
export const table: EditorBasicButtonDefinition = {
|
|
|
|
label: 'Table',
|
|
|
|
icon: tableIcon,
|
|
|
|
};
|
|
|
|
|
2024-08-04 01:01:54 +08:00
|
|
|
export const tableProperties: EditorButtonDefinition = {
|
|
|
|
label: 'Table properties',
|
|
|
|
icon: tableIcon,
|
|
|
|
action(context: EditorUiContext) {
|
|
|
|
context.editor.getEditorState().read(() => {
|
|
|
|
const cell = $getNodeFromSelection($getSelection(), $isTableCellNode);
|
|
|
|
if (!$isTableCellNode(cell)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const table = $getParentOfType(cell, $isTableNode);
|
|
|
|
const modalForm = context.manager.createModal('table_properties');
|
|
|
|
modalForm.show({});
|
|
|
|
// TODO
|
|
|
|
});
|
|
|
|
},
|
|
|
|
isActive: neverActive,
|
|
|
|
isDisabled: cellNotSelected,
|
|
|
|
};
|
|
|
|
|
|
|
|
export const clearTableFormatting: EditorButtonDefinition = {
|
|
|
|
label: 'Clear table formatting',
|
|
|
|
format: 'long',
|
|
|
|
action(context: EditorUiContext) {
|
|
|
|
context.editor.getEditorState().read(() => {
|
|
|
|
const cell = $getNodeFromSelection($getSelection(), $isTableCellNode);
|
|
|
|
if (!$isTableCellNode(cell)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const table = $getParentOfType(cell, $isTableNode);
|
|
|
|
// TODO
|
|
|
|
});
|
|
|
|
},
|
|
|
|
isActive: neverActive,
|
|
|
|
isDisabled: cellNotSelected,
|
|
|
|
};
|
|
|
|
|
|
|
|
export const resizeTableToContents: EditorButtonDefinition = {
|
|
|
|
label: 'Resize to contents',
|
|
|
|
format: 'long',
|
|
|
|
action(context: EditorUiContext) {
|
|
|
|
context.editor.getEditorState().read(() => {
|
|
|
|
const cell = $getNodeFromSelection($getSelection(), $isTableCellNode);
|
|
|
|
if (!$isTableCellNode(cell)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const table = $getParentOfType(cell, $isCustomTableNode);
|
|
|
|
if (!$isCustomTableNode(table)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const row of table.getChildren()) {
|
|
|
|
if ($isTableRowNode(row)) {
|
|
|
|
// TODO - Come back later as this may depend on if we
|
|
|
|
// are using a custom table row
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
isActive: neverActive,
|
|
|
|
isDisabled: cellNotSelected,
|
|
|
|
};
|
|
|
|
|
2024-07-21 22:11:24 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2024-08-02 18:16:54 +08:00
|
|
|
export const deleteTableMenuAction: EditorButtonDefinition = {
|
|
|
|
...deleteTable,
|
|
|
|
format: 'long',
|
|
|
|
isDisabled(selection) {
|
|
|
|
return !$selectionContainsNodeType(selection, $isTableNode);
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2024-07-21 22:11:24 +08:00
|
|
|
export const insertRowAbove: EditorButtonDefinition = {
|
2024-08-04 01:01:54 +08:00
|
|
|
label: 'Insert row before',
|
2024-07-21 22:11:24 +08:00
|
|
|
icon: insertRowAboveIcon,
|
|
|
|
action(context: EditorUiContext) {
|
|
|
|
context.editor.update(() => {
|
|
|
|
$insertTableRow__EXPERIMENTAL(false);
|
|
|
|
});
|
|
|
|
},
|
2024-08-04 01:01:54 +08:00
|
|
|
isActive: neverActive,
|
|
|
|
isDisabled: cellNotSelected,
|
2024-07-21 22:11:24 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
export const insertRowBelow: EditorButtonDefinition = {
|
2024-08-04 01:01:54 +08:00
|
|
|
label: 'Insert row after',
|
2024-07-21 22:11:24 +08:00
|
|
|
icon: insertRowBelowIcon,
|
|
|
|
action(context: EditorUiContext) {
|
|
|
|
context.editor.update(() => {
|
|
|
|
$insertTableRow__EXPERIMENTAL(true);
|
|
|
|
});
|
|
|
|
},
|
2024-08-04 01:01:54 +08:00
|
|
|
isActive: neverActive,
|
|
|
|
isDisabled: cellNotSelected,
|
2024-07-21 22:11:24 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
export const deleteRow: EditorButtonDefinition = {
|
|
|
|
label: 'Delete row',
|
|
|
|
icon: deleteRowIcon,
|
|
|
|
action(context: EditorUiContext) {
|
|
|
|
context.editor.update(() => {
|
|
|
|
$deleteTableRow__EXPERIMENTAL();
|
|
|
|
});
|
|
|
|
},
|
2024-08-04 01:01:54 +08:00
|
|
|
isActive: neverActive,
|
|
|
|
isDisabled: cellNotSelected,
|
|
|
|
};
|
|
|
|
|
|
|
|
export const rowProperties: EditorButtonDefinition = {
|
|
|
|
label: 'Row properties',
|
|
|
|
format: 'long',
|
|
|
|
action(context: EditorUiContext) {
|
|
|
|
context.editor.getEditorState().read(() => {
|
|
|
|
const cell = $getNodeFromSelection($getSelection(), $isTableCellNode);
|
|
|
|
if (!$isTableCellNode(cell)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const row = $getParentOfType(cell, $isTableRowNode);
|
|
|
|
const modalForm = context.manager.createModal('row_properties');
|
|
|
|
modalForm.show({});
|
|
|
|
// TODO
|
|
|
|
});
|
|
|
|
},
|
|
|
|
isActive: neverActive,
|
|
|
|
isDisabled: cellNotSelected,
|
|
|
|
};
|
|
|
|
|
|
|
|
export const cutRow: EditorButtonDefinition = {
|
|
|
|
label: 'Cut row',
|
|
|
|
format: 'long',
|
|
|
|
action(context: EditorUiContext) {
|
|
|
|
context.editor.getEditorState().read(() => {
|
|
|
|
// TODO
|
|
|
|
});
|
|
|
|
},
|
|
|
|
isActive: neverActive,
|
|
|
|
isDisabled: cellNotSelected,
|
|
|
|
};
|
|
|
|
|
|
|
|
export const copyRow: EditorButtonDefinition = {
|
|
|
|
label: 'Copy row',
|
|
|
|
format: 'long',
|
|
|
|
action(context: EditorUiContext) {
|
|
|
|
context.editor.getEditorState().read(() => {
|
|
|
|
// TODO
|
|
|
|
});
|
|
|
|
},
|
|
|
|
isActive: neverActive,
|
|
|
|
isDisabled: cellNotSelected,
|
|
|
|
};
|
|
|
|
|
|
|
|
export const pasteRowBefore: EditorButtonDefinition = {
|
|
|
|
label: 'Paste row before',
|
|
|
|
format: 'long',
|
|
|
|
action(context: EditorUiContext) {
|
|
|
|
context.editor.getEditorState().read(() => {
|
|
|
|
// TODO
|
|
|
|
});
|
|
|
|
},
|
|
|
|
isActive: neverActive,
|
|
|
|
isDisabled: cellNotSelected,
|
|
|
|
};
|
|
|
|
|
|
|
|
export const pasteRowAfter: EditorButtonDefinition = {
|
|
|
|
label: 'Paste row after',
|
|
|
|
format: 'long',
|
|
|
|
action(context: EditorUiContext) {
|
|
|
|
context.editor.getEditorState().read(() => {
|
|
|
|
// TODO
|
|
|
|
});
|
|
|
|
},
|
|
|
|
isActive: neverActive,
|
|
|
|
isDisabled: cellNotSelected,
|
|
|
|
};
|
|
|
|
|
|
|
|
export const cutColumn: EditorButtonDefinition = {
|
|
|
|
label: 'Cut column',
|
|
|
|
format: 'long',
|
|
|
|
action(context: EditorUiContext) {
|
|
|
|
context.editor.getEditorState().read(() => {
|
|
|
|
// TODO
|
|
|
|
});
|
|
|
|
},
|
|
|
|
isActive: neverActive,
|
|
|
|
isDisabled: cellNotSelected,
|
|
|
|
};
|
|
|
|
|
|
|
|
export const copyColumn: EditorButtonDefinition = {
|
|
|
|
label: 'Copy column',
|
|
|
|
format: 'long',
|
|
|
|
action(context: EditorUiContext) {
|
|
|
|
context.editor.getEditorState().read(() => {
|
|
|
|
// TODO
|
|
|
|
});
|
|
|
|
},
|
|
|
|
isActive: neverActive,
|
|
|
|
isDisabled: cellNotSelected,
|
|
|
|
};
|
|
|
|
|
|
|
|
export const pasteColumnBefore: EditorButtonDefinition = {
|
|
|
|
label: 'Paste column before',
|
|
|
|
format: 'long',
|
|
|
|
action(context: EditorUiContext) {
|
|
|
|
context.editor.getEditorState().read(() => {
|
|
|
|
// TODO
|
|
|
|
});
|
|
|
|
},
|
|
|
|
isActive: neverActive,
|
|
|
|
isDisabled: cellNotSelected,
|
|
|
|
};
|
|
|
|
|
|
|
|
export const pasteColumnAfter: EditorButtonDefinition = {
|
|
|
|
label: 'Paste column after',
|
|
|
|
format: 'long',
|
|
|
|
action(context: EditorUiContext) {
|
|
|
|
context.editor.getEditorState().read(() => {
|
|
|
|
// TODO
|
|
|
|
});
|
|
|
|
},
|
|
|
|
isActive: neverActive,
|
|
|
|
isDisabled: cellNotSelected,
|
2024-07-21 22:11:24 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2024-08-02 22:28:54 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
export const cellProperties: EditorButtonDefinition = {
|
|
|
|
label: 'Cell properties',
|
|
|
|
action(context: EditorUiContext) {
|
|
|
|
context.editor.getEditorState().read(() => {
|
|
|
|
const cell = $getNodeFromSelection($getSelection(), $isTableCellNode);
|
|
|
|
if ($isTableCellNode(cell)) {
|
|
|
|
|
|
|
|
const modalForm = context.manager.createModal('cell_properties');
|
|
|
|
modalForm.show({});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
2024-08-04 01:01:54 +08:00
|
|
|
isActive: neverActive,
|
|
|
|
isDisabled: cellNotSelected,
|
2024-08-02 22:28:54 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
export const mergeCells: EditorButtonDefinition = {
|
|
|
|
label: 'Merge cells',
|
|
|
|
action(context: EditorUiContext) {
|
|
|
|
context.editor.update(() => {
|
|
|
|
// Todo - Needs to be done manually
|
|
|
|
// Playground reference:
|
|
|
|
// https://github.com/facebook/lexical/blob/f373759a7849f473d34960a6bf4e34b2a011e762/packages/lexical-playground/src/plugins/TableActionMenuPlugin/index.tsx#L299
|
|
|
|
});
|
|
|
|
},
|
2024-08-04 01:01:54 +08:00
|
|
|
isActive: neverActive,
|
2024-08-02 22:28:54 +08:00
|
|
|
isDisabled(selection) {
|
|
|
|
return !$isTableSelection(selection);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
export const splitCell: EditorButtonDefinition = {
|
|
|
|
label: 'Split cell',
|
|
|
|
action(context: EditorUiContext) {
|
|
|
|
context.editor.update(() => {
|
|
|
|
$unmergeCell();
|
|
|
|
});
|
|
|
|
},
|
2024-08-04 01:01:54 +08:00
|
|
|
isActive: neverActive,
|
2024-08-02 22:28:54 +08:00
|
|
|
isDisabled(selection) {
|
|
|
|
const cell = $getNodeFromSelection(selection, $isTableCellNode) as TableCellNode|null;
|
|
|
|
if (cell) {
|
|
|
|
const merged = cell.getRowSpan() > 1 || cell.getColSpan() > 1;
|
|
|
|
return !merged;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2024-07-21 22:11:24 +08:00
|
|
|
};
|