'use client'; import { useMemo, useState } from 'react'; import classNames from 'classnames'; import { Plus, Trash2, X, SquareDashed } from 'lucide-react'; import { boxColor, boxColorAlpha } from './BoundingBoxOverlay'; // Detects an Ideogram structured caption (the distinctive marker is the // compositional_deconstruction block). Used by the viewer to decide whether to // show this form editor instead of a plain textarea. export function isIdeogramCaption(text: string): boolean { const t = text.trim(); if (!t.startsWith('{')) return false; try { const d = JSON.parse(t); return !!d && typeof d === 'object' && typeof d.compositional_deconstruction === 'object'; } catch { return false; } } // Normalize an arbitrary color string to a #rrggbb value usable by . function toHex6(c: string): string { const s = (c || '').trim(); if (/^#[0-9a-fA-F]{6}$/.test(s)) return s; if (/^#[0-9a-fA-F]{3}$/.test(s)) { return ( '#' + s .slice(1) .split('') .map(ch => ch + ch) .join('') ); } return '#000000'; } const clamp1000 = (n: number) => Math.max(0, Math.min(1000, Math.round(isNaN(n) ? 0 : n))); function Section({ title, children }: { title: string; children: React.ReactNode }) { return (
{title}
{children}
); } function TextField({ label, value, onChange, placeholder, }: { label?: string; value: string; onChange: (v: string) => void; placeholder?: string; }) { return ( ); } function TextAreaField({ label, value, onChange, rows = 3, placeholder, }: { label?: string; value: string; onChange: (v: string) => void; rows?: number; placeholder?: string; }) { return (