"use client"; import { Check, CircleAlert, RotateCcw } from "lucide-react"; import { AnimatePresence, motion, useReducedMotion } from "motion/react"; import type { CSSProperties, ReactNode } from "react"; import { useEffect, useRef } from "react"; import { EASE_IN_OUT, EASE_OUT, SPRING_PRESS } from "@/lib/ease"; import { useHoverCapable } from "@/lib/hooks/use-hover-capable"; import { cn } from "@/lib/utils"; export type ImageGenerationStatus = | "queued" | "generating" | "refining" | "complete" | "error"; export interface ImageGenerationProps { /** The completed media. Pass an img, Next Image, canvas, video, or custom preview. */ children?: ReactNode; status?: ImageGenerationStatus; /** Accessible description. Defaults to a description derived from prompt. */ label?: string; prompt?: string; resolution?: string; /** CSS aspect ratio reserved before generated media is available. */ aspectRatio?: CSSProperties["aspectRatio"]; size?: "compact" | "fluid"; /** Lets the active dither cluster follow fine-pointer movement. */ interactive?: boolean; statusText?: string; showStatus?: boolean; onRetry?: () => void; className?: string; mediaClassName?: string; statusClassName?: string; } const STATUS_TEXT: Record = { queued: "Waiting to generate", generating: "Generating image", refining: "Refining details", complete: "Image ready", error: "Generation failed", }; const MEDIA_STATE: Record< ImageGenerationStatus, { filter: string; opacity: number; scale: number } > = { queued: { filter: "blur(4px) saturate(0.75)", opacity: 0, scale: 1.02 }, generating: { filter: "blur(3px) saturate(0.85)", opacity: 0, scale: 1.015 }, refining: { filter: "blur(1.5px) saturate(0.95)", opacity: 0.62, scale: 1.005 }, complete: { filter: "blur(0px) saturate(1)", opacity: 1, scale: 1 }, error: { filter: "blur(2px) saturate(0.5)", opacity: 0.28, scale: 1 }, }; const OVERLAY_OPACITY: Record = { queued: 1, generating: 1, refining: 0.48, complete: 0, error: 0, }; const DOT_GAP = 10; const TWO_PI = Math.PI * 2; function DitherMark({ status, reduce, }: { status: ImageGenerationStatus; reduce: boolean; }) { if (status === "complete") { return