This library helps you create a menu. Your data is stored separately; keep it in whatever shape makes the most sense for your application. A menu has a lot of uses: form input, mentions, search, etc.
I have (hopefully!) given the users of this library a large amount of customizability.
I recommend looking at the examples before diving into the API or source code.
Use this function to update the menu's State.
Provide the same data as your view.
The Int argument is how many results you would like to show.
Add this to your program's subscriptions so the menu will respond to keyboard input.
Create the configuration for your view function (ViewConfig).
Say we have a List Person that we want to show as a series of options.
We would create a ViewConfig like so:
import Menu
viewConfig : Menu.ViewConfig Person
viewConfig =
let
customizedLi keySelected mouseSelected person =
{ attributes =
[ classList
[ ( "menu-item", True )
, ( "key-selected", keySelected )
, ( "mouse-selected", mouseSelected )
]
]
, children = [ Html.text person.name ]
}
in
Menu.viewConfig
{ toId = .name
, ul = [ class "menu-list" ]
, li = customizedLi
}You provide the following information in your menu configuration:
toId — turn a Person into a unique ID. This lets us use
Html.Keyed under the hood to make sorting faster.ul — specify any non-behavioral attributes you'd like for the list menu.li — specify any non-behavioral attributes and children for a list item: both selection states are provided.
See the examples to get a better understanding!Create the configuration for your update function (UpdateConfig).
Say we have a List Person that we want to show as a series of options.
We would create an UpdateConfig like so:
import Menu
updateConfig : Menu.UpdateConfig Msg Person
updateConfig =
Menu.updateConfig
{ toId = .name
, onKeyDown =
\code maybeId ->
if code == 38 || code == 40 then
Nothing
else if code == 13 then
Maybe.map SelectPerson maybeId
else
Just Reset
, onTooLow = Nothing
, onTooHigh = Nothing
, onMouseEnter = \_ -> Nothing
, onMouseLeave = \_ -> Nothing
, onMouseClick = \id -> Just (SelectPerson id)
, separateSelections = False
}You provide the following information in your menu configuration:
toId — turn a Person into a unique ID.ul — specify any non-behavioral attributes you'd like for the list menu.li — specify any non-behavioral attributes and children for a list item: both selection states are provided.Tracks keyboard and mouse selection within the menu.
Reset the keyboard navigation but leave the mouse state alone. Convenient when the two selections are represented separately.
Like reset but defaults to a keyboard selection of the first item.
Like reset but defaults to a keyboard selection of the last item.
True if the element has been selected via keyboard navigation.
True if the element has been selected via mouse hover.
A message type for the menu to update.
Configuration for your menu, describing your menu and its items.
Note: Your ViewConfig should never be held in your model. It should only appear in view code.
Configuration for updates
HTML lists require li tags as children, so we allow you to specify everything about li HTML node except the nodeType.
Sections require a separate view and configuration since another type of data must be provided: sections.
Note: Section data can have any shape: your static configuration will just tell the menu how to grab an ID for a section and its related data.
Presents a menu with sections.
You can follow the same instructions as described for view, providing a more advanced configuration and different data shape.
ViewWithSectionsConfig sets up your menu to handle sectioned data.
The sectioned data becomes the new data argument for viewWithSections.
Create the SectionConfig for your view function.
Say we have a List Century that we want to show as a series of sections.
We would create a SectionConfig like so:
type alias Century =
{ title : String
, people : List Person
}
import Menu
sectionConfig : Menu.SectionConfig Person Century
sectionConfig =
Menu.sectionConfig
{ toId = .title
, getData = .people
, ul = [ class "menu-section-list" ]
, li =
\section ->
{ nodeType = "div"
, attributes = [ class "menu-section-item" ]
, children =
[ div [ class "menu-section-box" ]
[ strong [ class "menu-section-text" ] [ text section.title ]
]
]
}
}You provide the following information in your menu configuration:
toId — turn a Century into a unique ID.getData — extract the data from Century, in this case: List Person.ul — specify any non-behavioral attributes you'd like for the section list.li — specify any non-behavioral attributes and children for a section.The same configuration as viewConfig, but provide a section configuration as well.
Describe everything about a Section HTML node.
The configuration for a section of the menu.
Note: This should never live in your model.
Configuration for your menu, describing your menu, its sections, and its items.
Note: This should never live in your model.
Take a list of
dataand turn it into a menu. TheViewConfigargument is the configuration for the menu view.ViewConfigdescribes the HTML we want to show for each item and the list. TheIntargument is how many results you would like to show. TheStateargument describes what is selected via mouse and keyboard.Note: The
StateandList datashould live in your Model. TheViewConfigfor the menu belongs in your view code.ViewConfigshould never exist in your model. Describe any potential menu configurations statically. This pattern has been inspired by Elm Sortable Table.