feat(a11y): screen reader name and description support for button widgets
This commit is contained in:
parent
f6039597b7
commit
b9c24d2421
6 changed files with 122 additions and 19 deletions
|
|
@ -38,6 +38,10 @@ impl<Message> Button<'_, Message> {
|
||||||
Self {
|
Self {
|
||||||
id: Id::unique(),
|
id: Id::unique(),
|
||||||
label: Cow::Borrowed(""),
|
label: Cow::Borrowed(""),
|
||||||
|
#[cfg(feature = "a11y")]
|
||||||
|
name: Cow::Borrowed(""),
|
||||||
|
#[cfg(feature = "a11y")]
|
||||||
|
description: Cow::Borrowed(""),
|
||||||
tooltip: Cow::Borrowed(""),
|
tooltip: Cow::Borrowed(""),
|
||||||
on_press: None,
|
on_press: None,
|
||||||
width: Length::Shrink,
|
width: Length::Shrink,
|
||||||
|
|
@ -151,7 +155,7 @@ impl<'a, Message: Clone + 'static> From<Button<'a, Message>> for Element<'a, Mes
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let button = if builder.variant.vertical {
|
let mut button = if builder.variant.vertical {
|
||||||
crate::widget::column::with_children(content)
|
crate::widget::column::with_children(content)
|
||||||
.padding(builder.padding)
|
.padding(builder.padding)
|
||||||
.spacing(builder.spacing)
|
.spacing(builder.spacing)
|
||||||
|
|
@ -167,6 +171,11 @@ impl<'a, Message: Clone + 'static> From<Button<'a, Message>> for Element<'a, Mes
|
||||||
.apply(super::custom)
|
.apply(super::custom)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "a11y")]
|
||||||
|
{
|
||||||
|
button = button.name(builder.name).description(builder.description);
|
||||||
|
}
|
||||||
|
|
||||||
let button = button
|
let button = button
|
||||||
.padding(0)
|
.padding(0)
|
||||||
.id(builder.id)
|
.id(builder.id)
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,10 @@ impl<'a, Message> Button<'a, Message> {
|
||||||
Self {
|
Self {
|
||||||
id: Id::unique(),
|
id: Id::unique(),
|
||||||
label: Cow::Borrowed(""),
|
label: Cow::Borrowed(""),
|
||||||
|
#[cfg(feature = "a11y")]
|
||||||
|
name: Cow::Borrowed(""),
|
||||||
|
#[cfg(feature = "a11y")]
|
||||||
|
description: Cow::Borrowed(""),
|
||||||
tooltip: Cow::Borrowed(""),
|
tooltip: Cow::Borrowed(""),
|
||||||
on_press: None,
|
on_press: None,
|
||||||
width: Length::Shrink,
|
width: Length::Shrink,
|
||||||
|
|
@ -79,12 +83,18 @@ where
|
||||||
.width(builder.width)
|
.width(builder.width)
|
||||||
.height(builder.height);
|
.height(builder.height);
|
||||||
|
|
||||||
super::custom_image_button(content, builder.variant.on_remove)
|
let mut button = super::custom_image_button(content, builder.variant.on_remove)
|
||||||
.padding(0)
|
.padding(0)
|
||||||
.selected(builder.variant.selected)
|
.selected(builder.variant.selected)
|
||||||
.id(builder.id)
|
.id(builder.id)
|
||||||
.on_press_maybe(builder.on_press)
|
.on_press_maybe(builder.on_press)
|
||||||
.class(builder.class)
|
.class(builder.class);
|
||||||
.into()
|
|
||||||
|
#[cfg(feature = "a11y")]
|
||||||
|
{
|
||||||
|
button = button.name(builder.name).description(builder.description);
|
||||||
|
}
|
||||||
|
|
||||||
|
button.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,10 @@ impl<'a, Message> Button<'a, Message> {
|
||||||
Self {
|
Self {
|
||||||
id: Id::unique(),
|
id: Id::unique(),
|
||||||
label: label.into(),
|
label: label.into(),
|
||||||
|
#[cfg(feature = "a11y")]
|
||||||
|
name: Cow::Borrowed(""),
|
||||||
|
#[cfg(feature = "a11y")]
|
||||||
|
description: Cow::Borrowed(""),
|
||||||
tooltip: Cow::Borrowed(""),
|
tooltip: Cow::Borrowed(""),
|
||||||
on_press: None,
|
on_press: None,
|
||||||
width: Length::Shrink,
|
width: Length::Shrink,
|
||||||
|
|
@ -62,7 +66,7 @@ pub fn icon() -> Handle {
|
||||||
|
|
||||||
impl<'a, Message: Clone + 'static> From<Button<'a, Message>> for Element<'a, Message> {
|
impl<'a, Message: Clone + 'static> From<Button<'a, Message>> for Element<'a, Message> {
|
||||||
fn from(mut builder: Button<'a, Message>) -> Element<'a, Message> {
|
fn from(mut builder: Button<'a, Message>) -> Element<'a, Message> {
|
||||||
let button: super::Button<'a, Message> = row::with_capacity(2)
|
let mut button: super::Button<'a, Message> = row::with_capacity(2)
|
||||||
.push({
|
.push({
|
||||||
// TODO: Avoid allocation
|
// TODO: Avoid allocation
|
||||||
crate::widget::text(builder.label.to_string())
|
crate::widget::text(builder.label.to_string())
|
||||||
|
|
@ -89,6 +93,15 @@ impl<'a, Message: Clone + 'static> From<Button<'a, Message>> for Element<'a, Mes
|
||||||
.on_press_maybe(builder.on_press.take())
|
.on_press_maybe(builder.on_press.take())
|
||||||
.class(builder.class);
|
.class(builder.class);
|
||||||
|
|
||||||
|
#[cfg(feature = "a11y")]
|
||||||
|
{
|
||||||
|
if !builder.label.is_empty() {
|
||||||
|
button = button.name(builder.label);
|
||||||
|
}
|
||||||
|
|
||||||
|
button = button.description(builder.description);
|
||||||
|
}
|
||||||
|
|
||||||
if builder.tooltip.is_empty() {
|
if builder.tooltip.is_empty() {
|
||||||
button.into()
|
button.into()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,16 @@ pub struct Builder<'a, Message, Variant> {
|
||||||
#[setters(into)]
|
#[setters(into)]
|
||||||
label: Cow<'a, str>,
|
label: Cow<'a, str>,
|
||||||
|
|
||||||
|
/// A name for screen reader support
|
||||||
|
#[cfg(feature = "a11y")]
|
||||||
|
#[setters(into)]
|
||||||
|
name: Cow<'a, str>,
|
||||||
|
|
||||||
|
/// A description for screen reader support
|
||||||
|
#[cfg(feature = "a11y")]
|
||||||
|
#[setters(into)]
|
||||||
|
description: Cow<'a, str>,
|
||||||
|
|
||||||
// Adds a tooltip to the button.
|
// Adds a tooltip to the button.
|
||||||
#[setters(into)]
|
#[setters(into)]
|
||||||
tooltip: Cow<'a, str>,
|
tooltip: Cow<'a, str>,
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,10 @@ impl<Message> Button<'_, Message> {
|
||||||
Self {
|
Self {
|
||||||
id: Id::unique(),
|
id: Id::unique(),
|
||||||
label: Cow::Borrowed(""),
|
label: Cow::Borrowed(""),
|
||||||
|
#[cfg(feature = "a11y")]
|
||||||
|
name: Cow::Borrowed(""),
|
||||||
|
#[cfg(feature = "a11y")]
|
||||||
|
description: Cow::Borrowed(""),
|
||||||
tooltip: Cow::Borrowed(""),
|
tooltip: Cow::Borrowed(""),
|
||||||
on_press: None,
|
on_press: None,
|
||||||
width: Length::Shrink,
|
width: Length::Shrink,
|
||||||
|
|
@ -136,8 +140,10 @@ impl<'a, Message: Clone + 'static> From<Button<'a, Message>> for Element<'a, Mes
|
||||||
#[cfg(feature = "a11y")]
|
#[cfg(feature = "a11y")]
|
||||||
{
|
{
|
||||||
if !builder.label.is_empty() {
|
if !builder.label.is_empty() {
|
||||||
button = button.name(builder.label);
|
button = button.name(builder.label)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button = button.description(builder.description);
|
||||||
}
|
}
|
||||||
|
|
||||||
if builder.tooltip.is_empty() {
|
if builder.tooltip.is_empty() {
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ use std::ops::{Add, Sub};
|
||||||
/// Horizontal spin button widget.
|
/// Horizontal spin button widget.
|
||||||
pub fn spin_button<'a, T, M>(
|
pub fn spin_button<'a, T, M>(
|
||||||
label: impl Into<Cow<'a, str>>,
|
label: impl Into<Cow<'a, str>>,
|
||||||
|
#[cfg(feature = "a11y")] name: impl Into<Cow<'a, str>>,
|
||||||
value: T,
|
value: T,
|
||||||
step: T,
|
step: T,
|
||||||
min: T,
|
min: T,
|
||||||
|
|
@ -25,7 +26,7 @@ pub fn spin_button<'a, T, M>(
|
||||||
where
|
where
|
||||||
T: Copy + Sub<Output = T> + Add<Output = T> + PartialOrd,
|
T: Copy + Sub<Output = T> + Add<Output = T> + PartialOrd,
|
||||||
{
|
{
|
||||||
SpinButton::new(
|
let mut button = SpinButton::new(
|
||||||
label,
|
label,
|
||||||
value,
|
value,
|
||||||
step,
|
step,
|
||||||
|
|
@ -33,12 +34,20 @@ where
|
||||||
max,
|
max,
|
||||||
Orientation::Horizontal,
|
Orientation::Horizontal,
|
||||||
on_press,
|
on_press,
|
||||||
)
|
);
|
||||||
|
|
||||||
|
#[cfg(feature = "a11y")]
|
||||||
|
{
|
||||||
|
button = button.name(name.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
button
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Vertical spin button widget.
|
/// Vertical spin button widget.
|
||||||
pub fn vertical<'a, T, M>(
|
pub fn vertical<'a, T, M>(
|
||||||
label: impl Into<Cow<'a, str>>,
|
label: impl Into<Cow<'a, str>>,
|
||||||
|
#[cfg(feature = "a11y")] name: impl Into<Cow<'a, str>>,
|
||||||
value: T,
|
value: T,
|
||||||
step: T,
|
step: T,
|
||||||
min: T,
|
min: T,
|
||||||
|
|
@ -48,15 +57,22 @@ pub fn vertical<'a, T, M>(
|
||||||
where
|
where
|
||||||
T: Copy + Sub<Output = T> + Add<Output = T> + PartialOrd,
|
T: Copy + Sub<Output = T> + Add<Output = T> + PartialOrd,
|
||||||
{
|
{
|
||||||
SpinButton::new(
|
let mut button = SpinButton::new(
|
||||||
label,
|
label,
|
||||||
value,
|
value,
|
||||||
step,
|
step,
|
||||||
min,
|
min,
|
||||||
max,
|
max,
|
||||||
Orientation::Vertical,
|
Orientation::Horizontal,
|
||||||
on_press,
|
on_press,
|
||||||
)
|
);
|
||||||
|
|
||||||
|
#[cfg(feature = "a11y")]
|
||||||
|
{
|
||||||
|
button = button.name(name.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
button
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
|
@ -71,6 +87,9 @@ where
|
||||||
{
|
{
|
||||||
/// The formatted value of the spin button.
|
/// The formatted value of the spin button.
|
||||||
label: Cow<'a, str>,
|
label: Cow<'a, str>,
|
||||||
|
/// A name for screen reader support.
|
||||||
|
#[cfg(feature = "a11y")]
|
||||||
|
name: Cow<'a, str>,
|
||||||
/// The current value of the spin button.
|
/// The current value of the spin button.
|
||||||
value: T,
|
value: T,
|
||||||
/// The amount to increment or decrement the value.
|
/// The amount to increment or decrement the value.
|
||||||
|
|
@ -99,6 +118,8 @@ where
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
label: label.into(),
|
label: label.into(),
|
||||||
|
#[cfg(feature = "a11y")]
|
||||||
|
name: Cow::Borrowed(""),
|
||||||
step,
|
step,
|
||||||
value: if value < min {
|
value: if value < min {
|
||||||
min
|
min
|
||||||
|
|
@ -113,6 +134,12 @@ where
|
||||||
on_press: Box::from(on_press),
|
on_press: Box::from(on_press),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "a11y")]
|
||||||
|
pub(self) fn name(mut self, name: Cow<'a, str>) -> Self {
|
||||||
|
self.name = name;
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn increment<T>(value: T, step: T, _min: T, max: T) -> T
|
fn increment<T>(value: T, step: T, _min: T, max: T) -> T
|
||||||
|
|
@ -153,21 +180,28 @@ where
|
||||||
fn make_button<'a, T, Message>(
|
fn make_button<'a, T, Message>(
|
||||||
spin_button: &SpinButton<'a, T, Message>,
|
spin_button: &SpinButton<'a, T, Message>,
|
||||||
icon: &'static str,
|
icon: &'static str,
|
||||||
|
#[cfg(feature = "a11y")] name: String,
|
||||||
operation: fn(T, T, T, T) -> T,
|
operation: fn(T, T, T, T) -> T,
|
||||||
) -> Element<'a, Message>
|
) -> Element<'a, Message>
|
||||||
where
|
where
|
||||||
Message: Clone + 'static,
|
Message: Clone + 'static,
|
||||||
T: Copy + Sub<Output = T> + Add<Output = T> + PartialOrd,
|
T: Copy + Sub<Output = T> + Add<Output = T> + PartialOrd,
|
||||||
{
|
{
|
||||||
icon::from_name(icon)
|
let mut button = icon::from_name(icon)
|
||||||
.apply(button::icon)
|
.apply(button::icon)
|
||||||
.on_press((spin_button.on_press)(operation(
|
.on_press((spin_button.on_press)(operation(
|
||||||
spin_button.value,
|
spin_button.value,
|
||||||
spin_button.step,
|
spin_button.step,
|
||||||
spin_button.min,
|
spin_button.min,
|
||||||
spin_button.max,
|
spin_button.max,
|
||||||
)))
|
)));
|
||||||
.into()
|
|
||||||
|
#[cfg(feature = "a11y")]
|
||||||
|
{
|
||||||
|
button = button.name(name.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
button.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn horizontal_variant<T, Message>(spin_button: SpinButton<'_, T, Message>) -> Element<'_, Message>
|
fn horizontal_variant<T, Message>(spin_button: SpinButton<'_, T, Message>) -> Element<'_, Message>
|
||||||
|
|
@ -175,9 +209,20 @@ where
|
||||||
Message: Clone + 'static,
|
Message: Clone + 'static,
|
||||||
T: Copy + Sub<Output = T> + Add<Output = T> + PartialOrd,
|
T: Copy + Sub<Output = T> + Add<Output = T> + PartialOrd,
|
||||||
{
|
{
|
||||||
let decrement_button = make_button(&spin_button, "list-remove-symbolic", decrement);
|
let decrement_button = make_button(
|
||||||
let increment_button = make_button(&spin_button, "list-add-symbolic", increment);
|
&spin_button,
|
||||||
|
"list-remove-symbolic",
|
||||||
|
#[cfg(feature = "a11y")]
|
||||||
|
[&spin_button.name, " decrease"].concat(),
|
||||||
|
decrement,
|
||||||
|
);
|
||||||
|
let increment_button = make_button(
|
||||||
|
&spin_button,
|
||||||
|
"list-add-symbolic",
|
||||||
|
#[cfg(feature = "a11y")]
|
||||||
|
[&spin_button.name, " increase"].concat(),
|
||||||
|
increment,
|
||||||
|
);
|
||||||
let label = text::body(spin_button.label)
|
let label = text::body(spin_button.label)
|
||||||
.apply(container)
|
.apply(container)
|
||||||
.center_x(Length::Fixed(48.0))
|
.center_x(Length::Fixed(48.0))
|
||||||
|
|
@ -198,8 +243,18 @@ where
|
||||||
Message: Clone + 'static,
|
Message: Clone + 'static,
|
||||||
T: Copy + Sub<Output = T> + Add<Output = T> + PartialOrd,
|
T: Copy + Sub<Output = T> + Add<Output = T> + PartialOrd,
|
||||||
{
|
{
|
||||||
let decrement_button = make_button(&spin_button, "list-remove-symbolic", decrement);
|
let decrement_button = make_button(
|
||||||
let increment_button = make_button(&spin_button, "list-add-symbolic", increment);
|
&spin_button,
|
||||||
|
"list-remove-symbolic",
|
||||||
|
[&spin_button.label, " decrease"].concat(),
|
||||||
|
decrement,
|
||||||
|
);
|
||||||
|
let increment_button = make_button(
|
||||||
|
&spin_button,
|
||||||
|
"list-add-symbolic",
|
||||||
|
[&spin_button.label, " increase"].concat(),
|
||||||
|
increment,
|
||||||
|
);
|
||||||
|
|
||||||
let label = text::body(spin_button.label)
|
let label = text::body(spin_button.label)
|
||||||
.apply(container)
|
.apply(container)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue