Skip to main content

freya_material_design/
button.rs

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