T06b forms selection: checkbox, radio, cards, switch, select, combobox, multi select, cascader, transfer list, list box, chips, rating, sliders, knob, stepper
This commit is contained in:
36 files changed
+5170
-198
No files matched your search
@@ -0,0 +1,214 @@
|
||||
use ely_gpui_component::{
|
||||
forms::{
|
||||
CheckState, Checkbox, CheckboxCard, CheckboxGroup, Choice, RadioCard, RadioGroup, Switch,
|
||||
},
|
||||
primitives::IconName,
|
||||
};
|
||||
use gpui::{App, Entity, IntoElement, ParentElement, SharedString, Styled, Window, div, px};
|
||||
|
||||
use crate::{
|
||||
probe::probe,
|
||||
ui::{code, section, specimen},
|
||||
};
|
||||
|
||||
pub(super) fn keep<T: 'static>(
|
||||
key: &'static str,
|
||||
init: impl FnOnce() -> T,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> Entity<T> {
|
||||
window.use_keyed_state(key, cx, move |_, _| init())
|
||||
}
|
||||
|
||||
pub(super) fn set<T: 'static>(state: &Entity<T>, value: T, cx: &mut App) {
|
||||
state.update(cx, |state, cx| {
|
||||
*state = value;
|
||||
cx.notify();
|
||||
});
|
||||
}
|
||||
|
||||
fn values(list: &[&'static str]) -> Vec<SharedString> {
|
||||
list.iter()
|
||||
.map(|value| SharedString::from(*value))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn checkboxes(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
|
||||
let channels = [
|
||||
Choice::new("email", "Email"),
|
||||
Choice::new("push", "Push"),
|
||||
Choice::new("sms", "Text message").disabled(),
|
||||
];
|
||||
let open: Vec<SharedString> = channels
|
||||
.iter()
|
||||
.filter(|choice| !choice.disabled)
|
||||
.map(|choice| choice.value.clone())
|
||||
.collect();
|
||||
let on = keep("check-channels", || values(&["email"]), window, cx);
|
||||
let now = on.read(cx).clone();
|
||||
let parent = match now.len() {
|
||||
0 => CheckState::Off,
|
||||
n if n == open.len() => CheckState::On,
|
||||
_ => CheckState::Mixed,
|
||||
};
|
||||
let (all, some) = (on.clone(), on.clone());
|
||||
section(
|
||||
"Checkbox / CheckboxGroup",
|
||||
"On, off, or mixed when a parent's children disagree. The check pops in.",
|
||||
cx,
|
||||
)
|
||||
.child(probe(
|
||||
"checks",
|
||||
div()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.gap_2()
|
||||
.w(px(280.0))
|
||||
.child(
|
||||
Checkbox::new("check-all", parent)
|
||||
.label("All notifications")
|
||||
.on_change(move |on, _, cx| {
|
||||
set(&all, if on { open.clone() } else { Vec::new() }, cx)
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
div().pl_6().child(
|
||||
CheckboxGroup::new("check-group", channels)
|
||||
.selected(now)
|
||||
.on_change(move |next, _, cx| set(&some, next.to_vec(), cx)),
|
||||
),
|
||||
),
|
||||
))
|
||||
.child(code("Checkbox::new(id, CheckState::Mixed)", cx))
|
||||
}
|
||||
|
||||
pub fn radios(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
|
||||
let plan = keep("radio-plan", || SharedString::from("pro"), window, cx);
|
||||
let density = keep(
|
||||
"radio-density",
|
||||
|| SharedString::from("standard"),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
let (plan_now, density_now) = (plan.read(cx).clone(), density.read(cx).clone());
|
||||
section(
|
||||
"Radio / RadioGroup",
|
||||
"One Tab stop per group; the arrow keys move the choice.",
|
||||
cx,
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.gap_6()
|
||||
.child(specimen(
|
||||
"plan",
|
||||
probe(
|
||||
"radios",
|
||||
RadioGroup::new(
|
||||
"radio-plan",
|
||||
[
|
||||
Choice::new("free", "Free"),
|
||||
Choice::new("pro", "Pro"),
|
||||
Choice::new("team", "Team"),
|
||||
Choice::new("enterprise", "Enterprise").disabled(),
|
||||
],
|
||||
)
|
||||
.selected(plan_now)
|
||||
.on_change(move |value, _, cx| set(&plan, value.clone(), cx)),
|
||||
),
|
||||
cx,
|
||||
))
|
||||
.child(specimen(
|
||||
"density, in a row",
|
||||
RadioGroup::new(
|
||||
"radio-density",
|
||||
[
|
||||
Choice::new("compact", "Compact"),
|
||||
Choice::new("standard", "Standard"),
|
||||
Choice::new("comfortable", "Comfortable"),
|
||||
],
|
||||
)
|
||||
.horizontal()
|
||||
.selected(density_now)
|
||||
.on_change(move |value, _, cx| set(&density, value.clone(), cx)),
|
||||
cx,
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn cards(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
|
||||
let space = keep("card-space", || SharedString::from("personal"), window, cx);
|
||||
let backup = keep("card-backup", || true, window, cx);
|
||||
let (space_now, backup_now) = (space.read(cx).clone(), *backup.read(cx));
|
||||
let (personal, team) = (space.clone(), space);
|
||||
section(
|
||||
"CheckboxCard / RadioCard",
|
||||
"Larger targets that explain a choice. The chosen border turns to ink.",
|
||||
cx,
|
||||
)
|
||||
.child(probe(
|
||||
"cards",
|
||||
div()
|
||||
.flex()
|
||||
.gap_3()
|
||||
.w(px(640.0))
|
||||
.child(
|
||||
div().flex_1().child(
|
||||
RadioCard::new("card-personal", space_now == "personal", "Personal")
|
||||
.description("Just you. Notes stay on this Mac.")
|
||||
.icon(IconName::User)
|
||||
.on_select(move |_, cx| set(&personal, "personal".into(), cx)),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
div().flex_1().child(
|
||||
RadioCard::new("card-team", space_now == "team", "Team")
|
||||
.description("Shared with everyone you invite.")
|
||||
.icon(IconName::Users)
|
||||
.on_select(move |_, cx| set(&team, "team".into(), cx)),
|
||||
),
|
||||
),
|
||||
))
|
||||
.child(
|
||||
div().w(px(640.0)).child(
|
||||
CheckboxCard::new("card-backup", backup_now, "Back up nightly")
|
||||
.description("Copies change sets to the cloud at 2 AM.")
|
||||
.icon(IconName::Cloud)
|
||||
.on_change(move |on, _, cx| set(&backup, on, cx)),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn switches(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
|
||||
let wifi = keep("switch-wifi", || true, window, cx);
|
||||
let sync = keep("switch-sync", || false, window, cx);
|
||||
let (wifi_now, sync_now) = (*wifi.read(cx), *sync.read(cx));
|
||||
section(
|
||||
"Switch / Toggle",
|
||||
"Takes effect at once. The thumb slides with a little overshoot.",
|
||||
cx,
|
||||
)
|
||||
.child(probe(
|
||||
"switches",
|
||||
div()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.gap_3()
|
||||
.child(
|
||||
Switch::new("switch-wifi", wifi_now)
|
||||
.label("Wi-Fi")
|
||||
.on_change(move |on, _, cx| set(&wifi, on, cx)),
|
||||
)
|
||||
.child(
|
||||
Switch::new("switch-sync", sync_now)
|
||||
.label("Sync over cellular")
|
||||
.on_change(move |on, _, cx| set(&sync, on, cx)),
|
||||
)
|
||||
.child(
|
||||
Switch::new("switch-locked", true)
|
||||
.label("Managed by your admin")
|
||||
.disabled(true),
|
||||
),
|
||||
))
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
mod choices;
|
||||
mod formats;
|
||||
mod numbers;
|
||||
mod pickers;
|
||||
mod rich;
|
||||
mod text;
|
||||
mod values;
|
||||
|
||||
use gpui::{AnyElement, App, IntoElement, ParentElement, Window, div};
|
||||
|
||||
@@ -109,6 +112,74 @@ const SCRIPT: &[Step] = &[
|
||||
Step::Wait(1200),
|
||||
Step::CancelPanel,
|
||||
Step::Wait(600),
|
||||
Step::DownAt("checks", 40.0, 66.0),
|
||||
Step::UpAt("checks", 40.0, 66.0),
|
||||
Step::Wait(300),
|
||||
Step::Shot("checks"),
|
||||
Step::DownAt("radios", 30.0, 66.0),
|
||||
Step::UpAt("radios", 30.0, 66.0),
|
||||
Step::Wait(400),
|
||||
Step::Shot("radios"),
|
||||
Step::DownAt("cards", 480.0, 30.0),
|
||||
Step::UpAt("cards", 480.0, 30.0),
|
||||
Step::Wait(400),
|
||||
Step::Shot("cards"),
|
||||
Step::DownAt("switches", 16.0, 39.0),
|
||||
Step::UpAt("switches", 16.0, 39.0),
|
||||
Step::Wait(600),
|
||||
Step::Shot("switches"),
|
||||
Step::Click("select"),
|
||||
Step::Wait(300),
|
||||
Step::Key("down"),
|
||||
Step::Wait(200),
|
||||
Step::Shot("select-open"),
|
||||
Step::Key("enter"),
|
||||
Step::Wait(300),
|
||||
Step::Click("combobox"),
|
||||
Step::Key("secondary-a"),
|
||||
Step::Type("lis"),
|
||||
Step::Wait(300),
|
||||
Step::Shot("combobox"),
|
||||
Step::Key("enter"),
|
||||
Step::Wait(200),
|
||||
Step::Click("multi"),
|
||||
Step::Wait(300),
|
||||
Step::Key("down"),
|
||||
Step::Key("enter"),
|
||||
Step::Wait(300),
|
||||
Step::Shot("multi"),
|
||||
Step::Key("escape"),
|
||||
Step::Click("cascader"),
|
||||
Step::Wait(300),
|
||||
Step::Key("down"),
|
||||
Step::Key("right"),
|
||||
Step::Wait(300),
|
||||
Step::Shot("cascader"),
|
||||
Step::Key("escape"),
|
||||
Step::DownAt("transfer", 60.0, 45.0),
|
||||
Step::UpAt("transfer", 60.0, 45.0),
|
||||
Step::Wait(200),
|
||||
Step::DownAt("transfer", 280.0, 134.0),
|
||||
Step::UpAt("transfer", 280.0, 134.0),
|
||||
Step::Wait(300),
|
||||
Step::Shot("transfer"),
|
||||
Step::DownAt("chips", 120.0, 14.0),
|
||||
Step::UpAt("chips", 120.0, 14.0),
|
||||
Step::DownAt("rating", 79.0, 13.0),
|
||||
Step::UpAt("rating", 79.0, 13.0),
|
||||
Step::Wait(300),
|
||||
Step::Shot("chips-rating"),
|
||||
Step::DownAt("slider", 130.0, 8.0),
|
||||
Step::DragTo("slider", 220.0, 8.0),
|
||||
Step::UpAt("slider", 220.0, 8.0),
|
||||
Step::Wait(200),
|
||||
Step::DownAt("knob", 24.0, 24.0),
|
||||
Step::DragTo("knob", 24.0, -36.0),
|
||||
Step::UpAt("knob", 24.0, -36.0),
|
||||
Step::DownAt("stepper", 76.0, 16.0),
|
||||
Step::UpAt("stepper", 76.0, 16.0),
|
||||
Step::Wait(300),
|
||||
Step::Shot("values"),
|
||||
Step::Rest,
|
||||
];
|
||||
|
||||
@@ -133,5 +204,19 @@ fn render(window: &mut Window, cx: &mut App) -> AnyElement {
|
||||
.child(rich::regex(window, cx))
|
||||
.child(rich::expression(window, cx))
|
||||
.child(rich::hotkey(window, cx))
|
||||
.child(choices::checkboxes(window, cx))
|
||||
.child(choices::radios(window, cx))
|
||||
.child(choices::cards(window, cx))
|
||||
.child(choices::switches(window, cx))
|
||||
.child(pickers::select(window, cx))
|
||||
.child(pickers::list_box(window, cx))
|
||||
.child(pickers::combobox(window, cx))
|
||||
.child(pickers::multi_select(window, cx))
|
||||
.child(pickers::cascader(window, cx))
|
||||
.child(pickers::transfer(window, cx))
|
||||
.child(values::chips(window, cx))
|
||||
.child(values::rating(window, cx))
|
||||
.child(values::sliders(window, cx))
|
||||
.child(values::dials(window, cx))
|
||||
.into_any_element()
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
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)),
|
||||
),
|
||||
))
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
use ely_gpui_component::forms::{Choice, ChoiceChips, Knob, RangeSlider, Rating, Slider, Stepper};
|
||||
use gpui::{App, IntoElement, ParentElement, SharedString, Styled, Window, div, px};
|
||||
|
||||
use super::choices::{keep, set};
|
||||
use crate::{
|
||||
probe::probe,
|
||||
ui::{section, specimen, specimens},
|
||||
};
|
||||
|
||||
pub fn chips(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
|
||||
let sort = keep("chips-sort", || vec![SharedString::from("new")], window, cx);
|
||||
let teams = keep(
|
||||
"chips-teams",
|
||||
|| vec![SharedString::from("design")],
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
let (sort_now, teams_now) = (sort.read(cx).clone(), teams.read(cx).clone());
|
||||
section(
|
||||
"ChoiceChips / FilterChips",
|
||||
"Pills for a few options. Filter chips toggle and show a check.",
|
||||
cx,
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.gap_6()
|
||||
.child(specimen(
|
||||
"choice",
|
||||
probe(
|
||||
"chips",
|
||||
ChoiceChips::new(
|
||||
"chips-sort",
|
||||
[
|
||||
Choice::new("new", "Newest"),
|
||||
Choice::new("top", "Popular"),
|
||||
Choice::new("old", "Oldest"),
|
||||
],
|
||||
)
|
||||
.selected(sort_now)
|
||||
.on_change(move |next, _, cx| set(&sort, next.to_vec(), cx)),
|
||||
),
|
||||
cx,
|
||||
))
|
||||
.child(specimen(
|
||||
"filter",
|
||||
ChoiceChips::new(
|
||||
"chips-teams",
|
||||
[
|
||||
Choice::new("design", "Design"),
|
||||
Choice::new("eng", "Engineering"),
|
||||
Choice::new("research", "Research"),
|
||||
Choice::new("ops", "Operations").disabled(),
|
||||
],
|
||||
)
|
||||
.multiple()
|
||||
.selected(teams_now)
|
||||
.on_change(move |next, _, cx| set(&teams, next.to_vec(), cx)),
|
||||
cx,
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn rating(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
|
||||
let stars = keep("rating-stars", || 3u8, window, cx);
|
||||
let now = *stars.read(cx);
|
||||
section(
|
||||
"Rating",
|
||||
"Hover previews, a click sets it, and clicking the same star clears it.",
|
||||
cx,
|
||||
)
|
||||
.child(
|
||||
specimens()
|
||||
.child(specimen(
|
||||
format!("{now} of 5"),
|
||||
probe(
|
||||
"rating",
|
||||
Rating::new("rating-stars", now)
|
||||
.on_change(move |next, _, cx| set(&stars, next, cx)),
|
||||
),
|
||||
cx,
|
||||
))
|
||||
.child(specimen(
|
||||
"read only",
|
||||
Rating::new("rating-fixed", 4).disabled(true),
|
||||
cx,
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn sliders(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
|
||||
let volume = keep("slider-volume", || 40.0, window, cx);
|
||||
let level = keep("slider-level", || 60.0, window, cx);
|
||||
let price = keep("slider-price", || (20.0, 80.0), window, cx);
|
||||
let (volume_now, level_now, (low, high)) = (*volume.read(cx), *level.read(cx), *price.read(cx));
|
||||
section(
|
||||
"Slider / RangeSlider / VerticalSlider",
|
||||
"Drag a thumb, click the track, or use the arrows; Page keys jump ten steps.",
|
||||
cx,
|
||||
)
|
||||
.child(
|
||||
specimens()
|
||||
.child(specimen(
|
||||
format!("volume {volume_now:.0}"),
|
||||
probe(
|
||||
"slider",
|
||||
div().w(px(320.0)).child(
|
||||
Slider::new("slider-volume", volume_now)
|
||||
.on_change(move |next, _, cx| set(&volume, next, cx)),
|
||||
),
|
||||
),
|
||||
cx,
|
||||
))
|
||||
.child(specimen(
|
||||
format!("price {low:.0} to {high:.0}"),
|
||||
div().w(px(320.0)).child(
|
||||
RangeSlider::new("slider-price", low, high)
|
||||
.step(5.0)
|
||||
.on_change(move |next, _, cx| set(&price, next, cx)),
|
||||
),
|
||||
cx,
|
||||
))
|
||||
.child(specimen(
|
||||
format!("level {level_now:.0}"),
|
||||
div().h(px(140.0)).child(
|
||||
Slider::new("slider-level", level_now)
|
||||
.vertical()
|
||||
.step(5.0)
|
||||
.on_change(move |next, _, cx| set(&level, next, cx)),
|
||||
),
|
||||
cx,
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn dials(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
|
||||
let gain = keep("knob-gain", || 65.0, window, cx);
|
||||
let pan = keep("knob-pan", || 0.0, window, cx);
|
||||
let guests = keep("stepper-guests", || 2.0, window, cx);
|
||||
let (gain_now, pan_now, guests_now) = (*gain.read(cx), *pan.read(cx), *guests.read(cx));
|
||||
section(
|
||||
"Knob / Dial / Stepper",
|
||||
"Drag a knob up or down, or use the arrows. The stepper counts without typing.",
|
||||
cx,
|
||||
)
|
||||
.child(
|
||||
specimens()
|
||||
.child(specimen(
|
||||
format!("gain {gain_now:.0}"),
|
||||
probe(
|
||||
"knob",
|
||||
Knob::new("knob-gain", gain_now)
|
||||
.on_change(move |next, _, cx| set(&gain, next, cx)),
|
||||
),
|
||||
cx,
|
||||
))
|
||||
.child(specimen(
|
||||
format!("pan {pan_now:.0}"),
|
||||
Knob::new("knob-pan", pan_now)
|
||||
.range(-50.0, 50.0)
|
||||
.on_change(move |next, _, cx| set(&pan, next, cx)),
|
||||
cx,
|
||||
))
|
||||
.child(specimen(
|
||||
"guests",
|
||||
probe(
|
||||
"stepper",
|
||||
Stepper::new("stepper-guests", guests_now)
|
||||
.range(1.0, 10.0)
|
||||
.on_change(move |next, _, cx| set(&guests, next, cx)),
|
||||
),
|
||||
cx,
|
||||
)),
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user