[WIKI-718] feat: add full width options in table block menu (#8087)

This commit is contained in:
Vipin Chaudhary 2025-11-13 14:46:27 +05:30 committed by GitHub
parent cbfdcd5638
commit f4c2d519fc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 98 additions and 7 deletions

View file

@ -0,0 +1,87 @@
import type { Node as ProseMirrorNode } from "@tiptap/pm/model";
import { TableMap } from "@tiptap/pm/tables";
import type { Editor } from "@tiptap/react";
import { MoveHorizontal } from "lucide-react";
// constants
import { CORE_EXTENSIONS } from "@/constants/extension";
// types
import type { BlockMenuOption } from "./block-menu";
const findSelectedTable = (editor: Editor): { tableNode: ProseMirrorNode | null; tablePos: number } => {
const { state } = editor;
const selectedNode = state.selection.content().content.firstChild;
if (selectedNode?.type.name === CORE_EXTENSIONS.TABLE) {
return {
tableNode: selectedNode,
tablePos: state.selection.from,
};
}
return { tableNode: null, tablePos: -1 };
};
const setTableToFullWidth = (editor: Editor): void => {
try {
const { state, view } = editor;
// Find the selected table
const { tableNode, tablePos } = findSelectedTable(editor);
if (!tableNode) return;
// Get content width from CSS variable
const editorContainer = view.dom.closest(".editor-container");
if (!editorContainer) return;
const contentWidthVar = getComputedStyle(editorContainer).getPropertyValue("--editor-content-width").trim();
if (!contentWidthVar) return;
const contentWidth = parseInt(contentWidthVar);
if (isNaN(contentWidth) || contentWidth <= 0) return;
// Calculate equal width for each column
const map = TableMap.get(tableNode);
const equalWidth = Math.floor(contentWidth / map.width);
// Update all cell widths
const tr = state.tr;
const tableStart = tablePos + 1;
const updatedCells = new Set<number>();
for (let row = 0; row < map.height; row++) {
for (let col = 0; col < map.width; col++) {
const cellIndex = row * map.width + col;
const cellPos = map.map[cellIndex];
// Skip if cell already updated (for merged cells)
if (updatedCells.has(cellPos)) continue;
const cell = state.doc.nodeAt(tableStart + cellPos);
if (!cell) continue;
// Handle colspan for merged cells
const colspan = cell.attrs.colspan || 1;
tr.setNodeMarkup(tableStart + cellPos, null, {
...cell.attrs,
colwidth: Array(colspan).fill(equalWidth),
});
updatedCells.add(cellPos);
}
}
view.dispatch(tr);
} catch (error) {
console.error("Error setting table to full width:", error);
}
};
export const getNodeOptions = (editor: Editor): BlockMenuOption[] => [
{
icon: MoveHorizontal,
key: "table-full-width",
label: "Fit to width",
isDisabled: !editor.isActive(CORE_EXTENSIONS.TABLE),
onClick: () => setTableToFullWidth(editor),
},
];

View file

@ -16,12 +16,21 @@ import { cn } from "@plane/utils";
import { CORE_EXTENSIONS } from "@/constants/extension";
// types
import type { IEditorProps } from "@/types";
// components
import { getNodeOptions } from "./block-menu-options";
type Props = {
disabledExtensions?: IEditorProps["disabledExtensions"];
editor: Editor;
flaggedExtensions?: IEditorProps["flaggedExtensions"];
};
export type BlockMenuOption = {
icon: LucideIcon;
key: string;
label: string;
onClick: (e: React.MouseEvent) => void;
isDisabled?: boolean;
};
export const BlockMenu = (props: Props) => {
const { editor } = props;
@ -130,13 +139,7 @@ export const BlockMenu = (props: Props) => {
}
}, [isOpen]);
const MENU_ITEMS: {
icon: LucideIcon;
key: string;
label: string;
onClick: (e: React.MouseEvent) => void;
isDisabled?: boolean;
}[] = [
const MENU_ITEMS: BlockMenuOption[] = [
{
icon: Trash2,
key: "delete",
@ -189,6 +192,7 @@ export const BlockMenu = (props: Props) => {
}
},
},
...getNodeOptions(editor),
];
if (!isOpen) {