button_like.rs

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