ironhtml_bootstrap/
buttons.rs1use crate::{Color, Size};
25use ironhtml::typed::Element;
26use ironhtml_elements::Button;
27
28extern crate alloc;
29use alloc::format;
30
31#[must_use]
50pub fn btn(color: Color, text: &str) -> Element<Button> {
51 let class = format!("btn btn-{}", color.as_str());
52 Element::<Button>::new()
53 .attr("type", "button")
54 .class(&class)
55 .text(text)
56}
57
58#[must_use]
65pub fn btn_outline(color: Color, text: &str) -> Element<Button> {
66 let class = format!("btn btn-outline-{}", color.as_str());
67 Element::<Button>::new()
68 .attr("type", "button")
69 .class(&class)
70 .text(text)
71}
72
73#[must_use]
80pub fn btn_sized(color: Color, size: Size, text: &str) -> Element<Button> {
81 let size_class = size.as_btn_class();
82 let class = if size_class.is_empty() {
83 format!("btn btn-{}", color.as_str())
84 } else {
85 format!("btn btn-{} {size_class}", color.as_str())
86 };
87 Element::<Button>::new()
88 .attr("type", "button")
89 .class(&class)
90 .text(text)
91}
92
93#[must_use]
95pub fn btn_outline_sized(color: Color, size: Size, text: &str) -> Element<Button> {
96 let size_class = size.as_btn_class();
97 let class = if size_class.is_empty() {
98 format!("btn btn-outline-{}", color.as_str())
99 } else {
100 format!("btn btn-outline-{} {size_class}", color.as_str())
101 };
102 Element::<Button>::new()
103 .attr("type", "button")
104 .class(&class)
105 .text(text)
106}
107
108#[must_use]
110pub fn btn_disabled(color: Color, text: &str) -> Element<Button> {
111 let class = format!("btn btn-{}", color.as_str());
112 Element::<Button>::new()
113 .attr("type", "button")
114 .class(&class)
115 .bool_attr("disabled")
116 .text(text)
117}
118
119#[must_use]
123pub fn btn_link(text: &str) -> Element<Button> {
124 Element::<Button>::new()
125 .attr("type", "button")
126 .class("btn btn-link")
127 .text(text)
128}
129
130#[must_use]
141pub fn btn_loading(color: Color, text: &str) -> Element<Button> {
142 use ironhtml_elements::Span;
143
144 let class = format!("btn btn-{}", color.as_str());
145 Element::<Button>::new()
146 .attr("type", "button")
147 .class(&class)
148 .bool_attr("disabled")
149 .child::<Span, _>(|s| {
150 s.class("spinner-border spinner-border-sm")
151 .attr("role", "status")
152 .attr("aria-hidden", "true")
153 })
154 .text(format!(" {text}"))
155}
156
157#[must_use]
168pub fn btn_loading_grow(color: Color, text: &str) -> Element<Button> {
169 use ironhtml_elements::Span;
170
171 let class = format!("btn btn-{}", color.as_str());
172 Element::<Button>::new()
173 .attr("type", "button")
174 .class(&class)
175 .bool_attr("disabled")
176 .child::<Span, _>(|s| {
177 s.class("spinner-grow spinner-grow-sm")
178 .attr("role", "status")
179 .attr("aria-hidden", "true")
180 })
181 .text(format!(" {text}"))
182}
183
184#[must_use]
195pub fn btn_block(color: Color, text: &str) -> Element<Button> {
196 let class = format!("btn btn-{} w-100", color.as_str());
197 Element::<Button>::new()
198 .attr("type", "button")
199 .class(&class)
200 .text(text)
201}
202
203#[must_use]
205pub fn btn_icon(color: Color, icon_class: &str, text: &str) -> Element<Button> {
206 use ironhtml_elements::I;
207
208 let class = format!("btn btn-{}", color.as_str());
209 Element::<Button>::new()
210 .attr("type", "button")
211 .class(&class)
212 .child::<I, _>(|i| i.class(icon_class))
213 .text(format!(" {text}"))
214}
215
216#[cfg(test)]
217mod tests {
218 use super::*;
219
220 #[test]
221 fn test_btn_primary() {
222 let b = btn(Color::Primary, "Click");
223 assert_eq!(
224 b.render(),
225 r#"<button type="button" class="btn btn-primary">Click</button>"#
226 );
227 }
228
229 #[test]
230 fn test_btn_outline() {
231 let b = btn_outline(Color::Danger, "Delete");
232 assert!(b.render().contains("btn-outline-danger"));
233 }
234
235 #[test]
236 fn test_btn_sized() {
237 let b = btn_sized(Color::Success, Size::Large, "Submit");
238 let html = b.render();
239 assert!(html.contains("btn-success"));
240 assert!(html.contains("btn-lg"));
241 }
242
243 #[test]
244 fn test_all_colors() {
245 for color in [
246 Color::Primary,
247 Color::Secondary,
248 Color::Success,
249 Color::Danger,
250 Color::Warning,
251 Color::Info,
252 Color::Light,
253 Color::Dark,
254 ] {
255 let b = btn(color, "Test");
256 assert!(b.render().contains(&format!("btn-{}", color.as_str())));
257 }
258 }
259}