[WIKI-543] fix: unable to delete last cell of a table (#7394)

* fix: delete last cell of a table

* refactor: last cell selection logic
This commit is contained in:
Aaryan Khandelwal
2025-07-17 21:19:54 +05:30
committed by GitHub
parent 48f1999c95
commit 7136b3129b
5 changed files with 64 additions and 7 deletions

View File

@@ -24,7 +24,7 @@ import { CORE_EXTENSIONS } from "@/constants/extension";
import { isCellSelection } from "@/extensions/table/table/utilities/helpers";
// types
import { TEditorCommands } from "@/types";
// local components
// local imports
import { TextAlignmentSelector } from "./alignment-selector";
type EditorBubbleMenuProps = Omit<BubbleMenuProps, "children">;

View File

@@ -1,9 +1,13 @@
import { mergeAttributes, Node } from "@tiptap/core";
import { TableMap } from "@tiptap/pm/tables";
// constants
import { CORE_EXTENSIONS } from "@/constants/extension";
// helpers
import { findParentNodeOfType } from "@/helpers/common";
// local imports
import { TableCellSelectionOutlinePlugin } from "./plugins/selection-outline/plugin";
import { DEFAULT_COLUMN_WIDTH } from "./table";
import { isCellSelection } from "./table/utilities/helpers";
export interface TableCellOptions {
HTMLAttributes: Record<string, any>;
@@ -54,6 +58,47 @@ export const TableCell = Node.create<TableCellOptions>({
return [TableCellSelectionOutlinePlugin(this.editor)];
},
addKeyboardShortcuts() {
return {
Backspace: ({ editor }) => {
const { state } = editor.view;
const { selection } = state;
if (isCellSelection(selection)) return false;
// Check if we're at the start of the cell
if (selection.from !== selection.to || selection.$head.parentOffset !== 0) return false;
// Find table and current cell
const tableNode = findParentNodeOfType(selection, [CORE_EXTENSIONS.TABLE])?.node;
const currentCellInfo = findParentNodeOfType(selection, [
CORE_EXTENSIONS.TABLE_CELL,
CORE_EXTENSIONS.TABLE_HEADER,
]);
const currentCellNode = currentCellInfo?.node;
const cellPos = currentCellInfo?.pos;
const cellDepth = currentCellInfo?.depth;
if (!tableNode || !currentCellNode || cellPos === null || cellDepth === null) return false;
// Check if this is the only cell in the TableMap (1 row, 1 column)
const tableMap = TableMap.get(tableNode);
const isOnlyCell = tableMap.width === 1 && tableMap.height === 1;
if (!isOnlyCell) return false;
// Cell has content, select the entire cell
// Use the position that points to the cell node itself, not its content
const cellNodePos = selection.$head.before(cellDepth);
editor.commands.setCellSelection({
anchorCell: cellNodePos,
headCell: cellNodePos,
});
return true;
},
};
},
parseHTML() {
return [{ tag: "td" }];
},

View File

@@ -13,7 +13,7 @@ export const insertLineAboveTableAction: KeyboardShortcutCommand = ({ editor })
const { selection } = editor.state;
// Find the table node and its position
const tableNode = findParentNodeOfType(selection, CORE_EXTENSIONS.TABLE);
const tableNode = findParentNodeOfType(selection, [CORE_EXTENSIONS.TABLE]);
if (!tableNode) return false;
const tablePos = tableNode.pos;

View File

@@ -13,7 +13,7 @@ export const insertLineBelowTableAction: KeyboardShortcutCommand = ({ editor })
const { selection } = editor.state;
// Find the table node and its position
const tableNode = findParentNodeOfType(selection, CORE_EXTENSIONS.TABLE);
const tableNode = findParentNodeOfType(selection, [CORE_EXTENSIONS.TABLE]);
if (!tableNode) return false;
const tablePos = tableNode.pos;

View File

@@ -1,3 +1,4 @@
import type { Node as ProseMirrorNode } from "@tiptap/pm/model";
import { EditorState, Selection } from "@tiptap/pm/state";
// plane imports
import { cn } from "@plane/utils";
@@ -21,17 +22,28 @@ export const getEditorClassNames = ({ noBorder, borderOnFocus, containerClassNam
);
// Helper function to find the parent node of a specific type
export function findParentNodeOfType(selection: Selection, typeName: string) {
export const findParentNodeOfType = (
selection: Selection,
typeName: string[]
): {
node: ProseMirrorNode;
pos: number;
depth: number;
} | null => {
let depth = selection.$anchor.depth;
while (depth > 0) {
const node = selection.$anchor.node(depth);
if (node.type.name === typeName) {
return { node, pos: selection.$anchor.start(depth) - 1 };
if (typeName.includes(node.type.name)) {
return {
node,
pos: selection.$anchor.start(depth) - 1,
depth,
};
}
depth--;
}
return null;
}
};
export const findTableAncestor = (node: Node | null): HTMLTableElement | null => {
while (node !== null && node.nodeName !== "TABLE") {