Usage
RecurrenceField from @prepared911/ui/recurrence-field lets operators configure a repeating schedule in one place. It composes a time range, an all-day switch, a start date, a time zone select, and a repeats rule, plus a summary sentence—so an operator defining "weekdays 09:00 to 17:00 until 12/31/2026" sees the whole rule. The committed value is an EventRecurrencePickerValue. formatRecurrenceSummary is the same sentence the field shows.
Today this is primarily the non-emergency intent scheduler—see manage-nonemergency/Intents/IntentModal/components/CreateSchedulePopover.tsx and ConfiguredScheduleEntry.tsx for the two canonical call sites.
Badge (see ConfiguredScheduleEntry), formatRecurrenceSummary gives operators and reviewers the same sentence.DateTimePicker. The recurrence machinery is overhead.AdvancedDateRangePicker or AdvancedDateTimeRangePicker; recurrence does not apply to search or analytics filters.DateTimePicker or Calendar with a note; recurrence is for the rule, not individual events.Select over the calendar picker's options: Daily, On weekdays, On weekends, Weekly, Every 2 weeks, Monthly, Monthly on the nth weekday, Annually, and Custom. Weekdays and weekends appear only when the start date matches.Custom). A panel for the interval, weekday toggles, monthly mode, and an end of Never, On a date, or After a count. Back returns to the main form.Switch, a start date via DateInput, and a time zone Select labeled with the GMT offset and city.copy.summary into one sentence and announces it with aria-live="polite". formatRecurrenceSummary returns that sentence for a chip.confirm adds Reset / Apply; pairing trigger with confirm and open / onOpenChange turns the whole control into a popover (see CreateSchedulePopover).
formatRecurrenceSummary drive any echoed chip: don't reformat the rule yourself.09:00 and end time to 17:00. If your product has different business hours, pass a seeded value rather than expecting operators to reset.confirm + trigger. When both are set, the picker tracks in-progress changes internally and only emits onValueChange when Apply fires: so closing the popover via Escape or outside-click discards the draft, matching the modal-commit expectation.disabled cascades to every sub-control so a parent "view only" state doesn't let part of the rule stay editable.value with the product's default start time, end time, and time zone. An empty field uses 09:00–17:00 and the zone from useLocale.disableFuture. Prevents selecting a future start date; useful when the series must begin today or earlier.trigger + open + onOpenChange. Use for popover-driven entry; leave them off for inline panels.confirm. Required when you want deferred commits. Without it, every change dispatches: acceptable in a dedicated form but not in a popover.formatRecurrenceSummary in any committed chip: keeping two copies of the sentence in sync by hand is a bug farm.confirm with a popover via trigger + open so closing discards the draft.RecurrenceField instance per rule; if you need two rules, render two pickers, not a multi-select.Combobox, Switch, Calendar, TimeInput). Tab order, focus on open, and announcing the summary on changes are part of the app's responsibility; the picker supplies the visible prose and the draft-commit discipline. See the Accessibility page for the full contract, including the aria-live pattern for the summary.