Usage
packages/ui/docs/decisions/0021-single-choice-control.md. Keep the presets to the few durations people pick most and let the amount cover the rest. DurationField shows at most five presets: more is a type error, and in development a longer list warns once and renders its first five.{ amount, unit } or null when the amount is empty. It follows the usual contract: value for controlled, defaultValue for uncontrolled, and onValueChange(value, details) for every change. details.part is amount, unit, preset or form, and details.reason is the control's own. Every change is cancelable except a native form reset.durationToSeconds and durationToMilliseconds turn a value into a number for a timer or a request. 24 hours and 1 day convert to the same seconds but are two different values: a preset selects only when both the amount and the unit match.units lists one to five units with the labels your product uses. Two to five render as a segmented choice beside the amount, because short labels of similar length are a SegmentedControl under ADR 0021. One unit renders as plain text beside the amount and no choice. Select is not part of the system yet, so a unit list that would need one (more than five, or labels that vary widely) is not supported.null. defaultUnit sets the unit shown while empty; it defaults to the default value's unit, then the first of units.defaultValue names it. Nothing marks a default with an icon or a star. Editing the amount or the unit changes the value, so the selection moves to the preset that matches, or clears when none does.3 hrs, 12 hrs, 1 day). Long or uneven labels fail the fit test of ADR 0021 and belong in a different control.Composition stories. The field itself has no none preset and no hidden segment.min and max take either a duration (an overall limit) or a number per unit.max={{ amount: 7, unit: DurationUnit.Days }} limits the field to a week in whichever unit is shown: 168 hours, 10,080 minutes.max={{ [DurationUnit.Hours]: 12, [DurationUnit.Days]: 3 }} limits hours and days separately and leaves minutes unbounded.0, so a zero duration is valid unless min says otherwise.name posts the amount and unitName posts the shown unit, both through hidden inputs; form reaches both. required blocks submit through the amount. A form reset restores defaultValue and its unit and calls onValueChange with reason form-reset. A draft the user is still typing commits before the form posts.name, so they post nothing of their own; they reach the form through the value. A form reset reports one change for the whole field.Box or FlexBox width or maxWidth props, or request a missing layout prop through find-pattern.size is InputSize and defaults to Large (32px). The unit and preset choices take the matching height.amountInputMinSize takes a NumberFieldInputMinSize and gives the amount's input a minimum width; the default sets none.