Date picker
A date behind a button, picked from a calendar that opens under it.
forSlots(DatePickerSlots)(Recipes.DatePicker({}))
Usage
The function that drew the preview, over the theme module Create a theme writes. The preview passes it the style picked above instead of its default.
export const DatePickerStyle = forSlots(DatePickerSlots)(Recipes.DatePicker({}))
const PanelCalendarStyle = forSlots(CalendarSlots)(Recipes.Calendar({ size: 'sm' }))
/** The open panel and its month are the component's; the date is the Model's. */
export interface DatePickerState {
readonly picker: UiDatePicker.Model
readonly due: Option.Option<FoldkitCalendar.CalendarDate>
}
const dayOf = (date: FoldkitCalendar.CalendarDate): string =>
`${date.year}-${String(date.month).padStart(2, '0')}-${String(date.day).padStart(2, '0')}`
export const datePicker = <Message>(
style: NamedStyle<typeof DatePickerSlots>,
state: DatePickerState,
toMessage: (message: UiDatePicker.Message) => Message,
h: HtmlBuilder<Message>,
): Html =>
h.submodel({
slotId: state.picker.id,
model: state.picker,
view: DatePickerView.view,
viewInputs: {
// Locked: paging the months resizes the panel, which must not flip sides as it does.
anchor: {
placement: 'bottom-start',
gap: 4,
padding: 8,
isPlacementLocked: true,
portal: false,
},
maybeSelectedDate: state.due,
triggerContent: due =>
h.span([], [Option.match(due, { onNone: () => 'Pick a due date', onSome: dayOf })]),
toCalendarView: Calendar.toView([PanelCalendarStyle.mixin], { h }),
toView: DatePicker.toView([style.mixin]),
},
toParentMessage: toMessage,
})