Files
Ely-GPUI-Components/examples/gallery/pages/forms/pickers.rs
T

236 lines
7.3 KiB
Rust

use ely_gpui_component::{
forms::{Cascade, Cascader, Choice, Combobox, ListBox, MultiSelect, Select, TransferList},
primitives::IconName,
};
use gpui::{App, IntoElement, ParentElement, SharedString, Styled, Window, div, px};
use super::{
choices::{keep, set},
text::field,
};
use crate::{
probe::probe,
ui::{blocked, section, specimen, specimens},
};
fn cities() -> Vec<Choice> {
[
("ams", "Amsterdam"),
("ber", "Berlin"),
("cph", "Copenhagen"),
("lis", "Lisbon"),
("lon", "London"),
("osl", "Oslo"),
("par", "Paris"),
("vie", "Vienna"),
]
.into_iter()
.map(|(value, label)| Choice::new(value, label))
.collect()
}
pub fn select(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
let view = keep("select-view", || SharedString::from("list"), window, cx);
let now = view.read(cx).clone();
section(
"Select / NativeSelect",
"A button that opens its list. Arrows move, Enter picks, Escape closes.",
cx,
)
.child(
specimens()
.child(specimen(
"view",
probe(
"select",
div().w(px(240.0)).child(
Select::new(
"select-view",
[
Choice::new("list", "List").icon(IconName::List),
Choice::new("board", "Board").icon(IconName::Kanban),
Choice::new("calendar", "Calendar").icon(IconName::Calendar),
Choice::new("gallery", "Gallery")
.icon(IconName::LayoutGrid)
.disabled(),
],
)
.selected(now)
.on_change(move |value, _, cx| set(&view, value.clone(), cx)),
),
),
cx,
))
.child(specimen(
"disabled",
div().w(px(200.0)).child(
Select::new("select-off", [Choice::new("utc", "UTC")])
.selected("utc")
.disabled(true),
),
cx,
)),
)
.child(blocked(
"NativeSelect: gpui 0.2.2 has no native popup menu, so Select draws its own.",
cx,
))
}
pub fn list_box(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
let picked = keep(
"listbox-cities",
|| vec![SharedString::from("lis")],
window,
cx,
);
let now = picked.read(cx).clone();
section(
"ListBox",
"A list chosen from in place. Focus it and use the arrows, Space or Enter.",
cx,
)
.child(
div().w(px(240.0)).child(
ListBox::new("listbox-cities", cities())
.selected(now)
.on_change(move |next, _, cx| set(&picked, next.to_vec(), cx)),
),
)
}
pub fn combobox(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
let city = field("input-city", window, cx, |input| {
input.placeholder("Search cities")
});
let tag = field("input-tag", window, cx, |input| {
input.placeholder("Any label")
});
let chosen = keep("combobox-city", || None::<SharedString>, window, cx);
let now = chosen.read(cx).clone();
let labels: Vec<Choice> = ["design", "docs", "infra", "motion", "release"]
.into_iter()
.map(|label| Choice::new(label, label))
.collect();
let mut combo = Combobox::new("combobox-city", &city, cities())
.on_change(move |value, _, cx| set(&chosen, Some(value.clone()), cx));
if let Some(value) = now {
combo = combo.selected(value);
}
section(
"Combobox / Autocomplete",
"Type to filter. A combobox keeps a listed value; an autocomplete keeps any text.",
cx,
)
.child(
specimens()
.child(specimen(
"combobox",
probe("combobox", div().w(px(260.0)).child(combo)),
cx,
))
.child(specimen(
"autocomplete",
div()
.w(px(260.0))
.child(Combobox::new("combobox-tag", &tag, labels).free()),
cx,
)),
)
}
pub fn multi_select(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
let picked = keep(
"multi-cities",
|| vec![SharedString::from("ber"), SharedString::from("osl")],
window,
cx,
);
let now = picked.read(cx).clone();
section(
"MultiSelect",
"Several values as chips. The list stays open while you pick; Backspace drops the last.",
cx,
)
.child(probe(
"multi",
div().w(px(360.0)).child(
MultiSelect::new("multi-cities", cities())
.selected(now)
.placeholder("Pick cities")
.on_change(move |next, _, cx| set(&picked, next.to_vec(), cx)),
),
))
}
pub fn cascader(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
let path = keep(
"cascade-office",
|| {
vec![
SharedString::from("eu"),
SharedString::from("pt"),
SharedString::from("lis"),
]
},
window,
cx,
);
let now = path.read(cx).clone();
let world = [
Cascade::new("am", "Americas")
.child(
Cascade::new("us", "United States")
.child(Cascade::new("nyc", "New York"))
.child(Cascade::new("sfo", "San Francisco")),
)
.child(Cascade::new("br", "Brazil").child(Cascade::new("sao", "São Paulo"))),
Cascade::new("eu", "Europe")
.child(
Cascade::new("pt", "Portugal")
.child(Cascade::new("lis", "Lisbon"))
.child(Cascade::new("opo", "Porto")),
)
.child(Cascade::new("de", "Germany").child(Cascade::new("ber", "Berlin"))),
Cascade::new("as", "Asia")
.child(Cascade::new("jp", "Japan").child(Cascade::new("tyo", "Tokyo"))),
];
section(
"CascadeSelect / Cascader",
"Each column opens the next. Right and Left walk the levels; a leaf picks the path.",
cx,
)
.child(probe(
"cascader",
div().w(px(320.0)).child(
Cascader::new("cascade-office", world)
.selected(now)
.on_change(move |next, _, cx| set(&path, next.to_vec(), cx)),
),
))
}
pub fn transfer(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
let chosen = keep(
"transfer-cities",
|| vec![SharedString::from("par")],
window,
cx,
);
let now = chosen.read(cx).clone();
section(
"TransferList",
"Mark rows on one side, then move them across.",
cx,
)
.child(probe(
"transfer",
div().w(px(560.0)).child(
TransferList::new("transfer-cities", cities())
.chosen(now)
.titles("Cities", "On the tour")
.on_change(move |next, _, cx| set(&chosen, next.to_vec(), cx)),
),
))
}