import React, { useCallback, useEffect, useState } from "react"; import { Editor } from "@tiptap/react"; import { ActionIcon, Button, Group, Paper, Text, Textarea, Tooltip, } from "@mantine/core"; import { IconAlt } from "@tabler/icons-react"; import { useTranslation } from "react-i18next"; const ALT_MAX_LENGTH = 300; function sanitizeAlt(value: string): string { return value .replace(/[\\\[\]!]/g, "") .replace(/\s+/g, " ") .trim(); } type UseAltTextControlArgs = { editor: Editor; nodeName: string; currentAlt: string; }; export function useAltTextControl({ editor, nodeName, currentAlt, }: UseAltTextControlArgs) { const { t } = useTranslation(); const [showInput, setShowInput] = useState(false); const [draft, setDraft] = useState(""); const open = useCallback(() => { setDraft(currentAlt || ""); setShowInput(true); }, [currentAlt]); useEffect(() => { const handler = () => { if (!editor.isActive(nodeName)) { setShowInput(false); } }; editor.on("selectionUpdate", handler); return () => { editor.off("selectionUpdate", handler); }; }, [editor, nodeName]); const cancel = useCallback(() => { setShowInput(false); }, []); const save = useCallback(() => { editor .chain() .focus(undefined, { scrollIntoView: false }) .updateAttributes(nodeName, { alt: sanitizeAlt(draft) || undefined }) .run(); setShowInput(false); }, [editor, nodeName, draft]); const onKeyDown = useCallback( (e: React.KeyboardEvent) => { if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) { e.preventDefault(); save(); } else if (e.key === "Escape") { e.preventDefault(); cancel(); } }, [save, cancel], ); const button = ( ); const panel = showInput ? ( {t("Alt text")} {t("Describe this for accessibility.")}