Add split cells action

Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
Émile Ré
2026-03-25 16:09:42 +04:00
parent 935e650991
commit 48fbca6b04
2 changed files with 34 additions and 3 deletions

View File

@@ -17,7 +17,7 @@ import { Strike } from "@tiptap/extension-strike";
import { TableKit } from "@tiptap/extension-table";
import { Text } from "@tiptap/extension-text";
import { Underline } from "@tiptap/extension-underline";
import { Dropcursor, Gapcursor, UndoRedo } from "@tiptap/extensions";
import { Dropcursor, UndoRedo } from "@tiptap/extensions";
import { type Content, EditorContent, useEditor, useEditorState } from "@tiptap/react";
import { type ComponentProps, useEffect, useRef } from "react";
import { tv } from "tailwind-variants";
@@ -59,7 +59,6 @@ const extensions = [
color: "#0081f1",
width: 2,
}),
Gapcursor,
UndoRedo,
TableKit.configure({
table: { resizable: true },

View File

@@ -12,7 +12,7 @@ import {
useFloatingRootContext,
useInteractions,
} from "@floating-ui/react";
import { BroomIcon, CircleIcon, DotsThreeCircleVerticalIcon, IntersectIcon } from "@phosphor-icons/react";
import { BroomIcon, CircleIcon, DotsThreeCircleVerticalIcon, IntersectIcon, SplitHorizontalIcon } from "@phosphor-icons/react";
import { TextSelection } from "@tiptap/pm/state";
import { cellAround, CellSelection, TableMap } from "@tiptap/pm/tables";
import { type useEditor, useEditorState } from "@tiptap/react";
@@ -263,6 +263,32 @@ export function TableCellMenu({ editor }: TableCellMenuProps) {
setMenuOpen(false);
};
const hasSpannedCell = (): boolean => {
const { selection } = editor.state;
if (selection instanceof CellSelection) {
let found = false;
selection.forEachCell((node) => {
if (node.attrs.colspan > 1 || node.attrs.rowspan > 1) {
found = true;
}
});
return found;
}
const $pos = editor.state.doc.resolve(selection.from);
const cell = cellAround($pos);
if (!cell) return false;
const cellNode = editor.state.doc.nodeAt(cell.pos);
if (!cellNode) return false;
return cellNode.attrs.colspan > 1 || cellNode.attrs.rowspan > 1;
};
const handleSplitCell = () => {
editor.chain().focus().splitCell().run();
setMenuOpen(false);
};
const handleClearContents = () => {
const { state, dispatch } = editor.view;
const { selection, schema } = state;
@@ -346,6 +372,12 @@ export function TableCellMenu({ editor }: TableCellMenuProps) {
<IntersectIcon size={16} weight="bold" />
Merge cells
</MenuButton>
{hasSpannedCell() && (
<MenuButton onClick={handleSplitCell}>
<SplitHorizontalIcon size={16} weight="bold" />
Split cells
</MenuButton>
)}
<MenuButton onClick={handleClearContents}>
<BroomIcon size={16} weight="bold" />
Clear contents