Lists · SelectableList: list semantics, row names, selection and place in set
This commit is contained in:
3 files changed
+33
-2
No files matched your search
+19
-1
@@ -2,7 +2,7 @@ use std::rc::Rc;
|
||||
|
||||
use gpui::{
|
||||
AnyElement, App, ClickEvent, ElementId, FontWeight, InteractiveElement, IntoElement,
|
||||
MouseButton, ParentElement, RenderOnce, SharedString, StatefulInteractiveElement, Styled,
|
||||
MouseButton, ParentElement, RenderOnce, Role, SharedString, StatefulInteractiveElement, Styled,
|
||||
Window, div, prelude::*, relative,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
@@ -29,6 +29,8 @@ pub struct ListItem {
|
||||
strong: bool,
|
||||
quiet: bool,
|
||||
struck: bool,
|
||||
/// Its place among its list's rows, from one, and their count.
|
||||
place: Option<(usize, usize)>,
|
||||
on_click: Option<OnClick>,
|
||||
}
|
||||
|
||||
@@ -47,6 +49,7 @@ impl ListItem {
|
||||
strong: false,
|
||||
quiet: false,
|
||||
struck: false,
|
||||
place: None,
|
||||
on_click: None,
|
||||
}
|
||||
}
|
||||
@@ -104,6 +107,12 @@ impl ListItem {
|
||||
self
|
||||
}
|
||||
|
||||
/// Tells assistive tech it is row `at` of `of`, from one.
|
||||
pub fn place(mut self, at: usize, of: usize) -> Self {
|
||||
self.place = Some((at, of));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn disabled(mut self, disabled: bool) -> Self {
|
||||
self.disabled = disabled;
|
||||
self
|
||||
@@ -140,6 +149,15 @@ impl RenderOnce for ListItem {
|
||||
let pressable = self.on_click.is_some() && !self.disabled;
|
||||
div()
|
||||
.id(self.id)
|
||||
.role(Role::ListItem)
|
||||
.aria_label(self.title.clone())
|
||||
.aria_selected(self.selected)
|
||||
.when_some(self.description.clone(), |row, text| {
|
||||
row.aria_description(text)
|
||||
})
|
||||
.when_some(self.place, |row, (at, of)| {
|
||||
row.aria_position_in_set(at).aria_size_of_set(of)
|
||||
})
|
||||
.flex()
|
||||
.items_center()
|
||||
.gap_3()
|
||||
|
||||
+13
-1
@@ -2,7 +2,8 @@ use std::{rc::Rc, time::Duration};
|
||||
|
||||
use gpui::{
|
||||
App, Div, ElementId, InteractiveElement, IntoElement, MouseButton, ParentElement, RenderOnce,
|
||||
ScrollHandle, SharedString, StatefulInteractiveElement, StyleRefinement, Styled, Window, div,
|
||||
Role, ScrollHandle, SharedString, StatefulInteractiveElement, StyleRefinement, Styled, Window,
|
||||
div, prelude::FluentBuilder as _,
|
||||
};
|
||||
use web_time::Instant;
|
||||
|
||||
@@ -86,6 +87,7 @@ pub struct SelectableList {
|
||||
rows: Vec<(SharedString, ListItem)>,
|
||||
selected: Vec<SharedString>,
|
||||
multiple: bool,
|
||||
label: Option<SharedString>,
|
||||
on_change: Option<OnSelect>,
|
||||
on_activate: Option<OnActivate>,
|
||||
}
|
||||
@@ -98,6 +100,7 @@ impl SelectableList {
|
||||
rows: Vec::new(),
|
||||
selected: Vec::new(),
|
||||
multiple: false,
|
||||
label: None,
|
||||
on_change: None,
|
||||
on_activate: None,
|
||||
}
|
||||
@@ -114,6 +117,12 @@ impl SelectableList {
|
||||
self
|
||||
}
|
||||
|
||||
/// Names the list for assistive tech.
|
||||
pub fn label(mut self, label: impl Into<SharedString>) -> Self {
|
||||
self.label = Some(label.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn multiple(mut self) -> Self {
|
||||
self.multiple = true;
|
||||
self
|
||||
@@ -249,6 +258,7 @@ impl RenderOnce for SelectableList {
|
||||
.map(|(ix, (key, item))| {
|
||||
let (pick, focus, activate) = (pick.clone(), focus.clone(), activate.clone());
|
||||
item.selected(selected.contains(&key))
|
||||
.place(ix + 1, count)
|
||||
.current(focused && ix == at)
|
||||
.on_click(move |event, window, cx| {
|
||||
let held = event.modifiers();
|
||||
@@ -269,6 +279,8 @@ impl RenderOnce for SelectableList {
|
||||
(cursor.clone(), activate.clone(), off.clone(), keys.clone());
|
||||
self.base
|
||||
.id(self.id)
|
||||
.role(Role::List)
|
||||
.when_some(self.label, |list, label| list.aria_label(label))
|
||||
.track_focus(&focus)
|
||||
.track_scroll(&scroll)
|
||||
.overflow_y_scroll()
|
||||
|
||||
Reference in new issue
Block a user