button_like.rs

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