247 lines
8.5 KiB
TypeScript
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'en-tête
|
|
</ContextMenuItem>
|
|
<ContextMenuItem
|
|
onClick={() => editor.chain().focus().toggleHeaderColumn().run()}
|
|
>
|
|
Colonne d'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>
|
|
)
|
|
}
|