ui: Rename and simplify NumberField component (#39731)

This commit is contained in:
Danilo Leal
2025-10-07 21:35:51 -03:00
committed by GitHub
parent 8bf37dd130
commit d615525771
5 changed files with 111 additions and 183 deletions
+3 -4
View File
@@ -11,7 +11,7 @@ use ui::{
ButtonLike, PopoverMenu, SwitchField, ToggleButtonGroup, ToggleButtonGroupStyle,
ToggleButtonSimple, ToggleState, Tooltip, prelude::*,
};
use ui_input::{NumericStepper, font_picker};
use ui_input::{NumberField, font_picker};
use crate::{ImportCursorSettings, ImportVsCodeSettings, SettingsImportState};
@@ -411,7 +411,7 @@ fn font_picker_stepper(
write_font_size: fn(Pixels, &mut App),
window: &mut Window,
cx: &mut App,
) -> NumericStepper<u32> {
) -> NumberField<u32> {
window.with_id(id, |window| {
let optimistic_font_size: gpui::Entity<Option<u32>> = window.use_state(cx, |_, _| None);
optimistic_font_size.update(cx, |optimistic_font_size, _| {
@@ -426,7 +426,7 @@ fn font_picker_stepper(
.read(cx)
.unwrap_or_else(|| font_size.into());
NumericStepper::new(
NumberField::new(
SharedString::new(format!("{}-stepper", id)),
stepper_font_size,
window,
@@ -437,7 +437,6 @@ fn font_picker_stepper(
write_font_size(Pixels::from(*new_value), cx);
})
.format(|value| format!("{value}px"))
.style(ui_input::NumericStepperStyle::Outlined)
.tab_index({
*tab_index += 2;
*tab_index - 2
+3 -3
View File
@@ -1053,7 +1053,7 @@ pub(crate) fn user_settings_data() -> Vec<SettingsPage> {
}),
metadata: None,
}),
// todo(settings ui): add units to this numeric stepper
// todo(settings ui): add units to this Number Field
SettingsPageItem::SettingItem(SettingItem {
title: "Hover Popover Delay",
description: "Time to wait in milliseconds before showing the informational hover box",
@@ -4021,7 +4021,7 @@ pub(crate) fn project_settings_data() -> Vec<SettingsPage> {
title: "Editing",
items: vec![
SettingsPageItem::SectionHeader("Indentation"),
// todo(settings_ui): Needs numeric stepper
// todo(settings_ui): Needs Number Field
// SettingsPageItem::SettingItem(SettingItem {
// title: "Tab Size",
// description: "How many columns a tab should occupy",
@@ -4079,7 +4079,7 @@ pub(crate) fn project_settings_data() -> Vec<SettingsPage> {
metadata: None,
}),
SettingsPageItem::SectionHeader("Wrapping"),
// todo(settings_ui): Needs numeric stepper
// todo(settings_ui): Needs Number Field
// SettingsPageItem::SettingItem(SettingItem {
// title: "Preferred Line Length",
// description: "The column at which to soft-wrap lines, for buffers where soft-wrap is enabled",
+12 -13
View File
@@ -32,7 +32,7 @@ use ui::{
ContextMenu, Divider, DropdownMenu, DropdownStyle, IconButtonShape, KeyBinding, KeybindingHint,
PopoverMenu, Switch, SwitchColor, TreeViewItem, WithScrollbar, prelude::*,
};
use ui_input::{NumericStepper, NumericStepperStyle, NumericStepperType};
use ui_input::{NumberField, NumberFieldType};
use util::{ResultExt as _, paths::PathStyle, rel_path::RelPath};
use zed_actions::OpenSettingsEditor;
@@ -377,31 +377,31 @@ fn init_renderers(cx: &mut App) {
render_dropdown(*settings_field, file, window, cx)
})
.add_renderer::<f32>(|settings_field, file, _, window, cx| {
render_numeric_stepper(*settings_field, file, window, cx)
render_number_field(*settings_field, file, window, cx)
})
.add_renderer::<u32>(|settings_field, file, _, window, cx| {
render_numeric_stepper(*settings_field, file, window, cx)
render_number_field(*settings_field, file, window, cx)
})
.add_renderer::<u64>(|settings_field, file, _, window, cx| {
render_numeric_stepper(*settings_field, file, window, cx)
render_number_field(*settings_field, file, window, cx)
})
.add_renderer::<usize>(|settings_field, file, _, window, cx| {
render_numeric_stepper(*settings_field, file, window, cx)
render_number_field(*settings_field, file, window, cx)
})
.add_renderer::<NonZero<usize>>(|settings_field, file, _, window, cx| {
render_numeric_stepper(*settings_field, file, window, cx)
render_number_field(*settings_field, file, window, cx)
})
.add_renderer::<NonZeroU32>(|settings_field, file, _, window, cx| {
render_numeric_stepper(*settings_field, file, window, cx)
render_number_field(*settings_field, file, window, cx)
})
.add_renderer::<CodeFade>(|settings_field, file, _, window, cx| {
render_numeric_stepper(*settings_field, file, window, cx)
render_number_field(*settings_field, file, window, cx)
})
.add_renderer::<FontWeight>(|settings_field, file, _, window, cx| {
render_numeric_stepper(*settings_field, file, window, cx)
render_number_field(*settings_field, file, window, cx)
})
.add_renderer::<settings::MinimumContrast>(|settings_field, file, _, window, cx| {
render_numeric_stepper(*settings_field, file, window, cx)
render_number_field(*settings_field, file, window, cx)
})
.add_renderer::<settings::ShowScrollbar>(|settings_field, file, _, window, cx| {
render_dropdown(*settings_field, file, window, cx)
@@ -1718,7 +1718,7 @@ fn render_font_picker(
.into_any_element()
}
fn render_numeric_stepper<T: NumericStepperType + Send + Sync>(
fn render_number_field<T: NumberFieldType + Send + Sync>(
field: SettingField<T>,
file: SettingsUiFile,
window: &mut Window,
@@ -1726,7 +1726,7 @@ fn render_numeric_stepper<T: NumericStepperType + Send + Sync>(
) -> AnyElement {
let (_, value) = SettingsStore::global(cx).get_value_from_file(file.to_settings(), field.pick);
let value = value.copied().unwrap_or_else(T::min_value);
NumericStepper::new("numeric_stepper", value, window, cx)
NumberField::new("numeric_stepper", value, window, cx)
.on_change({
move |value, _window, cx| {
let value = *value;
@@ -1737,7 +1737,6 @@ fn render_numeric_stepper<T: NumericStepperType + Send + Sync>(
}
})
.tab_index(0)
.style(NumericStepperStyle::Outlined)
.into_any_element()
}
@@ -9,25 +9,16 @@ use editor::{Editor, EditorStyle};
use gpui::{ClickEvent, Entity, FocusHandle, Focusable, FontWeight, Modifiers};
use settings::{CodeFade, MinimumContrast};
use ui::{IconButtonShape, prelude::*};
use ui::prelude::*;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub enum NumericStepperStyle {
Outlined,
#[default]
Ghost,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub enum NumericStepperMode {
pub enum NumberFieldMode {
#[default]
Read,
Edit,
}
pub trait NumericStepperType:
Display + Copy + Clone + Sized + PartialOrd + FromStr + 'static
{
pub trait NumberFieldType: Display + Copy + Clone + Sized + PartialOrd + FromStr + 'static {
fn default_format(value: &Self) -> String {
format!("{}", value)
}
@@ -40,7 +31,7 @@ pub trait NumericStepperType:
fn saturating_sub(self, rhs: Self) -> Self;
}
impl NumericStepperType for gpui::FontWeight {
impl NumberFieldType for gpui::FontWeight {
fn default_step() -> Self {
FontWeight(10.0)
}
@@ -64,7 +55,7 @@ impl NumericStepperType for gpui::FontWeight {
}
}
impl NumericStepperType for settings::CodeFade {
impl NumberFieldType for settings::CodeFade {
fn default_step() -> Self {
CodeFade(0.10)
}
@@ -88,7 +79,7 @@ impl NumericStepperType for settings::CodeFade {
}
}
impl NumericStepperType for settings::MinimumContrast {
impl NumberFieldType for settings::MinimumContrast {
fn default_step() -> Self {
MinimumContrast(1.0)
}
@@ -114,7 +105,7 @@ impl NumericStepperType for settings::MinimumContrast {
macro_rules! impl_numeric_stepper_int {
($type:ident) => {
impl NumericStepperType for $type {
impl NumberFieldType for $type {
fn default_step() -> Self {
1
}
@@ -148,7 +139,7 @@ macro_rules! impl_numeric_stepper_int {
macro_rules! impl_numeric_stepper_nonzero_int {
($nonzero:ty, $inner:ty) => {
impl NumericStepperType for $nonzero {
impl NumberFieldType for $nonzero {
fn default_step() -> Self {
<$nonzero>::new(1).unwrap()
}
@@ -184,7 +175,7 @@ macro_rules! impl_numeric_stepper_nonzero_int {
macro_rules! impl_numeric_stepper_float {
($type:ident) => {
impl NumericStepperType for $type {
impl NumberFieldType for $type {
fn default_format(value: &Self) -> String {
format!("{:.2}", value)
}
@@ -234,12 +225,11 @@ impl_numeric_stepper_nonzero_int!(NonZeroU64, u64);
impl_numeric_stepper_nonzero_int!(NonZero<usize>, usize);
#[derive(RegisterComponent)]
pub struct NumericStepper<T = usize> {
pub struct NumberField<T = usize> {
id: ElementId,
value: T,
style: NumericStepperStyle,
focus_handle: FocusHandle,
mode: Entity<NumericStepperMode>,
mode: Entity<NumberFieldMode>,
format: Box<dyn FnOnce(&T) -> String>,
large_step: T,
small_step: T,
@@ -251,12 +241,12 @@ pub struct NumericStepper<T = usize> {
tab_index: Option<isize>,
}
impl<T: NumericStepperType> NumericStepper<T> {
impl<T: NumberFieldType> NumberField<T> {
pub fn new(id: impl Into<ElementId>, value: T, window: &mut Window, cx: &mut App) -> Self {
let id = id.into();
let (mode, focus_handle) = window.with_id(id.clone(), |window| {
let mode = window.use_state(cx, |_, _| NumericStepperMode::default());
let mode = window.use_state(cx, |_, _| NumberFieldMode::default());
let focus_handle = window.use_state(cx, |_, cx| cx.focus_handle());
(mode, focus_handle)
});
@@ -266,7 +256,6 @@ impl<T: NumericStepperType> NumericStepper<T> {
mode,
value,
focus_handle: focus_handle.read(cx).clone(),
style: NumericStepperStyle::default(),
format: Box::new(T::default_format),
large_step: T::large_step(),
step: T::default_step(),
@@ -309,11 +298,6 @@ impl<T: NumericStepperType> NumericStepper<T> {
self
}
pub fn style(mut self, style: NumericStepperStyle) -> Self {
self.style = style;
self
}
pub fn on_reset(
mut self,
on_reset: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
@@ -333,7 +317,7 @@ impl<T: NumericStepperType> NumericStepper<T> {
}
}
impl<T: NumericStepperType> IntoElement for NumericStepper<T> {
impl<T: NumberFieldType> IntoElement for NumberField<T> {
type Element = gpui::Component<Self>;
fn into_element(self) -> Self::Element {
@@ -341,12 +325,8 @@ impl<T: NumericStepperType> IntoElement for NumericStepper<T> {
}
}
impl<T: NumericStepperType> RenderOnce for NumericStepper<T> {
impl<T: NumberFieldType> RenderOnce for NumberField<T> {
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
let shape = IconButtonShape::Square;
let icon_size = IconSize::Small;
let is_outlined = matches!(self.style, NumericStepperStyle::Outlined);
let mut tab_index = self.tab_index;
let get_step = {
@@ -371,8 +351,7 @@ impl<T: NumericStepperType> RenderOnce for NumericStepper<T> {
.when_some(self.on_reset, |this, on_reset| {
this.child(
IconButton::new("reset", IconName::RotateCcw)
.shape(shape)
.icon_size(icon_size)
.icon_size(IconSize::Small)
.when_some(tab_index.as_mut(), |this, tab_index| {
*tab_index += 1;
this.tab_index(*tab_index - 1)
@@ -382,7 +361,6 @@ impl<T: NumericStepperType> RenderOnce for NumericStepper<T> {
})
.child(
h_flex()
.when(!is_outlined, |this| this.gap_1())
.map(|decrement| {
let decrement_handler = {
let value = self.value;
@@ -397,57 +375,42 @@ impl<T: NumericStepperType> RenderOnce for NumericStepper<T> {
}
};
if is_outlined {
decrement.child(
h_flex()
.id("decrement_button")
.cursor(gpui::CursorStyle::PointingHand)
.p_1p5()
.size_full()
.justify_center()
.overflow_hidden()
.rounded_tl_sm()
.rounded_bl_sm()
.border_1()
.border_color(cx.theme().colors().border_variant)
.bg(cx.theme().colors().surface_background)
.hover(|s| s.bg(cx.theme().colors().element_hover))
.child(Icon::new(IconName::Dash).size(IconSize::Small))
.when_some(tab_index.as_mut(), |this, tab_index| {
*tab_index += 1;
this.tab_index(*tab_index - 1).focus(|style| {
style
.border_color(cx.theme().colors().border_focused)
.bg(cx.theme().colors().element_hover)
})
decrement.child(
h_flex()
.id("decrement_button")
.cursor(gpui::CursorStyle::PointingHand)
.p_1p5()
.size_full()
.justify_center()
.overflow_hidden()
.rounded_tl_sm()
.rounded_bl_sm()
.border_1()
.border_color(cx.theme().colors().border_variant)
.bg(cx.theme().colors().surface_background)
.hover(|s| s.bg(cx.theme().colors().element_hover))
.child(Icon::new(IconName::Dash).size(IconSize::Small))
.when_some(tab_index.as_mut(), |this, tab_index| {
*tab_index += 1;
this.tab_index(*tab_index - 1).focus(|style| {
style
.border_color(cx.theme().colors().border_focused)
.bg(cx.theme().colors().element_hover)
})
.on_click(decrement_handler),
)
} else {
decrement.child(
IconButton::new("decrement", IconName::Dash)
.shape(shape)
.icon_size(icon_size)
.when_some(tab_index.as_mut(), |this, tab_index| {
*tab_index += 1;
this.tab_index(*tab_index - 1)
})
.on_click(decrement_handler),
)
}
})
.on_click(decrement_handler),
)
})
.child(
h_flex()
.min_w_16()
.size_full()
.when(is_outlined, |this| {
this.border_y_1()
.border_color(cx.theme().colors().border_variant)
.bg(cx.theme().colors().surface_background)
})
.border_y_1()
.border_color(cx.theme().colors().border_variant)
.bg(cx.theme().colors().surface_background)
.in_focus(|this| this.border_color(cx.theme().colors().border_focused))
.child(match *self.mode.read(cx) {
NumericStepperMode::Read => h_flex()
NumberFieldMode::Read => h_flex()
.id("numeric_stepper_label")
.px_1()
.flex_1()
@@ -466,12 +429,12 @@ impl<T: NumericStepperType> RenderOnce for NumericStepper<T> {
move |click, _, _cx| {
if click.click_count() == 2 || click.is_keyboard() {
// Edit mode is disabled until we implement center text alignment for editor
// mode.write(cx, NumericStepperMode::Edit);
// mode.write(cx, NumberFieldMode::Edit);
}
}
})
.into_any_element(),
NumericStepperMode::Edit => h_flex()
NumberFieldMode::Edit => h_flex()
.flex_1()
.child(window.use_state(cx, {
|window, cx| {
@@ -506,7 +469,7 @@ impl<T: NumericStepperType> RenderOnce for NumericStepper<T> {
}
on_change(&new_value, window, cx);
};
mode.write(cx, NumericStepperMode::Read);
mode.write(cx, NumberFieldMode::Read);
}
})
.detach();
@@ -537,56 +500,43 @@ impl<T: NumericStepperType> RenderOnce for NumericStepper<T> {
}
};
if is_outlined {
increment.child(
h_flex()
.id("increment_button")
.cursor(gpui::CursorStyle::PointingHand)
.p_1p5()
.size_full()
.justify_center()
.overflow_hidden()
.rounded_tr_sm()
.rounded_br_sm()
.border_1()
.border_color(cx.theme().colors().border_variant)
.bg(cx.theme().colors().surface_background)
.hover(|s| s.bg(cx.theme().colors().element_hover))
.child(Icon::new(IconName::Plus).size(IconSize::Small))
.when_some(tab_index.as_mut(), |this, tab_index| {
*tab_index += 1;
this.tab_index(*tab_index - 1).focus(|style| {
style
.border_color(cx.theme().colors().border_focused)
.bg(cx.theme().colors().element_hover)
})
increment.child(
h_flex()
.id("increment_button")
.cursor(gpui::CursorStyle::PointingHand)
.p_1p5()
.size_full()
.justify_center()
.overflow_hidden()
.rounded_tr_sm()
.rounded_br_sm()
.border_1()
.border_color(cx.theme().colors().border_variant)
.bg(cx.theme().colors().surface_background)
.hover(|s| s.bg(cx.theme().colors().element_hover))
.child(Icon::new(IconName::Plus).size(IconSize::Small))
.when_some(tab_index.as_mut(), |this, tab_index| {
*tab_index += 1;
this.tab_index(*tab_index - 1).focus(|style| {
style
.border_color(cx.theme().colors().border_focused)
.bg(cx.theme().colors().element_hover)
})
.on_click(increment_handler),
)
} else {
increment.child(
IconButton::new("increment", IconName::Plus)
.shape(shape)
.icon_size(icon_size)
.when_some(tab_index.as_mut(), |this, tab_index| {
*tab_index += 1;
this.tab_index(*tab_index - 1)
})
.on_click(increment_handler),
)
}
})
.on_click(increment_handler),
)
}),
)
}
}
impl Component for NumericStepper<usize> {
impl Component for NumberField<usize> {
fn scope() -> ComponentScope {
ComponentScope::Input
}
fn name() -> &'static str {
"Numeric Stepper"
"Number Field"
}
fn sort_name() -> &'static str {
@@ -594,50 +544,30 @@ impl Component for NumericStepper<usize> {
}
fn description() -> Option<&'static str> {
Some("A button used to increment or decrement a numeric value.")
Some("A numeric input element with increment and decrement buttons.")
}
fn preview(window: &mut Window, cx: &mut App) -> Option<AnyElement> {
let first_stepper = window.use_state(cx, |_, _| 100usize);
let second_stepper = window.use_state(cx, |_, _| 100.0);
let stepper_example = window.use_state(cx, |_, _| 100.0);
Some(
v_flex()
.gap_6()
.children(vec![example_group_with_title(
"Styles",
vec![
single_example(
"Default",
NumericStepper::new(
"numeric-stepper-component-preview",
*first_stepper.read(cx),
window,
cx,
)
.on_change({
let first_stepper = first_stepper.clone();
move |value, _, cx| first_stepper.write(cx, *value)
})
.into_any_element(),
),
single_example(
"Outlined",
NumericStepper::new(
"numeric-stepper-with-border-component-preview",
*second_stepper.read(cx),
window,
cx,
)
.on_change({
let second_stepper = second_stepper.clone();
move |value, _, cx| second_stepper.write(cx, *value)
})
.min(1.0)
.max(100.0)
.style(NumericStepperStyle::Outlined)
.into_any_element(),
),
],
.children(vec![single_example(
"Default Numeric Stepper",
NumberField::new(
"numeric-stepper-component-preview",
*stepper_example.read(cx),
window,
cx,
)
.on_change({
let stepper_example = stepper_example.clone();
move |value, _, cx| stepper_example.write(cx, *value)
})
.min(1.0)
.max(100.0)
.into_any_element(),
)])
.into_any_element(),
)
+2 -2
View File
@@ -5,13 +5,13 @@
//! It can't be located in the `ui` crate because it depends on `editor`.
//!
mod font_picker;
mod numeric_stepper;
mod number_field;
use component::{example_group, single_example};
use editor::{Editor, EditorElement, EditorStyle};
pub use font_picker::*;
use gpui::{App, Entity, FocusHandle, Focusable, FontStyle, Hsla, Length, TextStyle};
pub use numeric_stepper::*;
pub use number_field::*;
use settings::Settings;
use std::sync::Arc;
use theme::ThemeSettings;