"use client"; import { useEffect, useRef, useState, type ReactNode } from "react"; import { createPortal } from "react-dom"; import { DownloadIcon } from "lucide-react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { Spinner } from "@/components/ui/spinner"; import { cn } from "@/lib/utils"; const EXPORT_WIDTH = 1200; function downloadFileName(value: string): string { return value.replace(/[\\/:*?"<>|]/gu, "-"); } export function GuideImageExport({ children, fileName, width = EXPORT_WIDTH, height, format = "png", disabled = false, captureClassName, buttonLabel = "ส่งออกภาพ", }: { children: ReactNode; fileName: string; width?: number; height?: number; format?: "png" | "webp"; disabled?: boolean; captureClassName?: string; buttonLabel?: string; }) { const captureRef = useRef(null); const [capturing, setCapturing] = useState(false); useEffect(() => { if (!capturing) return; let cancelled = false; async function capture() { try { const node = captureRef.current; if (!node) throw new Error("Capture target is unavailable"); const { domToBlob, waitUntilLoad } = await import("modern-screenshot"); await Promise.all([document.fonts.ready, waitUntilLoad(node)]); const blob = await domToBlob(node, { backgroundColor: getComputedStyle(node).backgroundColor, type: `image/${format}`, scale: 1, width, height, }); if (cancelled) return; const url = URL.createObjectURL(blob); const link = document.createElement("a"); link.download = downloadFileName(fileName); link.href = url; document.body.append(link); link.click(); link.remove(); window.setTimeout(() => URL.revokeObjectURL(url), 0); } catch { if (!cancelled) toast.error("ส่งออกภาพไม่สำเร็จ กรุณาลองอีกครั้ง"); } finally { if (!cancelled) setCapturing(false); } } void capture(); return () => { cancelled = true; }; }, [capturing, fileName, format, height, width]); return ( <> {capturing ? createPortal( , document.body, ) : null} ); }