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

@ -15,13 +15,13 @@ path = "src/onboarding.rs"
default = []
[dependencies]
anyhow.workspace = true
ai_onboarding.workspace = true
anyhow.workspace = true
client.workspace = true
command_palette_hooks.workspace = true
component.workspace = true
documented.workspace = true
db.workspace = true
documented.workspace = true
editor.workspace = true
feature_flags.workspace = true
fs.workspace = true

View file

@ -2,6 +2,7 @@ use gpui::{
Action, App, Context, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement,
NoAction, ParentElement, Render, Styled, Window, actions,
};
use menu::{SelectNext, SelectPrevious};
use ui::{ButtonLike, Divider, DividerColor, KeyBinding, Vector, VectorName, prelude::*};
use workspace::{
NewFile, Open, WorkspaceId,
@ -124,6 +125,7 @@ impl SectionEntry {
cx: &App,
) -> impl IntoElement {
ButtonLike::new(("onboarding-button-id", button_index))
.tab_index(button_index as isize)
.full_width()
.size(ButtonSize::Medium)
.child(
@ -153,10 +155,23 @@ pub struct WelcomePage {
focus_handle: FocusHandle,
}
impl WelcomePage {
fn select_next(&mut self, _: &SelectNext, window: &mut Window, cx: &mut Context<Self>) {
window.focus_next();
cx.notify();
}
fn select_previous(&mut self, _: &SelectPrevious, window: &mut Window, cx: &mut Context<Self>) {
window.focus_prev();
cx.notify();
}
}
impl Render for WelcomePage {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let (first_section, second_entries) = CONTENT;
let (first_section, second_section) = CONTENT;
let first_section_entries = first_section.entries.len();
let last_index = first_section_entries + second_section.entries.len();
h_flex()
.size_full()
@ -165,6 +180,8 @@ impl Render for WelcomePage {
.bg(cx.theme().colors().editor_background)
.key_context("Welcome")
.track_focus(&self.focus_handle(cx))
.on_action(cx.listener(Self::select_previous))
.on_action(cx.listener(Self::select_next))
.child(
h_flex()
.px_12()
@ -202,7 +219,7 @@ impl Render for WelcomePage {
window,
cx,
))
.child(second_entries.render(
.child(second_section.render(
first_section_entries,
&self.focus_handle,
window,
@ -220,6 +237,7 @@ impl Render for WelcomePage {
.border_dashed()
.child(
Button::new("welcome-exit", "Return to Setup")
.tab_index(last_index as isize)
.full_width()
.label_size(LabelSize::XSmall)
.on_click(|_, window, cx| {