diff --git a/crates/ui/src/components/toggle.rs b/crates/ui/src/components/toggle.rs index 4672a0cfc2..759b225434 100644 --- a/crates/ui/src/components/toggle.rs +++ b/crates/ui/src/components/toggle.rs @@ -543,28 +543,48 @@ impl RenderOnce for Switch { } } -/// A [`Switch`] that has a [`Label`]. -#[derive(IntoElement)] -pub struct SwitchWithLabel { +/// # SwitchField +/// +/// A field component that combines a label, description, and switch into one reusable component. +/// +/// # Examples +/// +/// ``` +/// use ui::prelude::*; +/// +/// SwitchField::new( +/// "feature-toggle", +/// "Enable feature", +/// "This feature adds new functionality to the app.", +/// ToggleState::Unselected, +/// |state, window, cx| { +/// // Logic here +/// } +/// ); +/// ``` +#[derive(IntoElement, RegisterComponent)] +pub struct SwitchField { id: ElementId, - label: Label, + label: SharedString, + description: SharedString, toggle_state: ToggleState, on_click: Arc, disabled: bool, color: SwitchColor, } -impl SwitchWithLabel { - /// Creates a switch with an attached label. +impl SwitchField { pub fn new( id: impl Into, - label: Label, + label: impl Into, + description: impl Into, toggle_state: impl Into, on_click: impl Fn(&ToggleState, &mut Window, &mut App) + 'static, ) -> Self { Self { id: id.into(), - label, + label: label.into(), + description: description.into(), toggle_state: toggle_state.into(), on_click: Arc::new(on_click), disabled: false, @@ -572,43 +592,141 @@ impl SwitchWithLabel { } } - /// Sets the disabled state of the [`SwitchWithLabel`]. pub fn disabled(mut self, disabled: bool) -> Self { self.disabled = disabled; self } /// Sets the color of the switch using the specified [`SwitchColor`]. + /// This changes the color scheme of the switch when it's in the "on" state. pub fn color(mut self, color: SwitchColor) -> Self { self.color = color; self } } -impl RenderOnce for SwitchWithLabel { - fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement { +impl RenderOnce for SwitchField { + fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement { h_flex() .id(SharedString::from(format!("{}-container", self.id))) - .gap(DynamicSpacing::Base08.rems(cx)) + .w_full() + .gap_4() + .justify_between() + .flex_wrap() .child( - Switch::new(self.id.clone(), self.toggle_state) - .disabled(self.disabled) - .color(self.color) - .on_click({ - let on_click = self.on_click.clone(); - move |checked, window, cx| { - (on_click)(checked, window, cx); - } - }), + v_flex() + .gap_0p5() + .max_w_5_6() + .child(Label::new(self.label)) + .child(Label::new(self.description).color(Color::Muted)), ) .child( - div() - .id(SharedString::from(format!("{}-label", self.id))) - .child(self.label), + 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); + } + }), ) } } +impl Component for SwitchField { + fn scope() -> ComponentScope { + ComponentScope::Input + } + + fn description() -> Option<&'static str> { + Some("A field component that combines a label, description, and switch") + } + + fn preview(_window: &mut Window, _cx: &mut App) -> Option { + Some( + v_flex() + .gap_6() + .children(vec![ + example_group_with_title( + "States", + vec![ + single_example( + "Unselected", + SwitchField::new( + "switch_field_unselected", + "Enable notifications", + "Receive notifications when new messages arrive.", + ToggleState::Unselected, + |_, _, _| {}, + ) + .into_any_element(), + ), + single_example( + "Selected", + SwitchField::new( + "switch_field_selected", + "Enable notifications", + "Receive notifications when new messages arrive.", + ToggleState::Selected, + |_, _, _| {}, + ) + .into_any_element(), + ), + ], + ), + example_group_with_title( + "Colors", + vec![ + single_example( + "Default", + SwitchField::new( + "switch_field_default", + "Default color", + "This uses the default switch color.", + ToggleState::Selected, + |_, _, _| {}, + ) + .into_any_element(), + ), + single_example( + "Accent", + SwitchField::new( + "switch_field_accent", + "Accent color", + "This uses the accent color scheme.", + ToggleState::Selected, + |_, _, _| {}, + ) + .color(SwitchColor::Accent) + .into_any_element(), + ), + ], + ), + example_group_with_title( + "Disabled", + vec![single_example( + "Disabled", + SwitchField::new( + "switch_field_disabled", + "Disabled field", + "This field is disabled and cannot be toggled.", + ToggleState::Selected, + |_, _, _| {}, + ) + .disabled(true) + .into_any_element(), + )], + ), + ]) + .into_any_element(), + ) + } +} + impl Component for Checkbox { fn scope() -> ComponentScope { ComponentScope::Input