// Field's public association and appearance seams. // // The association object is deliberately control-agnostic: Field can own the // accessible contract for the canonical Input or for a consumer's explicitly // named local control without either implementation reaching into the other. import { tv, type VariantProps } from "tailwind-variants"; import type { FieldLayout } from "./core/field"; export { FIELD_LAYOUTS, type FieldLayout, type FieldControlProps } from "./core/field"; // `layout` decides where the label sits relative to its control. A text-like // control reads label-first, stacked above it. A binary choice — a checkbox or // a switch — reads control-first: the box sits at the start of the row, its // label beside it (and clickable, through the same native `for`), and help and // error text wrap underneath, aligned with the label text rather than with the // box. The association contract is identical in both. const LAYOUT = { stacked: { root: "", label: "", help: "", error: "" }, inline: { root: "grid-cols-[auto_minmax(0,1fr)] items-center gap-x-[var(--reddb-spatial-gap-md)]", label: "cursor-pointer", help: "col-start-2", error: "col-start-2", }, } as const satisfies Record>; // A disabled control takes its label down with it: the label steps to // secondary ink (still AA, WCAG 1.4.3) so a dimmed control never sits beside a // full-strength name. It follows the control's own `:disabled` — a native // `disabled` or an enclosing disabled fieldset — and only a control's: a // disabled