Dialogs, a11y · Dialog card names its role, title and detail; prompt error reads as a label; Cancel and Close read i18n; a disabled button says so in its description
This commit is contained in:
6 files changed
+39
-11
No files matched your search
@@ -5,6 +5,7 @@ use gpui::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
i18n,
|
||||
motion::Spinner,
|
||||
primitives::{FocusRing, Icon, IconName},
|
||||
theme::{ActiveTheme, ControlSize, IconSize, Mix, Palette, Platform, Radius, TextSize},
|
||||
@@ -291,7 +292,10 @@ impl RenderOnce for Button {
|
||||
})
|
||||
.map(|el| {
|
||||
if self.disabled {
|
||||
return el.opacity(0.45).cursor_not_allowed();
|
||||
return el
|
||||
.aria_description(i18n::text(cx, "state.unavailable", &[]))
|
||||
.opacity(0.45)
|
||||
.cursor_not_allowed();
|
||||
}
|
||||
let el = match &self.focus {
|
||||
Some(handle) => el.track_focus(handle),
|
||||
|
||||
@@ -5,6 +5,7 @@ use gpui::{
|
||||
|
||||
use super::button::{ButtonVariant, ClickHandler, label_size, tone};
|
||||
use crate::{
|
||||
i18n,
|
||||
primitives::{FocusRing, Icon, IconName, Tooltip},
|
||||
theme::{ActiveTheme, ControlSize, Radius},
|
||||
};
|
||||
@@ -92,7 +93,10 @@ impl RenderOnce for IconButton {
|
||||
.when_some(self.tooltip, |el, text| el.tooltip(Tooltip::text(text)))
|
||||
.map(|el| {
|
||||
if self.disabled {
|
||||
return el.opacity(0.45).cursor_not_allowed();
|
||||
return el
|
||||
.aria_description(i18n::text(cx, "state.unavailable", &[]))
|
||||
.opacity(0.45)
|
||||
.cursor_not_allowed();
|
||||
}
|
||||
el.cursor_pointer()
|
||||
.tab_index(0)
|
||||
|
||||
@@ -32,6 +32,9 @@ const EN: &[(&str, &str)] = &[
|
||||
("palette.branch.delete", "Delete"),
|
||||
("palette.history.placeholder", "Search past commands"),
|
||||
("palette.history.empty", "No past command fits"),
|
||||
("dialog.cancel", "Cancel"),
|
||||
("dialog.close", "Close"),
|
||||
("state.unavailable", "Unavailable"),
|
||||
];
|
||||
|
||||
const ZH_CN: &[(&str, &str)] = &[
|
||||
@@ -62,6 +65,9 @@ const ZH_CN: &[(&str, &str)] = &[
|
||||
("palette.branch.delete", "删除"),
|
||||
("palette.history.placeholder", "搜索历史命令"),
|
||||
("palette.history.empty", "没有匹配的历史命令"),
|
||||
("dialog.cancel", "取消"),
|
||||
("dialog.close", "关闭"),
|
||||
("state.unavailable", "不可用"),
|
||||
];
|
||||
|
||||
/// Ely's own message for `key` in `locale`, English for a locale Ely does not ship; fails on an unknown key.
|
||||
|
||||
@@ -10,6 +10,7 @@ use super::TabOverflowMenu;
|
||||
use crate::{
|
||||
buttons::{ButtonVariant, IconButton},
|
||||
forms::Choice,
|
||||
i18n,
|
||||
primitives::{DragGhost, Icon, IconName},
|
||||
theme::{ActiveTheme, ControlSize, IconSize, TextSize},
|
||||
};
|
||||
@@ -206,7 +207,7 @@ impl RenderOnce for EditorTabs {
|
||||
IconButton::new(("close", ix), IconName::X)
|
||||
.size(ControlSize::Sm)
|
||||
.variant(ButtonVariant::Ghost)
|
||||
.tooltip("Close")
|
||||
.tooltip(i18n::text(cx, "dialog.close", &[]))
|
||||
.on_click(move |_, window, cx| {
|
||||
cx.stop_propagation();
|
||||
run(&close, "close", &slot_id, window, cx);
|
||||
|
||||
+11
-4
@@ -2,15 +2,15 @@ use std::rc::Rc;
|
||||
|
||||
use gpui::{
|
||||
Animation, AnimationExt, AnyElement, App, ElementId, FocusHandle, FontWeight,
|
||||
InteractiveElement, IntoElement, ParentElement, Pixels, RenderOnce, SharedString, Styled,
|
||||
Window, anchored, div, point, prelude::*,
|
||||
InteractiveElement, IntoElement, ParentElement, Pixels, RenderOnce, Role, SharedString,
|
||||
StatefulInteractiveElement, Styled, Window, anchored, div, point, prelude::*,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::{
|
||||
buttons::{ButtonVariant, IconButton},
|
||||
forms::{Enter, Run},
|
||||
motion,
|
||||
i18n, motion,
|
||||
primitives::{Backdrop, FocusScope, IconName, give_back, raise, take_focus},
|
||||
theme::{ActiveTheme, Elevation, Radius, TextSize},
|
||||
};
|
||||
@@ -119,6 +119,7 @@ impl RenderOnce for Dialog {
|
||||
};
|
||||
let theme = cx.theme();
|
||||
let colors = &theme.colors;
|
||||
let (title, description) = (self.title.clone(), self.detail.clone());
|
||||
let heading = div()
|
||||
.flex_none()
|
||||
.flex()
|
||||
@@ -164,6 +165,9 @@ impl RenderOnce for Dialog {
|
||||
let card = if fullscreen {
|
||||
div()
|
||||
.id(self.id.clone())
|
||||
.role(Role::Dialog)
|
||||
.aria_label(title)
|
||||
.when_some(description, |card, text| card.aria_description(text))
|
||||
.flex()
|
||||
.flex_col()
|
||||
.size_full()
|
||||
@@ -182,7 +186,7 @@ impl RenderOnce for Dialog {
|
||||
.child(
|
||||
IconButton::new((self.id.clone(), "close"), IconName::X)
|
||||
.variant(ButtonVariant::Ghost)
|
||||
.tooltip("Close")
|
||||
.tooltip(i18n::text(cx, "dialog.close", &[]))
|
||||
.on_click(move |_, window, cx| button(window, cx)),
|
||||
),
|
||||
)
|
||||
@@ -214,6 +218,9 @@ impl RenderOnce for Dialog {
|
||||
});
|
||||
div()
|
||||
.id(self.id.clone())
|
||||
.role(Role::Dialog)
|
||||
.aria_label(title)
|
||||
.when_some(description, |card, text| card.aria_description(text))
|
||||
.flex()
|
||||
.flex_col()
|
||||
.gap_5()
|
||||
|
||||
+10
-4
@@ -1,14 +1,15 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use gpui::{
|
||||
App, ElementId, Entity, IntoElement, ParentElement, RenderOnce, SharedString, Styled, Window,
|
||||
div, prelude::*,
|
||||
App, ElementId, Entity, IntoElement, ParentElement, RenderOnce, Role, SharedString,
|
||||
StatefulInteractiveElement, Styled, Window, div, prelude::*,
|
||||
};
|
||||
|
||||
use super::{Close, Dialog};
|
||||
use crate::{
|
||||
buttons::{Button, ButtonVariant},
|
||||
forms::{Input, Run, TextInput},
|
||||
i18n,
|
||||
primitives::{Icon, Severity},
|
||||
theme::{ActiveTheme, ControlSize, IconSize, TextSize},
|
||||
};
|
||||
@@ -156,10 +157,11 @@ impl RenderOnce for ConfirmDialog {
|
||||
};
|
||||
let (cancel_id, confirm_id) = ((self.id.clone(), "cancel"), (self.id.clone(), "confirm"));
|
||||
let on_close = self.on_close;
|
||||
let cancel = i18n::text(cx, "dialog.cancel", &[]);
|
||||
Dialog::new(self.id, self.title, move |window, cx| on_close(window, cx))
|
||||
.child(said(None, self.message, cx))
|
||||
.action(move |close| {
|
||||
Button::new(cancel_id, "Cancel")
|
||||
Button::new(cancel_id, cancel)
|
||||
.variant(ButtonVariant::Ghost)
|
||||
.on_click(move |_, window, cx| close(window, cx))
|
||||
})
|
||||
@@ -295,6 +297,9 @@ impl RenderOnce for PromptDialog {
|
||||
|field, reason| {
|
||||
field.child(
|
||||
div()
|
||||
.id((self.id.clone(), "error"))
|
||||
.role(Role::Label)
|
||||
.aria_label(reason.clone())
|
||||
.text_size(theme.text_size(TextSize::Xs))
|
||||
.text_color(colors.danger)
|
||||
.child(reason),
|
||||
@@ -306,13 +311,14 @@ impl RenderOnce for PromptDialog {
|
||||
(self.id.clone(), "submit"),
|
||||
self.submit,
|
||||
);
|
||||
let cancel = i18n::text(cx, "dialog.cancel", &[]);
|
||||
let on_close = self.on_close;
|
||||
Dialog::new(self.id, self.title, move |window, cx| on_close(window, cx))
|
||||
.focus_first(self.field.read(cx).focus().clone())
|
||||
.on_enter(move |close| Rc::new(move |window, cx| lifted(&close, window, cx)))
|
||||
.child(field)
|
||||
.action(move |close| {
|
||||
Button::new(cancel_id, "Cancel")
|
||||
Button::new(cancel_id, cancel)
|
||||
.variant(ButtonVariant::Ghost)
|
||||
.on_click(move |_, window, cx| close(window, cx))
|
||||
})
|
||||
|
||||
Reference in new issue
Block a user