ultisuite-client/components/drive/richtext/docs-graphic-context-menu.tsx
R3D347HR4Y 2a7c153748
Some checks are pending
E2E / Playwright e2e (push) Waiting to run
wrap page
2026-06-10 12:48:27 +02:00

137 lines
4.3 KiB
TypeScript

"use client"
import type { Editor } from "@tiptap/react"
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuSeparator,
ContextMenuSub,
ContextMenuSubContent,
ContextMenuSubTrigger,
ContextMenuTrigger,
} from "@/components/ui/context-menu"
import {
DOCS_GRAPHIC_WRAP_LABELS,
parseGraphicAttrs,
type DocsGraphicWrap,
} from "@/lib/drive/docs-graphic-types"
export function DocsGraphicContextMenu({
editor,
children,
onCrop,
onOpenOptions,
onReplaceImage,
}: {
editor: Editor
children: React.ReactNode
onCrop?: () => void
onOpenOptions?: () => void
onReplaceImage?: () => void
}) {
const active =
editor.isActive("docsGraphic") || editor.isActive("docsInlineGraphic")
if (!active) return <>{children}</>
const name = editor.isActive("docsInlineGraphic") ? "docsInlineGraphic" : "docsGraphic"
const attrs = parseGraphicAttrs(editor.getAttributes(name) as Record<string, unknown>)
const isImage = attrs.graphicType === "image"
const applyWrap = (wrap: DocsGraphicWrap) => {
editor.chain().focus().setDocsGraphicWrap(wrap).run()
}
const downloadImage = () => {
if (!attrs.src) return
const link = document.createElement("a")
link.href = attrs.src
link.download = "image"
link.click()
}
return (
<ContextMenu>
<ContextMenuTrigger asChild>{children}</ContextMenuTrigger>
<ContextMenuContent className="min-w-52">
<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>
<ContextMenuSeparator />
{isImage ? (
<>
<ContextMenuItem onClick={onReplaceImage}>Remplacer l&apos;image</ContextMenuItem>
<ContextMenuItem onClick={onCrop}>Recadrer</ContextMenuItem>
<ContextMenuItem onClick={onOpenOptions}>Options image</ContextMenuItem>
<ContextMenuItem
onClick={() => {
const alt = window.prompt("Texte alternatif", attrs.alt)
if (alt != null) editor.chain().focus().updateDocsGraphic({ alt }).run()
}}
>
Texte alternatif
</ContextMenuItem>
<ContextMenuItem onClick={downloadImage} disabled={!attrs.src}>
Télécharger l&apos;image
</ContextMenuItem>
</>
) : attrs.graphicType === "shape" ? (
<>
<ContextMenuItem
onClick={() => {
const fill = window.prompt("Couleur de remplissage", attrs.fill)
if (fill) editor.chain().focus().updateDocsGraphic({ fill }).run()
}}
>
Modifier le remplissage
</ContextMenuItem>
<ContextMenuItem
onClick={() => {
const stroke = window.prompt("Couleur du contour", attrs.stroke)
if (stroke) editor.chain().focus().updateDocsGraphic({ stroke }).run()
}}
>
Modifier le contour
</ContextMenuItem>
</>
) : null}
<ContextMenuSeparator />
<ContextMenuSub>
<ContextMenuSubTrigger>Habillage texte</ContextMenuSubTrigger>
<ContextMenuSubContent>
{(Object.keys(DOCS_GRAPHIC_WRAP_LABELS) as DocsGraphicWrap[]).map((wrap) => (
<ContextMenuItem key={wrap} onClick={() => applyWrap(wrap)}>
{DOCS_GRAPHIC_WRAP_LABELS[wrap]}
</ContextMenuItem>
))}
</ContextMenuSubContent>
</ContextMenuSub>
<ContextMenuSeparator />
<ContextMenuItem onClick={() => editor.chain().focus().bringDocsGraphicForward().run()}>
Avancer
</ContextMenuItem>
<ContextMenuItem onClick={() => editor.chain().focus().sendDocsGraphicBackward().run()}>
Reculer
</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
)
}