Cascade select
One value chosen as a path through nested options, from a column per level or one level at a time, by the pointer or the arrows.
Columns #
export const CascadeSelectStyle = forSlots(CascadeSelectSlots)(Recipes.CascadeSelect({}))
/** Folded with `CascadeSelect.update(CASCADE_PLACES)`; its Model from `CascadeSelect.init({ id })`. */
export const CASCADE_PLACES: CascadeSelect.Config = {
nodes: [
{
id: 'ca',
label: 'Canada',
children: [
{
id: 'on',
label: 'Ontario',
children: [
{ id: 'tor', label: 'Toronto' },
{ id: 'ott', label: 'Ottawa' },
],
},
{ id: 'qc', label: 'Quebec', children: [{ id: 'mtl', label: 'Montreal' }] },
],
},
{
id: 'jp',
label: 'Japan',
children: [
{ id: 'kanto', label: 'Kantō', children: [{ id: 'tyo', label: 'Tokyo' }] },
{ id: 'kansai', label: 'Kansai', children: [{ id: 'osa', label: 'Osaka' }] },
],
},
{ id: 'sg', label: 'Singapore' },
],
}
// A city chosen through its country and region: a column per level, the
// arrows within and between them, the value the path of ids.
export const cascadeSelect = <Message>(
style: NamedStyle<typeof CascadeSelectSlots>,
model: CascadeSelect.Model,
onMessage: (message: CascadeSelect.Message) => Message,
h: HtmlBuilder<Message>,
): Html =>
CascadeSelect.view(
{
model,
config: CASCADE_PLACES,
onMessage,
label: 'City',
placeholder: 'Choose a city',
levels: ['Country', 'Region', 'City'],
clearable: true,
style,
},
h,
)One level at a time #
// One level at a time, with a way back: a phone's width holds one column.
export const cascadeSelectDrill = <Message>(
style: NamedStyle<typeof CascadeSelectSlots>,
model: CascadeSelect.Model,
onMessage: (message: CascadeSelect.Message) => Message,
h: HtmlBuilder<Message>,
): Html =>
CascadeSelect.view(
{ model, config: CASCADE_PLACES, onMessage, label: 'City', layout: 'drill', style },
h,
)Usage
Each example above names the function that drew it, over the theme module Create a theme writes. The preview passes it the style picked above instead of its default.