import { type ButtonProps } from '../button'; import { type BandedGaugeBand } from './banded-gauge'; export type InsertMode = 'text' | 'image' | 'text-image'; export type InsertVariant = 'insert' | 'copy'; /** * The handful of lucide glyphs the result-card header can carry. Each maps to a * static native-SVG geometry string in {@link ICON_GEOMETRY}, hand-transcribed * from lucide-react 1.8.0's `__iconNode` arrays (pinned to that version so the * paths match the on-screen React glyphs exactly). We do NOT import the lucide * React components into the raster path — they can't be serialised into the * `` data-URI — so the geometry is inlined as raw `` elements. */ export type IconKey = 'activity' | 'scale' | 'ruler' | 'calendar' | 'calendar-heart' | 'baby' | 'heart' | 'droplets' | 'clock' | 'tag' | 'trending-up' | 'percent'; export interface InsertCardField { label: string; value: string; /** * Optional leading glyph for the row, drawn at {@link FIELD_ICON_SLOT} in * place of the default bullet dot. One of the known {@link IconKey} names; an * unknown / omitted value falls back to the muted bullet (fully * back-compatible — a field without an icon renders exactly as before). */ icon?: IconKey; } /** * Radial gauge — a hand-rolled native-SVG donut (track `` + value arc * via `stroke-dasharray`) drawn in the card's inline-end corner box. Survives * the `` → `` → `toBlob` raster. No ``, no charting * lib. * * This is the original gauge shape; `variant` is optional and defaults to * `'radial'`, so a gauge object authored before the banded variant existed * renders exactly as before. */ export interface InsertCardRadialGauge { /** Discriminant. Optional — omitted means `'radial'` (back-compat). */ variant?: 'radial'; /** Big number rendered in the gauge centre (e.g. `'22.4'`). */ value: string; /** * Filled fraction of the ring, `0`–`1`. Takes precedence when supplied; * otherwise derived from a `value`/`max` numeric parse (falling back to a * full ring when neither is numeric). */ fraction?: number; /** Denominator used to derive `fraction` when `fraction` is omitted. */ max?: number; /** * Number of evenly-spaced segment gaps to notch into the ring (e.g. `4` for * a quartered dial). `0`/omitted draws a continuous arc. */ segments?: number; /** * DS token NAME for the arc colour — e.g. `'--success'`, `'--warning'`, * `'--destructive'`, `'--info'`, or the light-orange overweight override. * Resolved to a concrete colour from a probe span at raster time; never a * hex literal in source. */ colorToken: string; /** Small category label under the value inside the ring. */ label?: string; } /** * Banded gauge — a full-width horizontal track split into coloured zones with a * marker at the value's position (the WHO BMI dial, drawn via the shared * `banded-gauge` module). It spans the card edge-to-edge below the field rows. * Same raster-safety guarantees as the radial donut: pure native SVG, no * ``. * * Every visible string (`valueLabel`, `categoryLabel`, `rangeLabel`, * `ariaLabel`) arrives ALREADY TRANSLATED — the calculator supplies `t()`- * resolved text. Every band's `colorToken` is registered for probe sampling so * the baked raster carries theme-correct fills. */ export interface InsertCardBandedGauge { /** Discriminant for the banded layout. */ variant: 'banded'; /** The true value (printed verbatim even when clamped to a bar end). */ value: number; /** Ascending coloured zones; the last `upTo` should equal `max`. */ bands: BandedGaugeBand[]; /** Low end of the drawn scale (maps to the bar's inline start). */ min: number; /** High end of the drawn scale (maps to the bar's inline end). */ max: number; /** Big number rendered above the marker (e.g. `'24.6'`). */ valueLabel: string; /** Band name shown beside the value (e.g. `'normal'`). Pre-translated. */ categoryLabel?: string; /** Range string for the band (e.g. `'18.5–24.9'`). Pre-translated. */ rangeLabel?: string; /** Full accessible name, e.g. `'BMI 24.6 — normal (18.5–24.9)'`. */ ariaLabel: string; /** Threshold tick values drawn under the bar (e.g. `[18.5, 25, 30]`). */ ticks?: number[]; } /** * Optional in-card gauge. A discriminated union on `variant`: * * • `'radial'` (default when `variant` is omitted) — the corner-box donut. * • `'banded'` — a full-width horizontal banded bar below the fields. */ export type InsertCardGauge = InsertCardRadialGauge | InsertCardBandedGauge; export interface InsertCardData { /** Card heading. */ title: string; /** Key/value rows. */ fields: InsertCardField[]; /** * Optional header glyph drawn inline-end of the title, tinted with the card's * category colour ({@link InsertCardData.highlightToken}). One of the known * {@link IconKey} names; an unknown / omitted value simply skips the glyph * (fully back-compatible — a card without an icon renders as before). */ icon?: IconKey; /** Optional highlighted line, rendered as a category chip (pill). */ highlight?: string; /** * DS token NAME for the highlight chip fill. Defaults to the accent token * (`--primary`). The chip text uses the matching `-foreground` when it * resolves, else falls back to the card background for contrast. */ highlightToken?: string; /** Optional radial gauge drawn natively in the card. */ gauge?: InsertCardGauge; /** * Optional brand wordmark line printed at the foot of the card. * * - omitted / `false` → no brand line and no footer at all; the card ends * after the fields/gauge. * - a string → that wordmark, rendered as a single quiet line (no hairline * rule above it). * * A `brand` passed to {@link SvgCardToPngOptions} overrides this per-render. */ brand?: string | false; } export interface InsertPayload { /** Which button the user chose. */ mode: InsertMode; /** Plain-text summary. Always present. */ text: string; /** Rich HTML summary (heading + list). Always present. */ html: string; /** * Branded SVG result-card markup. Empty for mode `'text'`. * * Kept for back-compat and for callers that need the live, copy-pasteable * vector. NOTE: SVG can carry `