tessera_ui_basic_components/icon_button.rs
1//! An interactive button that displays an icon.
2//!
3//! ## Usage
4//!
5//! Use for compact actions where an icon is sufficient to convey the meaning.
6use derive_builder::Builder;
7use tessera_ui::tessera;
8
9use crate::{
10 RippleState,
11 button::{ButtonArgs, button},
12 glass_button::{GlassButtonArgs, glass_button},
13 icon::{IconArgs, icon},
14};
15
16/// Arguments for [`icon_button`].
17#[derive(Clone, Builder)]
18#[builder(pattern = "owned")]
19pub struct IconButtonArgs {
20 /// Appearance/behavior settings for the underlying [`button`].
21 #[builder(default = "ButtonArgs::default()", setter(custom))]
22 pub button: ButtonArgs,
23 /// Icon that will be rendered at the center of the button.
24 #[builder(setter(into))]
25 pub icon: IconArgs,
26}
27
28impl IconButtonArgsBuilder {
29 /// Override the [`ButtonArgs`] using either a ready instance or a builder-produced value.
30 pub fn button(mut self, button: impl Into<ButtonArgs>) -> Self {
31 self.button = Some(button.into());
32 self
33 }
34}
35
36/// Lifted [`glass_button`] counterpart for icon buttons.
37#[derive(Clone, Builder)]
38#[builder(pattern = "owned")]
39pub struct GlassIconButtonArgs {
40 /// Appearance/behavior settings for the underlying [`glass_button`].
41 #[builder(default = "GlassButtonArgs::default()", setter(custom))]
42 pub button: GlassButtonArgs,
43 /// Icon rendered at the center of the glass button.
44 #[builder(setter(into))]
45 pub icon: IconArgs,
46}
47
48impl GlassIconButtonArgsBuilder {
49 /// Override the [`GlassButtonArgs`] using either a ready instance or a builder-produced value.
50 pub fn button(mut self, button: impl Into<GlassButtonArgs>) -> Self {
51 self.button = Some(button.into());
52 self
53 }
54}
55
56/// # icon_button
57///
58/// Renders a standard button with an icon as its content.
59///
60/// ## Usage
61///
62/// Use for common actions like "edit", "delete", or "settings" in a toolbar or list item.
63///
64/// ## Parameters
65///
66/// - `args` — configures the underlying button and the icon; see [`IconButtonArgs`].
67/// - `ripple_state` — a clonable [`RippleState`] to manage the ripple animation.
68///
69/// ## Examples
70///
71/// ```no_run
72/// use std::sync::Arc;
73/// use tessera_ui_basic_components::{
74/// icon_button::{icon_button, IconButtonArgsBuilder},
75/// button::ButtonArgsBuilder,
76/// icon::IconArgsBuilder,
77/// image_vector::{ImageVectorSource, load_image_vector_from_source},
78/// ripple_state::RippleState,
79/// };
80///
81/// let ripple_state = RippleState::new();
82/// let svg_path = "../assets/emoji_u1f416.svg";
83/// let vector_data = load_image_vector_from_source(
84/// &ImageVectorSource::Path(svg_path.to_string())
85/// ).unwrap();
86///
87/// icon_button(
88/// IconButtonArgsBuilder::default()
89/// .button(
90/// ButtonArgsBuilder::default()
91/// .on_click(Arc::new(|| {}))
92/// .build()
93/// .unwrap()
94/// )
95/// .icon(IconArgsBuilder::default().content(vector_data.clone()).build().expect("builder construction failed"))
96/// .build()
97/// .unwrap(),
98/// ripple_state,
99/// );
100/// ```
101#[tessera]
102pub fn icon_button(args: impl Into<IconButtonArgs>, ripple_state: RippleState) {
103 let args: IconButtonArgs = args.into();
104 let icon_args = args.icon.clone();
105
106 button(args.button, ripple_state, move || {
107 icon(icon_args.clone());
108 });
109}
110
111/// # glass_icon_button
112///
113/// Renders a button with a glass effect and an icon as its content.
114///
115/// ## Usage
116///
117/// Use for prominent icon-based actions in a modern, layered UI.
118///
119/// ## Parameters
120///
121/// - `args` — configures the underlying glass button and the icon; see [`GlassIconButtonArgs`].
122/// - `ripple_state` — a clonable [`RippleState`] to manage the ripple animation.
123///
124/// ## Examples
125///
126/// ```no_run
127/// use std::sync::Arc;
128/// use tessera_ui_basic_components::{
129/// icon_button::{glass_icon_button, GlassIconButtonArgsBuilder},
130/// glass_button::GlassButtonArgsBuilder,
131/// icon::IconArgsBuilder,
132/// image_vector::{ImageVectorSource, load_image_vector_from_source},
133/// ripple_state::RippleState,
134/// };
135///
136/// let ripple_state = RippleState::new();
137/// let svg_path = "../assets/emoji_u1f416.svg";
138/// let vector_data = load_image_vector_from_source(
139/// &ImageVectorSource::Path(svg_path.to_string())
140/// ).unwrap();
141///
142/// glass_icon_button(
143/// GlassIconButtonArgsBuilder::default()
144/// .button(
145/// GlassButtonArgsBuilder::default()
146/// .on_click(Arc::new(|| {}))
147/// .build()
148/// .unwrap()
149/// )
150/// .icon(IconArgsBuilder::default().content(vector_data).build().expect("builder construction failed"))
151/// .build()
152/// .unwrap(),
153/// ripple_state,
154/// );
155/// ```
156#[tessera]
157pub fn glass_icon_button(args: impl Into<GlassIconButtonArgs>, ripple_state: RippleState) {
158 let args: GlassIconButtonArgs = args.into();
159 let icon_args = args.icon.clone();
160
161 glass_button(args.button, ripple_state, move || {
162 icon(icon_args.clone());
163 });
164}