[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:
parent
48f1999c95
commit
7136b3129b
5 changed files with 64 additions and 7 deletions
|
|
@ -24,7 +24,7 @@ import { CORE_EXTENSIONS } from "@/constants/extension";
|
||||||
import { isCellSelection } from "@/extensions/table/table/utilities/helpers";
|
import { isCellSelection } from "@/extensions/table/table/utilities/helpers";
|
||||||
// types
|
// types
|
||||||
import { TEditorCommands } from "@/types";
|
import { TEditorCommands } from "@/types";
|
||||||
// local components
|
// local imports
|
||||||
import { TextAlignmentSelector } from "./alignment-selector";
|
import { TextAlignmentSelector } from "./alignment-selector";
|
||||||
|
|
||||||
type EditorBubbleMenuProps = Omit<BubbleMenuProps, "children">;
|
type EditorBubbleMenuProps = Omit<BubbleMenuProps, "children">;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,13 @@
|
||||||
import { mergeAttributes, Node } from "@tiptap/core";
|
import { mergeAttributes, Node } from "@tiptap/core";
|
||||||
|
import { TableMap } from "@tiptap/pm/tables";
|
||||||
// constants
|
// constants
|
||||||
import { CORE_EXTENSIONS } from "@/constants/extension";
|
import { CORE_EXTENSIONS } from "@/constants/extension";
|
||||||
|
// helpers
|
||||||
|
import { findParentNodeOfType } from "@/helpers/common";
|
||||||
// local imports
|
// local imports
|
||||||
import { TableCellSelectionOutlinePlugin } from "./plugins/selection-outline/plugin";
|
import { TableCellSelectionOutlinePlugin } from "./plugins/selection-outline/plugin";
|
||||||
import { DEFAULT_COLUMN_WIDTH } from "./table";
|
import { DEFAULT_COLUMN_WIDTH } from "./table";
|
||||||
|
import { isCellSelection } from "./table/utilities/helpers";
|
||||||
|
|
||||||
export interface TableCellOptions {
|
export interface TableCellOptions {
|
||||||
HTMLAttributes: Record<string, any>;
|
HTMLAttributes: Record<string, any>;
|
||||||
|
|
@ -54,6 +58,47 @@ export const TableCell = Node.create<TableCellOptions>({
|
||||||
return [TableCellSelectionOutlinePlugin(this.editor)];
|
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() {
|
parseHTML() {
|
||||||
return [{ tag: "td" }];
|
return [{ tag: "td" }];
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ export const insertLineAboveTableAction: KeyboardShortcutCommand = ({ editor })
|
||||||
const { selection } = editor.state;
|
const { selection } = editor.state;
|
||||||
|
|
||||||
// Find the table node and its position
|
// 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;
|
if (!tableNode) return false;
|
||||||
|
|
||||||
const tablePos = tableNode.pos;
|
const tablePos = tableNode.pos;
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ export const insertLineBelowTableAction: KeyboardShortcutCommand = ({ editor })
|
||||||
const { selection } = editor.state;
|
const { selection } = editor.state;
|
||||||
|
|
||||||
// Find the table node and its position
|
// 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;
|
if (!tableNode) return false;
|
||||||
|
|
||||||
const tablePos = tableNode.pos;
|
const tablePos = tableNode.pos;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import type { Node as ProseMirrorNode } from "@tiptap/pm/model";
|
||||||
import { EditorState, Selection } from "@tiptap/pm/state";
|
import { EditorState, Selection } from "@tiptap/pm/state";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { cn } from "@plane/utils";
|
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
|
// 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;
|
let depth = selection.$anchor.depth;
|
||||||
while (depth > 0) {
|
while (depth > 0) {
|
||||||
const node = selection.$anchor.node(depth);
|
const node = selection.$anchor.node(depth);
|
||||||
if (node.type.name === typeName) {
|
if (typeName.includes(node.type.name)) {
|
||||||
return { node, pos: selection.$anchor.start(depth) - 1 };
|
return {
|
||||||
|
node,
|
||||||
|
pos: selection.$anchor.start(depth) - 1,
|
||||||
|
depth,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
depth--;
|
depth--;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const findTableAncestor = (node: Node | null): HTMLTableElement | null => {
|
export const findTableAncestor = (node: Node | null): HTMLTableElement | null => {
|
||||||
while (node !== null && node.nodeName !== "TABLE") {
|
while (node !== null && node.nodeName !== "TABLE") {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue