"use client"
import { memo, useCallback, useEffect, useState } from "react"
import { createPortal } from "react-dom"
import type { Editor } from "@tiptap/react"
import { Icon } from "@iconify/react"
import {
ArrowDownToLine,
ArrowUpToLine,
Columns2,
Merge,
PaintBucket,
Rows2,
Split,
Square,
Trash2,
} from "lucide-react"
import { Button } from "@/components/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import {
docsClearTableCellBorders,
docsDefaultTableBorder,
docsSetTableCellBackground,
docsSetTableCellBordersAll,
docsSetTableCellVerticalAlign,
docsTableActive,
docsTableCanMerge,
docsTableCanSplit,
} from "@/lib/drive/docs-table-actions"
import {
DOCS_TABLE_BORDER_COLOR_PRESETS,
DOCS_TABLE_CELL_BACKGROUND_PRESETS,
} from "@/lib/drive/docs-table-types"
import { cn } from "@/lib/utils"
function ToolbarDivider() {
return
}
function IconToolbarButton({
label,
disabled,
onClick,
children,
}: {
label: string
disabled?: boolean
onClick: () => void
children: React.ReactNode
}) {
return (
)
}
function DocsTableFloatingToolbarInner({
editor,
canvasRef,
disabled,
}: {
editor: Editor | null
canvasRef: React.RefObject
disabled?: boolean
}) {
const [rect, setRect] = useState(null)
const [, setTick] = useState(0)
const refresh = useCallback(() => {
setTick((value) => value + 1)
if (!editor || !docsTableActive(editor)) {
setRect(null)
return
}
const selectedCell = editor.view.dom.querySelector(
"td.selectedCell, th.selectedCell, .ProseMirror-selectednode table"
) as HTMLElement | null
const table =
selectedCell?.closest("table") ??
(editor.view.dom.querySelector(".ProseMirror-selectednode table") as HTMLElement | null)
if (!table) {
setRect(null)
return
}
setRect(table.getBoundingClientRect())
}, [editor])
useEffect(() => {
if (!editor) return
refresh()
editor.on("selectionUpdate", refresh)
editor.on("transaction", refresh)
const canvas = canvasRef.current
canvas?.addEventListener("scroll", refresh, { passive: true })
window.addEventListener("resize", refresh)
return () => {
editor.off("selectionUpdate", refresh)
editor.off("transaction", refresh)
canvas?.removeEventListener("scroll", refresh)
window.removeEventListener("resize", refresh)
}
}, [canvasRef, editor, refresh])
if (!editor || disabled || !docsTableActive(editor) || !rect) return null
const canMerge = docsTableCanMerge(editor)
const canSplit = docsTableCanSplit(editor)
const toolbar = (
editor.chain().focus().addRowBefore().run()}
>
editor.chain().focus().addRowAfter().run()}
>
editor.chain().focus().addColumnBefore().run()}
>
editor.chain().focus().addColumnAfter().run()}
>
editor.chain().focus().mergeCells().run()}
>
editor.chain().focus().splitCell().run()}
>
docsSetTableCellBordersAll(editor, docsDefaultTableBorder("#000000"))
}
>
Bordures noires
docsClearTableCellBorders(editor)}>
Supprimer les bordures
{DOCS_TABLE_BORDER_COLOR_PRESETS.slice(0, 6).map((color) => (
docsSetTableCellBordersAll(editor, docsDefaultTableBorder(color))
}
>
{color}
))}
{DOCS_TABLE_CELL_BACKGROUND_PRESETS.map((preset) => (
docsSetTableCellBackground(editor, preset.color || null)}
>
{preset.label}
))}
docsSetTableCellVerticalAlign(editor, "top")}>
Haut
docsSetTableCellVerticalAlign(editor, "middle")}>
Milieu
docsSetTableCellVerticalAlign(editor, "bottom")}>
Bas
editor.chain().focus().toggleHeaderRow().run()}>
Ligne d'en-tête
editor.chain().focus().toggleHeaderColumn().run()}>
Colonne d'en-tête
editor.chain().focus().deleteRow().run()}>
Supprimer la ligne
editor.chain().focus().deleteColumn().run()}>
Supprimer la colonne
editor.chain().focus().deleteTable().run()}
>
Supprimer le tableau
)
return createPortal(toolbar, document.body)
}
export const DocsTableFloatingToolbar = memo(DocsTableFloatingToolbarInner)