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, $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} from "../forms/tables";
24 import {$mergeTableCellsInSelection} from "../../../utils/tables";
26 const neverActive = (): boolean => false;
27 const cellNotSelected = (selection: BaseSelection|null) => !$selectionContainsNodeType(selection, $isCustomTableCellNode);
29 export const table: EditorBasicButtonDefinition = {
34 export const tableProperties: EditorButtonDefinition = {
35 label: 'Table properties',
37 action(context: EditorUiContext) {
38 context.editor.getEditorState().read(() => {
39 const cell = $getNodeFromSelection($getSelection(), $isCustomTableCellNode);
40 if (!$isCustomTableCellNode(cell)) {
44 const table = $getParentOfType(cell, $isTableNode);
45 const modalForm = context.manager.createModal('table_properties');
50 isActive: neverActive,
51 isDisabled: cellNotSelected,
54 export const clearTableFormatting: EditorButtonDefinition = {
55 label: 'Clear table formatting',
57 action(context: EditorUiContext) {
58 context.editor.getEditorState().read(() => {
59 const cell = $getNodeFromSelection($getSelection(), $isCustomTableCellNode);
60 if (!$isCustomTableCellNode(cell)) {
64 const table = $getParentOfType(cell, $isTableNode);
68 isActive: neverActive,
69 isDisabled: cellNotSelected,
72 export const resizeTableToContents: EditorButtonDefinition = {
73 label: 'Resize to contents',
75 action(context: EditorUiContext) {
76 context.editor.getEditorState().read(() => {
77 const cell = $getNodeFromSelection($getSelection(), $isCustomTableCellNode);
78 if (!$isCustomTableCellNode(cell)) {
82 const table = $getParentOfType(cell, $isCustomTableNode);
83 if (!$isCustomTableNode(table)) {
87 for (const row of table.getChildren()) {
88 if ($isTableRowNode(row)) {
89 // TODO - Come back later as this may depend on if we
90 // are using a custom table row
95 isActive: neverActive,
96 isDisabled: cellNotSelected,
99 export const deleteTable: EditorButtonDefinition = {
100 label: 'Delete table',
102 action(context: EditorUiContext) {
103 context.editor.update(() => {
104 const table = $getNodeFromSelection($getSelection(), $isCustomTableNode);
115 export const deleteTableMenuAction: EditorButtonDefinition = {
118 isDisabled(selection) {
119 return !$selectionContainsNodeType(selection, $isTableNode);
123 export const insertRowAbove: EditorButtonDefinition = {
124 label: 'Insert row before',
125 icon: insertRowAboveIcon,
126 action(context: EditorUiContext) {
127 context.editor.update(() => {
128 $insertTableRow__EXPERIMENTAL(false);
131 isActive: neverActive,
132 isDisabled: cellNotSelected,
135 export const insertRowBelow: EditorButtonDefinition = {
136 label: 'Insert row after',
137 icon: insertRowBelowIcon,
138 action(context: EditorUiContext) {
139 context.editor.update(() => {
140 $insertTableRow__EXPERIMENTAL(true);
143 isActive: neverActive,
144 isDisabled: cellNotSelected,
147 export const deleteRow: EditorButtonDefinition = {
150 action(context: EditorUiContext) {
151 context.editor.update(() => {
152 $deleteTableRow__EXPERIMENTAL();
155 isActive: neverActive,
156 isDisabled: cellNotSelected,
159 export const rowProperties: EditorButtonDefinition = {
160 label: 'Row properties',
162 action(context: EditorUiContext) {
163 context.editor.getEditorState().read(() => {
164 const cell = $getNodeFromSelection($getSelection(), $isCustomTableCellNode);
165 if (!$isCustomTableCellNode(cell)) {
169 const row = $getParentOfType(cell, $isTableRowNode);
170 const modalForm = context.manager.createModal('row_properties');
175 isActive: neverActive,
176 isDisabled: cellNotSelected,
179 export const cutRow: EditorButtonDefinition = {
182 action(context: EditorUiContext) {
183 context.editor.getEditorState().read(() => {
187 isActive: neverActive,
188 isDisabled: cellNotSelected,
191 export const copyRow: EditorButtonDefinition = {
194 action(context: EditorUiContext) {
195 context.editor.getEditorState().read(() => {
199 isActive: neverActive,
200 isDisabled: cellNotSelected,
203 export const pasteRowBefore: EditorButtonDefinition = {
204 label: 'Paste row before',
206 action(context: EditorUiContext) {
207 context.editor.getEditorState().read(() => {
211 isActive: neverActive,
212 isDisabled: cellNotSelected,
215 export const pasteRowAfter: EditorButtonDefinition = {
216 label: 'Paste row after',
218 action(context: EditorUiContext) {
219 context.editor.getEditorState().read(() => {
223 isActive: neverActive,
224 isDisabled: cellNotSelected,
227 export const cutColumn: EditorButtonDefinition = {
230 action(context: EditorUiContext) {
231 context.editor.getEditorState().read(() => {
235 isActive: neverActive,
236 isDisabled: cellNotSelected,
239 export const copyColumn: EditorButtonDefinition = {
240 label: 'Copy column',
242 action(context: EditorUiContext) {
243 context.editor.getEditorState().read(() => {
247 isActive: neverActive,
248 isDisabled: cellNotSelected,
251 export const pasteColumnBefore: EditorButtonDefinition = {
252 label: 'Paste column before',
254 action(context: EditorUiContext) {
255 context.editor.getEditorState().read(() => {
259 isActive: neverActive,
260 isDisabled: cellNotSelected,
263 export const pasteColumnAfter: EditorButtonDefinition = {
264 label: 'Paste column after',
266 action(context: EditorUiContext) {
267 context.editor.getEditorState().read(() => {
271 isActive: neverActive,
272 isDisabled: cellNotSelected,
275 export const insertColumnBefore: EditorButtonDefinition = {
276 label: 'Insert column before',
277 icon: insertColumnBeforeIcon,
278 action(context: EditorUiContext) {
279 context.editor.update(() => {
280 $insertTableColumn__EXPERIMENTAL(false);
288 export const insertColumnAfter: EditorButtonDefinition = {
289 label: 'Insert column after',
290 icon: insertColumnAfterIcon,
291 action(context: EditorUiContext) {
292 context.editor.update(() => {
293 $insertTableColumn__EXPERIMENTAL(true);
301 export const deleteColumn: EditorButtonDefinition = {
302 label: 'Delete column',
303 icon: deleteColumnIcon,
304 action(context: EditorUiContext) {
305 context.editor.update(() => {
306 $deleteTableColumn__EXPERIMENTAL();
314 export const cellProperties: EditorButtonDefinition = {
315 label: 'Cell properties',
316 action(context: EditorUiContext) {
317 context.editor.getEditorState().read(() => {
318 const cell = $getNodeFromSelection($getSelection(), $isCustomTableCellNode);
319 if ($isCustomTableCellNode(cell)) {
320 $showCellPropertiesForm(cell, context);
324 isActive: neverActive,
325 isDisabled: cellNotSelected,
328 export const mergeCells: EditorButtonDefinition = {
329 label: 'Merge cells',
330 action(context: EditorUiContext) {
331 context.editor.update(() => {
332 const selection = $getSelection();
333 if ($isTableSelection(selection)) {
334 $mergeTableCellsInSelection(selection);
338 isActive: neverActive,
339 isDisabled(selection) {
340 return !$isTableSelection(selection);
344 export const splitCell: EditorButtonDefinition = {
346 action(context: EditorUiContext) {
347 context.editor.update(() => {
351 isActive: neverActive,
352 isDisabled(selection) {
353 const cell = $getNodeFromSelection(selection, $isCustomTableCellNode) as TableCellNode|null;
355 const merged = cell.getRowSpan() > 1 || cell.getColSpan() > 1;