ultisuite-client/components/drive/richtext/docs-table-context-menu.tsx
R3D347HR4Y 303b2b1074
Some checks are pending
E2E / Playwright e2e (push) Waiting to run
wow
2026-06-11 01:22:40 +02:00

247 lines
8.5 KiB
TypeScript

"use client"
import { useRef, useState } from "react"
import type { Editor } from "@tiptap/react"
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuSeparator,
ContextMenuSub,
ContextMenuSubContent,
ContextMenuSubTrigger,
ContextMenuTrigger,
} from "@/components/ui/context-menu"
import { focusEditorAtPointer } from "@/lib/drive/focus-editor-at-pointer"
import {
docsClearTableCellBorders,
docsDefaultTableBorder,
docsSetTableAlignment,
docsSetTableCellBackground,
docsSetTableCellBordersAll,
docsSetTableCellVerticalAlign,
docsSetTableRowHeight,
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"
export function DocsTableContextMenu({
editor,
disabled,
children,
}: {
editor: Editor
disabled?: boolean
children: React.ReactNode
}) {
const pointerRef = useRef<{ x: number; y: number } | null>(null)
const [tableMenuActive, setTableMenuActive] = useState(false)
const refreshTableMenuState = () => {
const point = pointerRef.current
if (point) focusEditorAtPointer(editor, point.x, point.y)
setTableMenuActive(editor.isActive("table"))
}
const canMerge = tableMenuActive && docsTableCanMerge(editor)
const canSplit = tableMenuActive && docsTableCanSplit(editor)
return (
<ContextMenu
onOpenChange={(open) => {
if (open) refreshTableMenuState()
else setTableMenuActive(false)
}}
>
<ContextMenuTrigger
asChild
disabled={disabled}
onContextMenu={(event) => {
pointerRef.current = { x: event.clientX, y: event.clientY }
}}
>
{children}
</ContextMenuTrigger>
<ContextMenuContent
className="min-w-56"
onCloseAutoFocus={(event) => event.preventDefault()}
>
<ContextMenuItem onClick={() => document.execCommand("cut")}>
Couper
</ContextMenuItem>
<ContextMenuItem onClick={() => document.execCommand("copy")}>
Copier
</ContextMenuItem>
<ContextMenuItem onClick={() => document.execCommand("paste")}>
Coller
</ContextMenuItem>
<ContextMenuItem
onClick={() => editor.chain().focus().deleteSelection().run()}
>
Supprimer
</ContextMenuItem>
{tableMenuActive ? (
<>
<ContextMenuSeparator />
<ContextMenuItem
onClick={() => editor.chain().focus().addRowBefore().run()}
>
Insérer une ligne au-dessus
</ContextMenuItem>
<ContextMenuItem
onClick={() => editor.chain().focus().addRowAfter().run()}
>
Insérer une ligne en dessous
</ContextMenuItem>
<ContextMenuItem
onClick={() => editor.chain().focus().addColumnBefore().run()}
>
Insérer une colonne à gauche
</ContextMenuItem>
<ContextMenuItem
onClick={() => editor.chain().focus().addColumnAfter().run()}
>
Insérer une colonne à droite
</ContextMenuItem>
<ContextMenuSeparator />
<ContextMenuItem
disabled={!canMerge}
onClick={() => editor.chain().focus().mergeCells().run()}
>
Fusionner les cellules
</ContextMenuItem>
<ContextMenuItem
disabled={!canSplit}
onClick={() => editor.chain().focus().splitCell().run()}
>
Scinder la cellule
</ContextMenuItem>
<ContextMenuSeparator />
<ContextMenuSub>
<ContextMenuSubTrigger>Couleur de cellule</ContextMenuSubTrigger>
<ContextMenuSubContent>
{DOCS_TABLE_CELL_BACKGROUND_PRESETS.map((preset) => (
<ContextMenuItem
key={preset.id || "none"}
onClick={() =>
docsSetTableCellBackground(editor, preset.color || null)
}
>
{preset.label}
</ContextMenuItem>
))}
</ContextMenuSubContent>
</ContextMenuSub>
<ContextMenuSub>
<ContextMenuSubTrigger>Bordures</ContextMenuSubTrigger>
<ContextMenuSubContent>
<ContextMenuItem
onClick={() =>
docsSetTableCellBordersAll(editor, docsDefaultTableBorder("#000000"))
}
>
Bordures noires
</ContextMenuItem>
<ContextMenuItem onClick={() => docsClearTableCellBorders(editor)}>
Supprimer les bordures
</ContextMenuItem>
{DOCS_TABLE_BORDER_COLOR_PRESETS.slice(0, 6).map((color) => (
<ContextMenuItem
key={color}
onClick={() =>
docsSetTableCellBordersAll(editor, docsDefaultTableBorder(color))
}
>
{color}
</ContextMenuItem>
))}
</ContextMenuSubContent>
</ContextMenuSub>
<ContextMenuSub>
<ContextMenuSubTrigger>Alignement vertical</ContextMenuSubTrigger>
<ContextMenuSubContent>
<ContextMenuItem
onClick={() => docsSetTableCellVerticalAlign(editor, "top")}
>
Haut
</ContextMenuItem>
<ContextMenuItem
onClick={() => docsSetTableCellVerticalAlign(editor, "middle")}
>
Milieu
</ContextMenuItem>
<ContextMenuItem
onClick={() => docsSetTableCellVerticalAlign(editor, "bottom")}
>
Bas
</ContextMenuItem>
</ContextMenuSubContent>
</ContextMenuSub>
<ContextMenuSub>
<ContextMenuSubTrigger>Alignement du tableau</ContextMenuSubTrigger>
<ContextMenuSubContent>
<ContextMenuItem onClick={() => docsSetTableAlignment(editor, "left")}>
Gauche
</ContextMenuItem>
<ContextMenuItem onClick={() => docsSetTableAlignment(editor, "center")}>
Centre
</ContextMenuItem>
<ContextMenuItem onClick={() => docsSetTableAlignment(editor, "right")}>
Droite
</ContextMenuItem>
</ContextMenuSubContent>
</ContextMenuSub>
<ContextMenuSub>
<ContextMenuSubTrigger>Hauteur de ligne</ContextMenuSubTrigger>
<ContextMenuSubContent>
<ContextMenuItem onClick={() => docsSetTableRowHeight(editor, "32px")}>
Compacte
</ContextMenuItem>
<ContextMenuItem onClick={() => docsSetTableRowHeight(editor, "48px")}>
Normale
</ContextMenuItem>
<ContextMenuItem onClick={() => docsSetTableRowHeight(editor, null)}>
Automatique
</ContextMenuItem>
</ContextMenuSubContent>
</ContextMenuSub>
<ContextMenuSeparator />
<ContextMenuItem
onClick={() => editor.chain().focus().toggleHeaderRow().run()}
>
Ligne d&apos;en-tête
</ContextMenuItem>
<ContextMenuItem
onClick={() => editor.chain().focus().toggleHeaderColumn().run()}
>
Colonne d&apos;en-tête
</ContextMenuItem>
<ContextMenuSeparator />
<ContextMenuItem
onClick={() => editor.chain().focus().deleteRow().run()}
>
Supprimer la ligne
</ContextMenuItem>
<ContextMenuItem
onClick={() => editor.chain().focus().deleteColumn().run()}
>
Supprimer la colonne
</ContextMenuItem>
<ContextMenuItem
className="text-destructive focus:text-destructive"
onClick={() => editor.chain().focus().deleteTable().run()}
>
Supprimer le tableau
</ContextMenuItem>
</>
) : null}
</ContextMenuContent>
</ContextMenu>
)
}