alexbruf/elm-cally/1.1.0

Cally.Date

The single-date picker, a port of calendar-date/calendar-date.tsx.

Renders as <calendar-date> with the same part attributes, aria attributes and keyboard behaviour as Cally, in the light DOM.

type Msg
    = CalendarMsg Cally.Date.Msg
    | Picked Cally.Date.Value


config : Cally.Date.Config Msg
config =
    Cally.Date.defaultConfig
        { id = "start-date"
        , today = model.today
        , locale = Cally.Locale.enGB
        , toMsg = CalendarMsg
        , onChange = Picked
        }


view =
    Cally.Date.view config
        model.value
        model.calendar
        [ Cally.Month.view { offset = 0 } ]

The value is yours: view and update both take it, and onChange hands you the new one.

type alias Value =
Maybe Date

What this picker selects: one date, or none.

type alias Model =
{ focusedDate : Date
, page : Page
}

Everything the picker remembers for itself: which day the roving tabindex is on, and which months are on screen.

type Msg

Opaque. Route it back with update through Config.toMsg.

type alias Config msg =
{ id : String
, today : Date
, locale : Locale
, min : Maybe Date
, max : Maybe Date
, months : Int
, pageBy : PageBy
, firstDayOfWeek : Weekday
, formatWeekday : WeekdayFormat
, showOutsideDays : Bool
, showWeekNumbers : Bool
, isDateDisallowed : Date -> Bool
, getDayParts : Date -> List String
, previous : Html msg
, next : Html msg
, heading : Maybe (Context msg -> Html msg)
, toMsg : Msg -> msg
, onChange : Value -> msg
, onFocusDay : Maybe (Date -> msg)
, onPageChange : Maybe (( Date, Date ) -> msg)
}

Everything Cally takes as a prop, plus the messages this picker sends you.

id prefixes every DOM id the picker renders, so it must be unique on the page and stable across renders; focus uses those ids.

type PageBy
= Months
| Single

How the previous and next buttons move: a whole page of months at a time, or one month at a time. Cally's page-by.

= Day
| Next
| Previous

What focus should put the browser focus on.

{ id : String
, today : Date
, locale : Locale
, toMsg : Msg -> msg
, onChange : Value -> msg
}
-> Config msg

A Config with Cally's defaults: one month, paged by months, narrow weekday names, no outside days, no week numbers, and the locale's own first day of the week.

init : Config msg -> Value -> Model

The starting model. Focus lands on the value, or on today when there is no value, clamped to min and max.

Config msg
-> Value
-> Model
-> List (Context msg -> Html msg)
-> Html msg

Render the picker. The children are the months, and anything else that reads the Context; each one is applied to the Context so it can sit anywhere in the tree.

update : Config msg -> Value -> Msg -> Model -> ( Model, Cmd msg )

The update you wire into your own.

Consumer callbacks (onChange, onFocusDay, onPageChange) come back as commands, so they arrive as ordinary messages on the next update. The command also carries the Browser.Dom.focus call that keyboard navigation needs.

Config msg
-> Value
-> Msg
-> Model
-> { model : Model
, events : List msg
, focus : Maybe FocusTarget
}

The pure core of update.

events are the callbacks the message produced, in the order Cally dispatches them, and focus is the element the picker wants the browser focus on afterwards (Cally's setTimeout(focus)). update is this function with the two turned into commands; tests use this one.

focus : Config msg -> Model -> FocusTarget -> Cmd msg

Put the browser focus on the day that holds tabindex="0", or on one of the paging buttons. Cally's focus({ target }).

focusDate : Config msg -> Date -> Model -> Model

Move the roving focus, Cally's focused-date property. The date is clamped to min and max, and the page follows it.

context : Config msg -> Value -> Model -> Context msg

The Context this picker hands its children. Exposed so you can build a child on your own, and so tests can inspect it.