import type { ControlSize } from "@charcuterie/tokens"; import type { ReactNode } from "react"; /** * Which shape the options are drawn in. The control is the same * `radiogroup` either way — this is layout, and it is a prop rather * than a second component because nothing about the semantics, the * keyboard model or the element changes with it. * * - `row` — the default. Each option is a line of prose beside its * radio, stacked down the page. The form-length list. * - `tile` — each option is a bordered card carrying a name, an * optional line of help and a selected surface, and the group is * a grid that gains columns with the CONTAINER's width. */ export type RadioItemShape = "row" | "tile"; export type RadioItem = { /** * A line of help under the label. Drawn one step down the type * ramp in `content-muted`, inside the option's accessible name — * a hint a screen reader never reads is a hint half the audience * does not have. */ hint?: ReactNode; /** * Leading content, before the name. A `Badge`, an app's own icon, * a count. `tile` only: a row already leads with its radio, and a * second leading mark either side of it has nowhere to sit. */ icon?: ReactNode; /** * A disabled option is simply **not registered** with the roving * group, so the arrow keys skip it without any command in * `RovingFocus` having to know what "disabled" means. It stays * registered with the picker: it is still one of the options. */ isDisabled?: boolean; label: ReactNode; value: string; }; export type RadioGroupProps = { className?: string; /** * Draws each option as a card in a grid instead of a row in a * stack. Defaults to `row`. */ itemShape?: RadioItemShape; items: readonly RadioItem[]; /** * Shows which option is chosen at full contrast but refuses to move * the choice — the arrow keys and clicks no longer select, and the * group announces `aria-readonly`. Focus can still travel the * options so a keyboard user can read them. */ isReadOnly?: boolean; /** The group's accessible name. Required. */ label: string; /** * The narrowest a tile track may be, in CSS px. `tile` only. * * It is the grid's floor and not the tile's width: tracks below it * are not created, and the ones that are share the row evenly. */ minTileInlineSize?: number; onChange?: (selectedValue: string | null) => void; /** **Initial** only. Charcuterie owns it from then on. */ selectedValue?: string; size?: ControlSize; }; /** * One choice out of many, each on its own row with a label the size * of prose — the stacked sibling of `SegmentedControl`. * * The two are the *same* composition — `SinglePicker` + `RovingFocus`, * a `radiogroup` of `radio`s where selection follows focus — and a * different shape. `SegmentedControl` is a compact strip for a * handful of short options that share a control row; `RadioGroup` is * the form-length list where each option carries a real sentence and * an in-line strip would wrap. Picking between them is layout, not * behaviour, which is why the keyboard model here is identical and * lives in the same two hooks. * * ### `radiogroup`, not a stack of checkboxes * * A column of `` is the **independent * toggles** pattern: nothing says the options are mutually * exclusive, and a screen reader never announces "1 of 4". A single * choice from a named set is a radio group, and its arrow keys both * move focus and check — APG's one activation mode, the same reason * `SegmentedControl` has no `manual` prop. * * ### `itemShape="tile"` is the choice tile * * A bordered card carrying a name, a line of help and a selected * surface, in a grid that gains columns with its container. It is a * prop and not a third component because **only the box changes**: * the element, the role, the roving tabindex, selection-follows-focus * and `isReadOnly` are the ones already tested here. `SegmentedControl` * earns its own file by being a different control — one connected * strip, no radio affordance; a tile is this control with a border. * * ### A tile that ACTS is `ActionTiles` * * Same box, read from `tileStyles.ts`, and nothing else in common: * no `radio` role, no roving tabindex, no selection to follow focus, * no read-only. Ask what a press does. It records a value something * below reads — this. It goes somewhere or starts something, and * nothing stays selected — `ActionTiles`. Inverting every clause of * the paragraph above is what earned that one its own file * (`docs/decisions/2026-09-01-a-tile-that-acts-is-its-own-component-and-shares-only-the-box.md`). */ export declare const RadioGroup: ({ className, itemShape, items, isReadOnly, label, minTileInlineSize, onChange, selectedValue, size, }: RadioGroupProps) => ReactNode; //# sourceMappingURL=RadioGroup.d.ts.map