import { posToDOMRect, findParentNode } from "@tiptap/react"; import { Node as PMNode } from "@tiptap/pm/model"; import React, { useCallback } from "react"; import { EditorMenuProps, ShouldShowProps, } from "@/features/editor/components/table/types/types.ts"; import { ActionIcon, Tooltip } from "@mantine/core"; import { IconColumnInsertLeft, IconColumnInsertRight, IconColumnRemove, IconRowInsertBottom, IconRowInsertTop, IconRowRemove, IconTableColumn, IconTableRow, IconTrashX, } from "@tabler/icons-react"; import { BubbleMenu } from "@tiptap/react/menus"; import { isCellSelection, isTextSelected } from "@docmost/editor-ext"; import { useTranslation } from "react-i18next"; import classes from "../common/toolbar-menu.module.css"; export const TableMenu = React.memo( ({ editor }: EditorMenuProps): JSX.Element => { const { t } = useTranslation(); const shouldShow = useCallback( ({ state }: ShouldShowProps) => { if (!state) { return false; } if (isTextSelected(editor)) return false; return editor.isActive("table") && !isCellSelection(state.selection); }, [editor], ); const getReferencedVirtualElement = useCallback(() => { const { selection } = editor.state; const predicate = (node: PMNode) => node.type.name === "table"; const parent = findParentNode(predicate)(selection); if (parent) { const dom = editor.view.nodeDOM(parent?.pos) as HTMLElement; const rect = dom.getBoundingClientRect(); return { getBoundingClientRect: () => rect, getClientRects: () => [rect], }; } const rect = posToDOMRect(editor.view, selection.from, selection.to); return { getBoundingClientRect: () => rect, getClientRects: () => [rect], }; }, [editor]); const toggleHeaderColumn = useCallback(() => { editor.chain().focus().toggleHeaderColumn().run(); }, [editor]); const toggleHeaderRow = useCallback(() => { editor.chain().focus().toggleHeaderRow().run(); }, [editor]); const addColumnLeft = useCallback(() => { editor.chain().focus().addColumnBefore().run(); }, [editor]); const addColumnRight = useCallback(() => { editor.chain().focus().addColumnAfter().run(); }, [editor]); const deleteColumn = useCallback(() => { editor.chain().focus().deleteColumn().run(); }, [editor]); const addRowAbove = useCallback(() => { editor.chain().focus().addRowBefore().run(); }, [editor]); const addRowBelow = useCallback(() => { editor.chain().focus().addRowAfter().run(); }, [editor]); const deleteRow = useCallback(() => { editor.chain().focus().deleteRow().run(); }, [editor]); const deleteTable = useCallback(() => { editor.chain().focus().deleteTable().run(); }, [editor]); return ( { element.style.zIndex = "99"; }} options={{ placement: "bottom", offset: { mainAxis: 15, }, flip: { fallbackPlacements: ["bottom", "top"], padding: { top: 35 + 15, left: 8, right: 8, bottom: -Infinity }, boundary: editor.options.element as HTMLElement, }, shift: { padding: 8 + 15, crossAxis: true, }, }} shouldShow={shouldShow} >
); }, ); export default TableMenu;