Components

Date picker

A date behind a button, picked from a calendar that opens under it.

size
scheme

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,
  })

The recipe ↗This code ↗