button_like.rs

  1use documented::Documented;
  2use gpui::{
  3    AnyElement, AnyView, ClickEvent, CursorStyle, DefiniteLength, FocusHandle, Hsla, MouseButton,
  4    MouseClickEvent, MouseDownEvent, MouseUpEvent, Rems, StyleRefinement, relative,
  5    transparent_black,
  6};
  7use smallvec::SmallVec;
  8
  9use crate::{DynamicSpacing, ElevationIndex, prelude::*};
 10
 11/// A trait for buttons that can be Selected. Enables setting the [`ButtonStyle`] of a button when it is selected.
 12pub trait SelectableButton: Toggleable {
 13    fn selected_style(self, style: ButtonStyle) -> Self;
 14}
 15
 16/// A common set of traits all buttons must implement.
 17pub trait ButtonCommon: Clickable + Disableable {
 18    /// A unique element ID to identify the button.
 19    fn id(&self) -> &ElementId;
 20
 21    /// The visual style of the button.
 22    ///
 23    /// Most commonly will be [`ButtonStyle::Subtle`], or [`ButtonStyle::Filled`]
 24    /// for an emphasized button.
 25    fn style(self, style: ButtonStyle) -> Self;
 26
 27    /// The size of the button.
 28    ///
 29    /// Most buttons will use the default size.
 30    ///
 31    /// [`ButtonSize`] can also be used to help build non-button elements
 32    /// that are consistently sized with buttons.
 33    fn size(self, size: ButtonSize) -> Self;
 34
 35    /// The tooltip that shows when a user hovers over the button.
 36    ///
 37    /// Nearly all interactable elements should have a tooltip. Some example
 38    /// exceptions might a scroll bar, or a slider.
 39    fn tooltip(self, tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static) -> Self;
 40
 41    fn tab_index(self, tab_index: impl Into<isize>) -> Self;
 42
 43    fn layer(self, elevation: ElevationIndex) -> Self;
 44
 45    fn track_focus(self, focus_handle: &FocusHandle) -> Self;
 46}
 47
 48#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
 49pub enum IconPosition {
 50    #[default]
 51    Start,
 52    End,
 53}
 54
 55#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
 56pub enum KeybindingPosition {
 57    Start,
 58    #[default]
 59    End,
 60}
 61
 62#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
 63pub enum TintColor {
 64    #[default]
 65    Accent,
 66    Error,
 67    Warning,
 68    Success,
 69}
 70
 71impl TintColor {
 72    fn button_like_style(self, cx: &mut App) -> ButtonLikeStyles {
 73        match self {
 74            TintColor::Accent => ButtonLikeStyles {
 75                background: cx.theme().status().info_background,
 76                border_color: cx.theme().status().info_border,
 77                label_color: cx.theme().colors().text,
 78                icon_color: cx.theme().colors().text,
 79            },
 80            TintColor::Error => ButtonLikeStyles {
 81                background: cx.theme().status().error_background,
 82                border_color: cx.theme().status().error_border,
 83                label_color: cx.theme().colors().text,
 84                icon_color: cx.theme().colors().text,
 85            },
 86            TintColor::Warning => ButtonLikeStyles {
 87                background: cx.theme().status().warning_background,
 88                border_color: cx.theme().status().warning_border,
 89                label_color: cx.theme().colors().text,
 90                icon_color: cx.theme().colors().text,
 91            },
 92            TintColor::Success => ButtonLikeStyles {
 93                background: cx.theme().status().success_background,
 94                border_color: cx.theme().status().success_border,
 95                label_color: cx.theme().colors().text,
 96                icon_color: cx.theme().colors().text,
 97            },
 98        }
 99    }
100}
101
102impl From<TintColor> for Color {
103    fn from(tint: TintColor) -> Self {
104        match tint {
105            TintColor::Accent => Color::Accent,
106            TintColor::Error => Color::Error,
107            TintColor::Warning => Color::Warning,
108            TintColor::Success => Color::Success,
109        }
110    }
111}
112
113// Used to go from ButtonStyle -> Color through tint colors.
114impl From<ButtonStyle> for Color {
115    fn from(style: ButtonStyle) -> Self {
116        match style {
117            ButtonStyle::Tinted(tint) => tint.into(),
118            _ => Color::Default,
119        }
120    }
121}
122
123/// The visual appearance of a button.
124#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
125pub enum ButtonStyle {
126    /// A filled button with a solid background color. Provides emphasis versus
127    /// the more common subtle button.
128    Filled,
129
130    /// Used to emphasize a button in some way, like a selected state, or a semantic
131    /// coloring like an error or success button.
132    Tinted(TintColor),
133
134    /// Usually used as a secondary action that should have more emphasis than
135    /// a fully transparent button.
136    Outlined,
137
138    /// The default button style, used for most buttons. Has a transparent background,
139    /// but has a background color to indicate states like hover and active.
140    #[default]
141    Subtle,
142
143    /// Used for buttons that only change foreground color on hover and active states.
144    ///
145    /// TODO: Better docs for this.
146    Transparent,
147}
148
149#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
150pub(crate) enum ButtonLikeRounding {
151    All,
152    Left,
153    Right,
154}
155
156#[derive(Debug, Clone)]
157pub(crate) struct ButtonLikeStyles {
158    pub background: Hsla,
159    #[allow(unused)]
160    pub border_color: Hsla,
161    #[allow(unused)]
162    pub label_color: Hsla,
163    #[allow(unused)]
164    pub icon_color: Hsla,
165}
166
167fn element_bg_from_elevation(elevation: Option<ElevationIndex>, cx: &mut App) -> Hsla {
168    match elevation {
169        Some(ElevationIndex::Background) => cx.theme().colors().element_background,
170        Some(ElevationIndex::ElevatedSurface) => cx.theme().colors().elevated_surface_background,
171        Some(ElevationIndex::Surface) => cx.theme().colors().surface_background,
172        Some(ElevationIndex::ModalSurface) => cx.theme().colors().background,
173        _ => cx.theme().colors().element_background,
174    }
175}
176
177impl ButtonStyle {
178    pub(crate) fn enabled(
179        self,
180        elevation: Option<ElevationIndex>,
181
182        cx: &mut App,
183    ) -> ButtonLikeStyles {
184        match self {
185            ButtonStyle::Filled => ButtonLikeStyles {
186                background: element_bg_from_elevation(elevation, cx),
187                border_color: transparent_black(),
188                label_color: Color::Default.color(cx),
189                icon_color: Color::Default.color(cx),
190            },
191            ButtonStyle::Tinted(tint) => tint.button_like_style(cx),
192            ButtonStyle::Outlined => ButtonLikeStyles {
193                background: element_bg_from_elevation(elevation, cx),
194                border_color: cx.theme().colors().border_variant,
195                label_color: Color::Default.color(cx),
196                icon_color: Color::Default.color(cx),
197            },
198            ButtonStyle::Subtle => ButtonLikeStyles {
199                background: cx.theme().colors().ghost_element_background,
200                border_color: transparent_black(),
201                label_color: Color::Default.color(cx),
202                icon_color: Color::Default.color(cx),
203            },
204            ButtonStyle::Transparent => ButtonLikeStyles {
205                background: transparent_black(),
206                border_color: transparent_black(),
207                label_color: Color::Default.color(cx),
208                icon_color: Color::Default.color(cx),
209            },
210        }
211    }
212
213    pub(crate) fn hovered(
214        self,
215        elevation: Option<ElevationIndex>,
216
217        cx: &mut App,
218    ) -> ButtonLikeStyles {
219        match self {
220            ButtonStyle::Filled => {
221                let mut filled_background = element_bg_from_elevation(elevation, cx);
222                filled_background.fade_out(0.5);
223
224                ButtonLikeStyles {
225                    background: filled_background,
226                    border_color: transparent_black(),
227                    label_color: Color::Default.color(cx),
228                    icon_color: Color::Default.color(cx),
229                }
230            }
231            ButtonStyle::Tinted(tint) => {
232                let mut styles = tint.button_like_style(cx);
233                let theme = cx.theme();
234                styles.background = theme.darken(styles.background, 0.05, 0.2);
235                styles
236            }
237            ButtonStyle::Outlined => ButtonLikeStyles {
238                background: cx.theme().colors().ghost_element_hover,
239                border_color: cx.theme().colors().border,
240                label_color: Color::Default.color(cx),
241                icon_color: Color::Default.color(cx),
242            },
243            ButtonStyle::Subtle => ButtonLikeStyles {
244                background: cx.theme().colors().ghost_element_hover,
245                border_color: transparent_black(),
246                label_color: Color::Default.color(cx),
247                icon_color: Color::Default.color(cx),
248            },
249            ButtonStyle::Transparent => ButtonLikeStyles {
250                background: transparent_black(),
251                border_color: transparent_black(),
252                // TODO: These are not great
253                label_color: Color::Muted.color(cx),
254                // TODO: These are not great
255                icon_color: Color::Muted.color(cx),
256            },
257        }
258    }
259
260    pub(crate) fn active(self, cx: &mut App) -> ButtonLikeStyles {
261        match self {
262            ButtonStyle::Filled => ButtonLikeStyles {
263                background: cx.theme().colors().element_active,
264                border_color: transparent_black(),
265                label_color: Color::Default.color(cx),
266                icon_color: Color::Default.color(cx),
267            },
268            ButtonStyle::Tinted(tint) => tint.button_like_style(cx),
269            ButtonStyle::Subtle => ButtonLikeStyles {
270                background: cx.theme().colors().ghost_element_active,
271                border_color: transparent_black(),
272                label_color: Color::Default.color(cx),
273                icon_color: Color::Default.color(cx),
274            },
275            ButtonStyle::Outlined => ButtonLikeStyles {
276                background: cx.theme().colors().element_active,
277                border_color: cx.theme().colors().border_variant,
278                label_color: Color::Default.color(cx),
279                icon_color: Color::Default.color(cx),
280            },
281            ButtonStyle::Transparent => ButtonLikeStyles {
282                background: transparent_black(),
283                border_color: transparent_black(),
284                // TODO: These are not great
285                label_color: Color::Muted.color(cx),
286                // TODO: These are not great
287                icon_color: Color::Muted.color(cx),
288            },
289        }
290    }
291
292    #[allow(unused)]
293    pub(crate) fn focused(self, window: &mut Window, cx: &mut App) -> ButtonLikeStyles {
294        match self {
295            ButtonStyle::Filled => ButtonLikeStyles {
296                background: cx.theme().colors().element_background,
297                border_color: cx.theme().colors().border_focused,
298                label_color: Color::Default.color(cx),
299                icon_color: Color::Default.color(cx),
300            },
301            ButtonStyle::Tinted(tint) => tint.button_like_style(cx),
302            ButtonStyle::Subtle => ButtonLikeStyles {
303                background: cx.theme().colors().ghost_element_background,
304                border_color: cx.theme().colors().border_focused,
305                label_color: Color::Default.color(cx),
306                icon_color: Color::Default.color(cx),
307            },
308            ButtonStyle::Outlined => ButtonLikeStyles {
309                background: cx.theme().colors().ghost_element_background,
310                border_color: cx.theme().colors().border,
311                label_color: Color::Default.color(cx),
312                icon_color: Color::Default.color(cx),
313            },
314            ButtonStyle::Transparent => ButtonLikeStyles {
315                background: transparent_black(),
316                border_color: cx.theme().colors().border_focused,
317                label_color: Color::Accent.color(cx),
318                icon_color: Color::Accent.color(cx),
319            },
320        }
321    }
322
323    #[allow(unused)]
324    pub(crate) fn disabled(
325        self,
326        elevation: Option<ElevationIndex>,
327        window: &mut Window,
328        cx: &mut App,
329    ) -> ButtonLikeStyles {
330        match self {
331            ButtonStyle::Filled => ButtonLikeStyles {
332                background: cx.theme().colors().element_disabled,
333                border_color: cx.theme().colors().border_disabled,
334                label_color: Color::Disabled.color(cx),
335                icon_color: Color::Disabled.color(cx),
336            },
337            ButtonStyle::Tinted(tint) => tint.button_like_style(cx),
338            ButtonStyle::Subtle => ButtonLikeStyles {
339                background: cx.theme().colors().ghost_element_disabled,
340                border_color: cx.theme().colors().border_disabled,
341                label_color: Color::Disabled.color(cx),
342                icon_color: Color::Disabled.color(cx),
343            },
344            ButtonStyle::Outlined => ButtonLikeStyles {
345                background: cx.theme().colors().element_disabled,
346                border_color: cx.theme().colors().border_disabled,
347                label_color: Color::Default.color(cx),
348                icon_color: Color::Default.color(cx),
349            },
350            ButtonStyle::Transparent => ButtonLikeStyles {
351                background: transparent_black(),
352                border_color: transparent_black(),
353                label_color: Color::Disabled.color(cx),
354                icon_color: Color::Disabled.color(cx),
355            },
356        }
357    }
358}
359
360/// The height of a button.
361///
362/// Can also be used to size non-button elements to align with [`Button`]s.
363#[derive(Default, PartialEq, Clone, Copy)]
364pub enum ButtonSize {
365    Large,
366    Medium,
367    #[default]
368    Default,
369    Compact,
370    None,
371}
372
373impl ButtonSize {
374    pub fn rems(self) -> Rems {
375        match self {
376            ButtonSize::Large => rems_from_px(32.),
377            ButtonSize::Medium => rems_from_px(28.),
378            ButtonSize::Default => rems_from_px(22.),
379            ButtonSize::Compact => rems_from_px(18.),
380            ButtonSize::None => rems_from_px(16.),
381        }
382    }
383}
384
385/// A button-like element that can be used to create a custom button when
386/// prebuilt buttons are not sufficient. Use this sparingly, as it is
387/// unconstrained and may make the UI feel less consistent.
388///
389/// This is also used to build the prebuilt buttons.
390#[derive(IntoElement, Documented, RegisterComponent)]
391pub struct ButtonLike {
392    pub(super) base: Div,
393    id: ElementId,
394    pub(super) style: ButtonStyle,
395    pub(super) disabled: bool,
396    pub(super) selected: bool,
397    pub(super) selected_style: Option<ButtonStyle>,
398    pub(super) width: Option<DefiniteLength>,
399    pub(super) height: Option<DefiniteLength>,
400    pub(super) layer: Option<ElevationIndex>,
401    tab_index: Option<isize>,
402    size: ButtonSize,
403    rounding: Option<ButtonLikeRounding>,
404    tooltip: Option<Box<dyn Fn(&mut Window, &mut App) -> AnyView>>,
405    hoverable_tooltip: Option<Box<dyn Fn(&mut Window, &mut App) -> AnyView>>,
406    cursor_style: CursorStyle,
407    on_click: Option<Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
408    on_right_click: Option<Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
409    children: SmallVec<[AnyElement; 2]>,
410    focus_handle: Option<FocusHandle>,
411}
412
413impl ButtonLike {
414    pub fn new(id: impl Into<ElementId>) -> Self {
415        Self {
416            base: div(),
417            id: id.into(),
418            style: ButtonStyle::default(),
419            disabled: false,
420            selected: false,
421            selected_style: None,
422            width: None,
423            height: None,
424            size: ButtonSize::Default,
425            rounding: Some(ButtonLikeRounding::All),
426            tooltip: None,
427            hoverable_tooltip: None,
428            children: SmallVec::new(),
429            cursor_style: CursorStyle::PointingHand,
430            on_click: None,
431            on_right_click: None,
432            layer: None,
433            tab_index: None,
434            focus_handle: None,
435        }
436    }
437
438    pub fn new_rounded_left(id: impl Into<ElementId>) -> Self {
439        Self::new(id).rounding(ButtonLikeRounding::Left)
440    }
441
442    pub fn new_rounded_right(id: impl Into<ElementId>) -> Self {
443        Self::new(id).rounding(ButtonLikeRounding::Right)
444    }
445
446    pub fn new_rounded_all(id: impl Into<ElementId>) -> Self {
447        Self::new(id).rounding(ButtonLikeRounding::All)
448    }
449
450    pub fn opacity(mut self, opacity: f32) -> Self {
451        self.base = self.base.opacity(opacity);
452        self
453    }
454
455    pub fn height(mut self, height: DefiniteLength) -> Self {
456        self.height = Some(height);
457        self
458    }
459
460    pub(crate) fn rounding(mut self, rounding: impl Into<Option<ButtonLikeRounding>>) -> Self {
461        self.rounding = rounding.into();
462        self
463    }
464
465    pub fn on_right_click(
466        mut self,
467        handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
468    ) -> Self {
469        self.on_right_click = Some(Box::new(handler));
470        self
471    }
472
473    pub fn hoverable_tooltip(
474        mut self,
475        tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static,
476    ) -> Self {
477        self.hoverable_tooltip = Some(Box::new(tooltip));
478        self
479    }
480}
481
482impl Disableable for ButtonLike {
483    fn disabled(mut self, disabled: bool) -> Self {
484        self.disabled = disabled;
485        self
486    }
487}
488
489impl Toggleable for ButtonLike {
490    fn toggle_state(mut self, selected: bool) -> Self {
491        self.selected = selected;
492        self
493    }
494}
495
496impl SelectableButton for ButtonLike {
497    fn selected_style(mut self, style: ButtonStyle) -> Self {
498        self.selected_style = Some(style);
499        self
500    }
501}
502
503impl Clickable for ButtonLike {
504    fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static) -> Self {
505        self.on_click = Some(Box::new(handler));
506        self
507    }
508
509    fn cursor_style(mut self, cursor_style: CursorStyle) -> Self {
510        self.cursor_style = cursor_style;
511        self
512    }
513}
514
515impl FixedWidth for ButtonLike {
516    fn width(mut self, width: impl Into<DefiniteLength>) -> Self {
517        self.width = Some(width.into());
518        self
519    }
520
521    fn full_width(mut self) -> Self {
522        self.width = Some(relative(1.));
523        self
524    }
525}
526
527impl ButtonCommon for ButtonLike {
528    fn id(&self) -> &ElementId {
529        &self.id
530    }
531
532    fn style(mut self, style: ButtonStyle) -> Self {
533        self.style = style;
534        self
535    }
536
537    fn size(mut self, size: ButtonSize) -> Self {
538        self.size = size;
539        self
540    }
541
542    fn tooltip(mut self, tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static) -> Self {
543        self.tooltip = Some(Box::new(tooltip));
544        self
545    }
546
547    fn tab_index(mut self, tab_index: impl Into<isize>) -> Self {
548        self.tab_index = Some(tab_index.into());
549        self
550    }
551
552    fn layer(mut self, elevation: ElevationIndex) -> Self {
553        self.layer = Some(elevation);
554        self
555    }
556
557    fn track_focus(mut self, focus_handle: &gpui::FocusHandle) -> Self {
558        self.focus_handle = Some(focus_handle.clone());
559        self
560    }
561}
562
563impl VisibleOnHover for ButtonLike {
564    fn visible_on_hover(mut self, group_name: impl Into<SharedString>) -> Self {
565        self.base = self.base.visible_on_hover(group_name);
566        self
567    }
568}
569
570impl ParentElement for ButtonLike {
571    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
572        self.children.extend(elements)
573    }
574}
575
576impl RenderOnce for ButtonLike {
577    fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
578        let style = self
579            .selected_style
580            .filter(|_| self.selected)
581            .unwrap_or(self.style);
582
583        self.base
584            .h_flex()
585            .id(self.id.clone())
586            .when_some(self.tab_index, |this, tab_index| this.tab_index(tab_index))
587            .when_some(self.focus_handle, |this, focus_handle| {
588                this.track_focus(&focus_handle)
589            })
590            .font_ui(cx)
591            .group("")
592            .flex_none()
593            .h(self.height.unwrap_or(self.size.rems().into()))
594            .when_some(self.width, |this, width| {
595                this.w(width).justify_center().text_center()
596            })
597            .when(matches!(self.style, ButtonStyle::Outlined), |this| {
598                this.border_1()
599            })
600            .when_some(self.rounding, |this, rounding| match rounding {
601                ButtonLikeRounding::All => this.rounded_sm(),
602                ButtonLikeRounding::Left => this.rounded_l_sm(),
603                ButtonLikeRounding::Right => this.rounded_r_sm(),
604            })
605            .gap(DynamicSpacing::Base04.rems(cx))
606            .map(|this| match self.size {
607                ButtonSize::Large | ButtonSize::Medium => this.px(DynamicSpacing::Base06.rems(cx)),
608                ButtonSize::Default | ButtonSize::Compact => {
609                    this.px(DynamicSpacing::Base04.rems(cx))
610                }
611                ButtonSize::None => this.px_px(),
612            })
613            .border_color(style.enabled(self.layer, cx).border_color)
614            .bg(style.enabled(self.layer, cx).background)
615            .when(self.disabled, |this| {
616                if self.cursor_style == CursorStyle::PointingHand {
617                    this.cursor_not_allowed()
618                } else {
619                    this.cursor(self.cursor_style)
620                }
621            })
622            .when(!self.disabled, |this| {
623                let hovered_style = style.hovered(self.layer, cx);
624                let focus_color =
625                    |refinement: StyleRefinement| refinement.bg(hovered_style.background);
626                this.cursor(self.cursor_style)
627                    .hover(focus_color)
628                    .map(|this| {
629                        if matches!(self.style, ButtonStyle::Outlined) {
630                            this.focus(|s| s.border_color(cx.theme().colors().border_focused))
631                        } else {
632                            this.focus(focus_color)
633                        }
634                    })
635                    .active(|active| active.bg(style.active(cx).background))
636            })
637            .when_some(
638                self.on_right_click.filter(|_| !self.disabled),
639                |this, on_right_click| {
640                    this.on_mouse_down(MouseButton::Right, |_event, window, cx| {
641                        window.prevent_default();
642                        cx.stop_propagation();
643                    })
644                    .on_mouse_up(
645                        MouseButton::Right,
646                        move |event, window, cx| {
647                            cx.stop_propagation();
648                            let click_event = ClickEvent::Mouse(MouseClickEvent {
649                                down: MouseDownEvent {
650                                    button: MouseButton::Right,
651                                    position: event.position,
652                                    modifiers: event.modifiers,
653                                    click_count: 1,
654                                    first_mouse: false,
655                                },
656                                up: MouseUpEvent {
657                                    button: MouseButton::Right,
658                                    position: event.position,
659                                    modifiers: event.modifiers,
660                                    click_count: 1,
661                                },
662                            });
663                            (on_right_click)(&click_event, window, cx)
664                        },
665                    )
666                },
667            )
668            .when_some(
669                self.on_click.filter(|_| !self.disabled),
670                |this, on_click| {
671                    this.on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
672                        .on_click(move |event, window, cx| {
673                            cx.stop_propagation();
674                            (on_click)(event, window, cx)
675                        })
676                },
677            )
678            .when_some(self.tooltip, |this, tooltip| {
679                this.tooltip(move |window, cx| tooltip(window, cx))
680            })
681            .when_some(self.hoverable_tooltip, |this, tooltip| {
682                this.hoverable_tooltip(move |window, cx| tooltip(window, cx))
683            })
684            .children(self.children)
685    }
686}
687
688impl Component for ButtonLike {
689    fn scope() -> ComponentScope {
690        ComponentScope::Input
691    }
692
693    fn sort_name() -> &'static str {
694        // ButtonLike should be at the bottom of the button list
695        "ButtonZ"
696    }
697
698    fn description() -> Option<&'static str> {
699        Some(ButtonLike::DOCS)
700    }
701
702    fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
703        Some(
704            v_flex()
705                .gap_6()
706                .children(vec![
707                    example_group(vec![
708                        single_example(
709                            "Default",
710                            ButtonLike::new("default")
711                                .child(Label::new("Default"))
712                                .into_any_element(),
713                        ),
714                        single_example(
715                            "Filled",
716                            ButtonLike::new("filled")
717                                .style(ButtonStyle::Filled)
718                                .child(Label::new("Filled"))
719                                .into_any_element(),
720                        ),
721                        single_example(
722                            "Subtle",
723                            ButtonLike::new("outline")
724                                .style(ButtonStyle::Subtle)
725                                .child(Label::new("Subtle"))
726                                .into_any_element(),
727                        ),
728                        single_example(
729                            "Tinted",
730                            ButtonLike::new("tinted_accent_style")
731                                .style(ButtonStyle::Tinted(TintColor::Accent))
732                                .child(Label::new("Accent"))
733                                .into_any_element(),
734                        ),
735                        single_example(
736                            "Transparent",
737                            ButtonLike::new("transparent")
738                                .style(ButtonStyle::Transparent)
739                                .child(Label::new("Transparent"))
740                                .into_any_element(),
741                        ),
742                    ]),
743                    example_group_with_title(
744                        "Button Group Constructors",
745                        vec![
746                            single_example(
747                                "Left Rounded",
748                                ButtonLike::new_rounded_left("left_rounded")
749                                    .child(Label::new("Left Rounded"))
750                                    .style(ButtonStyle::Filled)
751                                    .into_any_element(),
752                            ),
753                            single_example(
754                                "Right Rounded",
755                                ButtonLike::new_rounded_right("right_rounded")
756                                    .child(Label::new("Right Rounded"))
757                                    .style(ButtonStyle::Filled)
758                                    .into_any_element(),
759                            ),
760                            single_example(
761                                "Button Group",
762                                h_flex()
763                                    .gap_px()
764                                    .child(
765                                        ButtonLike::new_rounded_left("bg_left")
766                                            .child(Label::new("Left"))
767                                            .style(ButtonStyle::Filled),
768                                    )
769                                    .child(
770                                        ButtonLike::new_rounded_right("bg_right")
771                                            .child(Label::new("Right"))
772                                            .style(ButtonStyle::Filled),
773                                    )
774                                    .into_any_element(),
775                            ),
776                        ],
777                    ),
778                ])
779                .into_any_element(),
780        )
781    }
782}