onboarding: Wire up tab index (#35659)

Closes #ISSUE

Allows tabbing through everything in all three pages. Until #35075 is
merged it is not possible to actually "click" tab focused buttons with
the keyboard.

Additionally adds an action `onboarding::Finish` and displays the
keybind. The action corresponds to both the "Skip all" and "Start
Building" buttons, with the keybind displayed similar to how it is for
the page nav buttons

Release Notes:

- N/A *or* Added/Fixed/Improved ...

---------

Co-authored-by: MrSubidubi <finn@zed.dev>
This commit is contained in:
Ben Kunkle
2025-08-05 19:48:15 +00:00
committed by GitHub
co-authored by MrSubidubi
parent 0b5592d788
commit 6b77654f66
11 changed files with 505 additions and 280 deletions
+60 -44
View File
@@ -424,6 +424,7 @@ pub struct Switch {
label: Option<SharedString>,
key_binding: Option<KeyBinding>,
color: SwitchColor,
tab_index: Option<isize>,
}
impl Switch {
@@ -437,6 +438,7 @@ impl Switch {
label: None,
key_binding: None,
color: SwitchColor::default(),
tab_index: None,
}
}
@@ -472,6 +474,11 @@ impl Switch {
self.key_binding = key_binding.into();
self
}
pub fn tab_index(mut self, tab_index: impl Into<isize>) -> Self {
self.tab_index = Some(tab_index.into());
self
}
}
impl RenderOnce for Switch {
@@ -501,6 +508,20 @@ impl RenderOnce for Switch {
.w(DynamicSpacing::Base32.rems(cx))
.h(DynamicSpacing::Base20.rems(cx))
.group(group_id.clone())
.border_1()
.p(px(1.0))
.border_color(cx.theme().colors().border_transparent)
.rounded_full()
.id((self.id.clone(), "switch"))
.when_some(
self.tab_index.filter(|_| !self.disabled),
|this, tab_index| {
this.tab_index(tab_index).focus(|mut style| {
style.border_color = Some(cx.theme().colors().border_focused);
style
})
},
)
.child(
h_flex()
.when(is_on, |on| on.justify_end())
@@ -572,6 +593,7 @@ pub struct SwitchField {
disabled: bool,
color: SwitchColor,
tooltip: Option<Rc<dyn Fn(&mut Window, &mut App) -> AnyView>>,
tab_index: Option<isize>,
}
impl SwitchField {
@@ -591,6 +613,7 @@ impl SwitchField {
disabled: false,
color: SwitchColor::Accent,
tooltip: None,
tab_index: None,
}
}
@@ -615,14 +638,33 @@ impl SwitchField {
self.tooltip = Some(Rc::new(tooltip));
self
}
pub fn tab_index(mut self, tab_index: isize) -> Self {
self.tab_index = Some(tab_index);
self
}
}
impl RenderOnce for SwitchField {
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
let tooltip = self.tooltip;
let tooltip = self.tooltip.map(|tooltip_fn| {
h_flex()
.gap_0p5()
.child(Label::new(self.label.clone()))
.child(
IconButton::new("tooltip_button", IconName::Info)
.icon_size(IconSize::XSmall)
.icon_color(Color::Muted)
.shape(crate::IconButtonShape::Square)
.tooltip({
let tooltip = tooltip_fn.clone();
move |window, cx| tooltip(window, cx)
}),
)
});
h_flex()
.id(SharedString::from(format!("{}-container", self.id)))
.id((self.id.clone(), "container"))
.when(!self.disabled, |this| {
this.hover(|this| this.cursor_pointer())
})
@@ -630,25 +672,11 @@ impl RenderOnce for SwitchField {
.gap_4()
.justify_between()
.flex_wrap()
.child(match (&self.description, &tooltip) {
.child(match (&self.description, tooltip) {
(Some(description), Some(tooltip)) => v_flex()
.gap_0p5()
.max_w_5_6()
.child(
h_flex()
.gap_0p5()
.child(Label::new(self.label.clone()))
.child(
IconButton::new("tooltip_button", IconName::Info)
.icon_size(IconSize::XSmall)
.icon_color(Color::Muted)
.shape(crate::IconButtonShape::Square)
.tooltip({
let tooltip = tooltip.clone();
move |window, cx| tooltip(window, cx)
}),
),
)
.child(tooltip)
.child(Label::new(description.clone()).color(Color::Muted))
.into_any_element(),
(Some(description), None) => v_flex()
@@ -657,35 +685,23 @@ impl RenderOnce for SwitchField {
.child(Label::new(self.label.clone()))
.child(Label::new(description.clone()).color(Color::Muted))
.into_any_element(),
(None, Some(tooltip)) => h_flex()
.gap_0p5()
.child(Label::new(self.label.clone()))
.child(
IconButton::new("tooltip_button", IconName::Info)
.icon_size(IconSize::XSmall)
.icon_color(Color::Muted)
.shape(crate::IconButtonShape::Square)
.tooltip({
let tooltip = tooltip.clone();
move |window, cx| tooltip(window, cx)
}),
)
.into_any_element(),
(None, Some(tooltip)) => tooltip.into_any_element(),
(None, None) => Label::new(self.label.clone()).into_any_element(),
})
.child(
Switch::new(
SharedString::from(format!("{}-switch", self.id)),
self.toggle_state,
)
.color(self.color)
.disabled(self.disabled)
.on_click({
let on_click = self.on_click.clone();
move |state, window, cx| {
(on_click)(state, window, cx);
}
}),
Switch::new((self.id.clone(), "switch"), self.toggle_state)
.color(self.color)
.disabled(self.disabled)
.when_some(
self.tab_index.filter(|_| !self.disabled),
|this, tab_index| this.tab_index(tab_index),
)
.on_click({
let on_click = self.on_click.clone();
move |state, window, cx| {
(on_click)(state, window, cx);
}
}),
)
.when(!self.disabled, |this| {
this.on_click({