Usage
Calendar from @prepared911/ui/calendar is the date grid. It uses local Date values. A field that edits a date is DateInput; that field owns the popover. Use the grid when operators need dates in calendar context: proximity to today, day of week, and span across weeks.
Calendar supports three modes via CalendarMode:
Single: one date.Range: a contiguous start / end range.DaysAgo: a single date resolved N days before the anchor (for "last 7 days" style filters).supervisor-analytics and logging-recorder dispatch surfaces.Calendar inline rather than hiding it behind a field.DateInput or a plain Input with type="date".TimeInput.AdvancedDateRangePicker, which pairs a mode strip with the grid.RecurrenceField so the operator sees the whole rule, not just one date.MonthCaption. Shared header with month / year Selects and chevron navigation. Hide the selects with hideMonthYearSelect when the surrounding popover is already short.react-day-picker provides the grid, weekday header, and selected / range-span styling.Calendar. Pass confirm on the grid when it is inline or in a custom popover shell. A date field is DateInput, which always requires applyLabel and resetLabel on its popover (CORE-1464).trigger. Without it, Calendar is an inline block. With it, the grid mounts as Popover content anchored to your trigger. Use open / onOpenChange / onClose to coordinate with surrounding UI.CalendarMode.Single. value?: Date, onChange(value: Date). The simplest case; pair with a label and optional Apply button.CalendarMode.Range. value?: { start: Date; end: Date }, onChange(value). Selecting an earlier date after an end date resets the range start.CalendarMode.DaysAgo. Adds a required daysAgo: number. Pick any date and the committed value is daysAgo days earlier: useful for "look back N days from today" shortcuts where the display anchor moves but the stored value is always relative.minSelectableDate / maxSelectableDate. Constrain navigation and selection. MonthCaption disables months and years outside the window so operators cannot page past a cliff.disableFuture. Shorthand for "today or earlier"; preferable to computing maxSelectableDate = new Date() yourself because it also hides future months from the year Select.disabled. Accepts boolean or (date: Date) => boolean. Use the predicate to gray out weekends, holidays, or days with no data.hideMonthYearSelect. Drops the month / year Selects in favor of chevrons-only. Use for narrow popovers where the selects would wrap.trigger for inline layouts (two pickers side-by-side in the dispatch analytics popover); pass trigger for a date field that opens on click.Calendar may still commit on each click. A field that edits a date is DateInput, which always requires applyLabel and resetLabel on its popover (ADR 0027, CORE-1464).Selects stay disabled at the minSelectableDate / maxSelectableDate boundaries so the grid cannot render an empty month.Date objects. Pair with convertLocalToUTC / convertUTCToLocal from @prepared911/util-helpers at the boundary; the component does not assume a storage time zone.minSelectableDate / maxSelectableDate whenever a constraint exists: do not rely on validation alone.DateInput with required footer labels for filter and form workflows so mid-selection does not dispatch a network request.Calendars bound to the same value without coordinating open state: they will fight for focus.Calendar for time-only or duration entry; the grid is noise in those cases.Single pickers: use CalendarMode.Range so the component handles the span highlight and end-before-start correction for you.Calendar inherits react-day-picker's grid semantics (roving tabindex, arrow-key navigation) and routes Apply / Reset through @prepared911/ui Buttons. The app is responsible for a visible label on the trigger, focus handoff when used in a popover, and announcing the committed value after Apply. See the Accessibility page for the full contract.
Calendar wrapped in a Popover around a text field.Calendar paired with a native time input.Calendar inside a multi-step recurrence rule.