ui: Wire up tab indices within buttons (#35368)

This change adds the current tab index functionality to buttons and
implements a proof of concept for the new welcome page.

Primarily blocked on https://github.com/zed-industries/zed/pull/34804,
secondarily on https://github.com/zed-industries/zed/pull/35075 so we
can ensure navigation always works as intended.

Another thing to consider here is whether we want to assign the tab
order more implicitly / "automatically" based on the current layout
ordering. This would generally enable us to add a default order to
focusable elements if we want this. See [the
specification](https://html.spec.whatwg.org/multipage/interaction.html#flattened-tabindex-ordered-focus-navigation-scope)
on some more context on how the web usually handles this for focusable
elements.

Release Notes:

- N/A
This commit is contained in:
Finn Evers 2025-08-05 19:05:18 +02:00 committed by GitHub
parent 5940ed979f
commit 19c1504c8f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 53 additions and 6 deletions

View file

@ -393,6 +393,11 @@ impl ButtonCommon for Button {
self
}
fn tab_index(mut self, tab_index: impl Into<isize>) -> Self {
self.base = self.base.tab_index(tab_index);
self
}
fn layer(mut self, elevation: ElevationIndex) -> Self {
self.base = self.base.layer(elevation);
self

View file

@ -1,7 +1,7 @@
use documented::Documented;
use gpui::{
AnyElement, AnyView, ClickEvent, CursorStyle, DefiniteLength, Hsla, MouseButton,
MouseDownEvent, MouseUpEvent, Rems, relative, transparent_black,
MouseDownEvent, MouseUpEvent, Rems, StyleRefinement, relative, transparent_black,
};
use smallvec::SmallVec;
@ -37,6 +37,8 @@ pub trait ButtonCommon: Clickable + Disableable {
/// exceptions might a scroll bar, or a slider.
fn tooltip(self, tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static) -> Self;
fn tab_index(self, tab_index: impl Into<isize>) -> Self;
fn layer(self, elevation: ElevationIndex) -> Self;
}
@ -393,6 +395,7 @@ pub struct ButtonLike {
pub(super) width: Option<DefiniteLength>,
pub(super) height: Option<DefiniteLength>,
pub(super) layer: Option<ElevationIndex>,
tab_index: Option<isize>,
size: ButtonSize,
rounding: Option<ButtonLikeRounding>,
tooltip: Option<Box<dyn Fn(&mut Window, &mut App) -> AnyView>>,
@ -421,6 +424,7 @@ impl ButtonLike {
on_click: None,
on_right_click: None,
layer: None,
tab_index: None,
}
}
@ -525,6 +529,11 @@ impl ButtonCommon for ButtonLike {
self
}
fn tab_index(mut self, tab_index: impl Into<isize>) -> Self {
self.tab_index = Some(tab_index.into());
self
}
fn layer(mut self, elevation: ElevationIndex) -> Self {
self.layer = Some(elevation);
self
@ -554,6 +563,7 @@ impl RenderOnce for ButtonLike {
self.base
.h_flex()
.id(self.id.clone())
.when_some(self.tab_index, |this, tab_index| this.tab_index(tab_index))
.font_ui(cx)
.group("")
.flex_none()
@ -591,8 +601,12 @@ impl RenderOnce for ButtonLike {
}
})
.when(!self.disabled, |this| {
let hovered_style = style.hovered(self.layer, cx);
let focus_color =
|refinement: StyleRefinement| refinement.bg(hovered_style.background);
this.cursor(self.cursor_style)
.hover(|hover| hover.bg(style.hovered(self.layer, cx).background))
.hover(focus_color)
.focus(focus_color)
.active(|active| active.bg(style.active(cx).background))
})
.when_some(

View file

@ -164,6 +164,11 @@ impl ButtonCommon for IconButton {
self
}
fn tab_index(mut self, tab_index: impl Into<isize>) -> Self {
self.base = self.base.tab_index(tab_index);
self
}
fn layer(mut self, elevation: ElevationIndex) -> Self {
self.base = self.base.layer(elevation);
self

View file

@ -121,6 +121,11 @@ impl ButtonCommon for ToggleButton {
self
}
fn tab_index(mut self, tab_index: impl Into<isize>) -> Self {
self.base = self.base.tab_index(tab_index);
self
}
fn layer(mut self, elevation: ElevationIndex) -> Self {
self.base = self.base.layer(elevation);
self