freya_material_design/
button.rs

1use std::time::Duration;
2
3use freya_components::{
4    button::{
5        Button,
6        ButtonLayoutVariant,
7    },
8    get_theme,
9    theming::component_themes::ButtonLayoutThemePartialExt,
10};
11use freya_core::prelude::*;
12
13use crate::ripple::Ripple;
14
15/// Extension trait that adds ripple effect support to [Button].
16///
17/// This trait provides the [ButtonRippleExt::ripple] method that wraps the button's children
18/// in a [Ripple] component, creating a Material Design-style ripple effect on click.
19///
20/// # Example
21///
22/// ```rust
23/// # use freya::{material_design::*, prelude::*};
24/// fn app() -> impl IntoElement {
25///     Button::new()
26///         .on_press(|_| println!("Pressed!"))
27///         .ripple()
28///         .color((200, 200, 255))
29///         .child("Click me!")
30///         .child("More text")
31/// }
32/// ```
33pub trait ButtonRippleExt {
34    /// Enable ripple effect on this button.
35    /// Returns a [RippleButton] that allows adding children and configuring the ripple.
36    fn ripple(self) -> RippleButton;
37}
38
39impl ButtonRippleExt for Button {
40    fn ripple(self) -> RippleButton {
41        RippleButton {
42            button: self,
43            ripple: Ripple::new(),
44        }
45    }
46}
47
48/// A Button with a Ripple effect wrapper.
49///
50/// Created by calling [ButtonRippleExt::ripple] on a Button.
51/// Allows adding children to the ripple and configuring its color/duration.
52#[derive(Clone, PartialEq)]
53pub struct RippleButton {
54    button: Button,
55    ripple: Ripple,
56}
57
58impl ChildrenExt for RippleButton {
59    fn get_children(&mut self) -> &mut Vec<Element> {
60        self.ripple.get_children()
61    }
62}
63
64impl RippleButton {
65    /// Set the color of the ripple effect.
66    pub fn color(mut self, color: impl Into<Color>) -> Self {
67        self.ripple = self.ripple.color(color);
68        self
69    }
70
71    /// Set the duration of the ripple animation.
72    pub fn duration(mut self, duration: Duration) -> Self {
73        self.ripple = self.ripple.duration(duration);
74        self
75    }
76}
77
78impl Render for RippleButton {
79    fn render(&self) -> impl IntoElement {
80        let mut button = self.button.clone();
81
82        let theme_layout = match button.get_layout_variant() {
83            ButtonLayoutVariant::Normal => get_theme!(&button.get_theme_layout(), button_layout),
84            ButtonLayoutVariant::Compact => {
85                get_theme!(&button.get_theme_layout(), compact_button_layout)
86            }
87            ButtonLayoutVariant::Expanded => {
88                get_theme!(&button.get_theme_layout(), expanded_button_layout)
89            }
90        };
91
92        let ripple = self.ripple.clone().padding(theme_layout.padding);
93
94        button.get_children().clear();
95        button.get_children().push(ripple.into());
96        button.padding(0.)
97    }
98
99    fn render_key(&self) -> DiffKey {
100        self.button.render_key()
101    }
102}