"use client"; import { useCallback, useState } from "react"; import { Handle, NodeResizer, Position, type NodeProps } from "@xyflow/react"; import { useAction, useMutation } from "convex/react"; import { Download, Loader2 } from "lucide-react"; import { api } from "@/convex/_generated/api"; import type { Id } from "@/convex/_generated/dataModel"; import { useDebouncedCallback } from "@/hooks/use-debounced-callback"; import BaseNodeWrapper from "./base-node-wrapper"; interface FrameNodeData { label?: string; width?: number; height?: number; } export default function FrameNode({ id, data, selected, width, height }: NodeProps) { const nodeData = data as FrameNodeData; const updateData = useMutation(api.nodes.updateData); const exportFrame = useAction(api.export.exportFrame); const [label, setLabel] = useState(nodeData.label ?? "Frame"); const [isExporting, setIsExporting] = useState(false); const [exportError, setExportError] = useState(null); const debouncedSave = useDebouncedCallback((value: string) => { void updateData({ nodeId: id as Id<"nodes">, data: { ...nodeData, label: value } }); }, 500); const handleLabelChange = useCallback( (event: React.ChangeEvent) => { setLabel(event.target.value); debouncedSave(event.target.value); }, [debouncedSave], ); const handleExport = useCallback(async () => { if (isExporting) return; setIsExporting(true); setExportError(null); try { const result = await exportFrame({ frameNodeId: id as Id<"nodes"> }); const a = document.createElement("a"); a.href = result.url; a.download = result.filename; a.click(); } catch (error) { setExportError(error instanceof Error ? error.message : "Export failed"); } finally { setIsExporting(false); } }, [exportFrame, id, isExporting]); const frameW = Math.round(width ?? 400); const frameH = Math.round(height ?? 300); return (
{ if (event.key === "Enter") { (event.target as HTMLInputElement).blur(); } }} className="nodrag nowheel w-40 border-none bg-transparent text-sm font-medium text-muted-foreground outline-none focus:text-foreground" /> {frameW}x{frameH}
{exportError && (
{exportError}
)}
); }