Usage
RecurrenceField from @prepared911/ui/recurrence-field lets operators configure a repeating schedule in one place. It composes frequency selection, optional custom cadence, start date and time, end rules, and an always-visible summary line—so an operator defining "weekdays 9am to 5pm until Dec 31" sees the whole rule rather than piecing it together from four separate inputs. The committed value is an EventRecurrencePickerValue. copy.formatSummary(value) is the same prose 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), formatSummary gives operators and reviewers the same prose.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.Combobox over the RecurrenceFrequency enum: Daily, Weekdays, Weekends, Weekly, EveryTwoWeeks, Monthly, MonthlyNthDay, Annually, Custom.Custom). A nested group of Switch, Combobox, and selectors—CustomRecurrenceOptions—that expands into CustomRecurrenceType plus monthly-mode and weekday selectors as needed.Calendar, start / end times via TimeInput, plus an All-day Switch.RecurrenceEndType: Never, On (a committed end date), or After (a count of occurrences).formatSummary renders the full rule in plain English above or below the body, depending on your layout, so operators see what they're committing.confirm adds Reset / Apply; pairing trigger with confirm and open / onOpenChange turns the whole control into a popover (see CreateSchedulePopover).
formatSummary(value) drive any echoed chip or description: 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.formatSummary so the rule text stays accurate without an Apply step.Custom slides the custom pane in; switching away slides it out. Focus stays on the operator's most recent control.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 / end times and timezone (getSystemTimezone() is the shipped default).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.formatSummary(value) in any committed chip or summary: keeping two copies of the prose 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.