import { type Component, createSignal, createEffect, For } from "solid-js"; import { Trash2, Type } from "lucide-solid"; import { cn } from "@/lib/utils"; import type { Editor } from "@tiptap/core"; // Custom Icons const AddRowAbove = () => ( ); const AddRowBelow = () => ( ); const AddColLeft = () => ( ); const AddColRight = () => ( ); const DeleteRow = () => ( ); const DeleteCol = () => ( ); const MergeCells = () => ( ); const SplitCell = () => ( ); interface TableAction { label: string; icon: Component; command: () => void; iconClass?: string; } interface TableGroup { name: string; actions: TableAction[]; } interface TableBubbleMenuProps { editor: Editor; } export const TableBubbleMenu: Component = (props) => { const [isVisible, setIsVisible] = createSignal(false); createEffect(() => { const updateVisibility = () => { const editor = props.editor; if (!editor) return; setIsVisible(editor.isActive("table")); }; props.editor.on("selectionUpdate", updateVisibility); props.editor.on("transaction", updateVisibility); return () => { props.editor.off("selectionUpdate", updateVisibility); props.editor.off("transaction", updateVisibility); }; }); const groups: TableGroup[] = [ { name: "Rows", actions: [ { label: "Insert Row Above", icon: AddRowAbove, command: () => props.editor.chain().focus().addRowBefore().run() }, { label: "Insert Row Below", icon: AddRowBelow, command: () => props.editor.chain().focus().addRowAfter().run() }, { label: "Delete Row", icon: DeleteRow, iconClass: "text-destructive", command: () => props.editor.chain().focus().deleteRow().run() }, ] }, { name: "Cols", actions: [ { label: "Insert Column Left", icon: AddColLeft, command: () => props.editor.chain().focus().addColumnBefore().run() }, { label: "Insert Column Right", icon: AddColRight, command: () => props.editor.chain().focus().addColumnAfter().run() }, { label: "Delete Column", icon: DeleteCol, iconClass: "text-destructive", command: () => props.editor.chain().focus().deleteColumn().run() }, ] }, { name: "Cells", actions: [ { label: "Merge Cells", icon: MergeCells, command: () => props.editor.chain().focus().mergeCells().run() }, { label: "Split Cell", icon: SplitCell, command: () => props.editor.chain().focus().splitCell().run() }, { label: "Header Row", icon: Type, command: () => props.editor.chain().focus().toggleHeaderRow().run() }, ] }, { name: "Table", actions: [ { label: "Delete Table", icon: Trash2, iconClass: "text-destructive", command: () => props.editor.chain().focus().deleteTable().run() }, ] } ]; return ( { e.preventDefault(); e.stopPropagation(); }} > {(group, groupIdx) => ( <> {(action) => ( { e.preventDefault(); e.stopPropagation(); action.command(); }} class={cn( "p-0.5 rounded-md hover:bg-muted transition-colors text-muted-foreground hover:text-foreground shrink-0 group relative", action.iconClass )} > {action.label} )} {groupIdx() < groups.length - 1 && ( )} > )} ); };