diff --git a/packages/editor/src/core/components/menus/bubble-menu/root.tsx b/packages/editor/src/core/components/menus/bubble-menu/root.tsx index 3a557921811..05e8911491c 100644 --- a/packages/editor/src/core/components/menus/bubble-menu/root.tsx +++ b/packages/editor/src/core/components/menus/bubble-menu/root.tsx @@ -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; diff --git a/packages/editor/src/core/extensions/table/table-cell.ts b/packages/editor/src/core/extensions/table/table-cell.ts index a9c98717bef..42fd3c7df5b 100644 --- a/packages/editor/src/core/extensions/table/table-cell.ts +++ b/packages/editor/src/core/extensions/table/table-cell.ts @@ -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; @@ -54,6 +58,47 @@ export const TableCell = Node.create({ 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" }]; }, diff --git a/packages/editor/src/core/extensions/table/table/utilities/insert-line-above-table-action.ts b/packages/editor/src/core/extensions/table/table/utilities/insert-line-above-table-action.ts index 35c2ee3c713..9a50a839c46 100644 --- a/packages/editor/src/core/extensions/table/table/utilities/insert-line-above-table-action.ts +++ b/packages/editor/src/core/extensions/table/table/utilities/insert-line-above-table-action.ts @@ -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; diff --git a/packages/editor/src/core/extensions/table/table/utilities/insert-line-below-table-action.ts b/packages/editor/src/core/extensions/table/table/utilities/insert-line-below-table-action.ts index 6c26e22a2f6..b30b8ae4dd6 100644 --- a/packages/editor/src/core/extensions/table/table/utilities/insert-line-below-table-action.ts +++ b/packages/editor/src/core/extensions/table/table/utilities/insert-line-below-table-action.ts @@ -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; diff --git a/packages/editor/src/core/helpers/common.ts b/packages/editor/src/core/helpers/common.ts index e694e1e8539..301d81917a3 100644 --- a/packages/editor/src/core/helpers/common.ts +++ b/packages/editor/src/core/helpers/common.ts @@ -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") {