Skip to main content

dioxus_bulma/components/
button.rs

1use crate::theme::{BulmaColor, BulmaSize};
2use crate::utils::build_class;
3use dioxus::prelude::*;
4
5#[derive(Props, Clone, PartialEq)]
6pub struct ButtonProps {
7    #[props(default)]
8    pub color: Option<BulmaColor>,
9    #[props(default)]
10    pub size: Option<BulmaSize>,
11    #[props(default)]
12    pub outlined: Option<bool>,
13    #[props(default)]
14    pub inverted: Option<bool>,
15    #[props(default)]
16    pub rounded: Option<bool>,
17    #[props(default)]
18    pub loading: Option<bool>,
19    #[props(default)]
20    pub disabled: Option<bool>,
21    #[props(default)]
22    pub fullwidth: Option<bool>,
23    #[props(default)]
24    pub onclick: Option<EventHandler<MouseEvent>>,
25    #[props(default)]
26    pub id: Option<String>,
27    #[props(default)]
28    pub class: Option<String>,
29    #[props(default)]
30    pub style: Option<String>,
31    /// If present, generate the button as a Link component using the dioxus router
32    #[cfg(feature = "router")]
33    #[props(default, into)]
34    pub to: crate::router_helpers::MaybeNav,
35    pub children: Element,
36}
37
38#[component]
39pub fn Button(props: ButtonProps) -> Element {
40    let color = props.color.unwrap_or(BulmaColor::Primary);
41    let size = props.size.unwrap_or_default();
42    let outlined = props.outlined.unwrap_or(false);
43    let inverted = props.inverted.unwrap_or(false);
44    let rounded = props.rounded.unwrap_or(false);
45    let loading = props.loading.unwrap_or(false);
46    let disabled = props.disabled.unwrap_or(false);
47    let fullwidth = props.fullwidth.unwrap_or(false);
48    
49    let base_classes = vec!["button"];
50    
51    let optional_classes = vec![
52        Some(format!("is-{}", color.as_str())),
53        if size != BulmaSize::Normal { Some(size.as_class().to_string()) } else { None },
54        if outlined { Some("is-outlined".to_string()) } else { None },
55        if inverted { Some("is-inverted".to_string()) } else { None },
56        if rounded { Some("is-rounded".to_string()) } else { None },
57        if loading { Some("is-loading".to_string()) } else { None },
58        if fullwidth { Some("is-fullwidth".to_string()) } else { None },
59        props.class.clone(),
60    ];
61    
62    let final_class = build_class(&base_classes, &optional_classes);
63    let button_style = props.style.as_deref().unwrap_or("");
64
65    #[cfg(feature = "router")]
66    if let Some(nav_target) = props.to.0 {
67        return rsx! {
68            Link {
69                to: nav_target,
70                class: "{final_class}",
71                style: "{button_style}",
72                id: props.id.clone(),
73                onclick: move |evt| {
74                    if !disabled && !loading {
75                        if let Some(handler) = &props.onclick {
76                            handler.call(evt);
77                        }
78                    }
79                },
80                {props.children}
81            }
82        };
83    }
84
85    rsx! {
86        button {
87            class: "{final_class}",
88            style: "{button_style}",
89            id: props.id.clone(),
90            disabled: disabled,
91            onclick: move |evt| {
92                if !disabled && !loading {
93                    if let Some(handler) = &props.onclick {
94                        handler.call(evt);
95                    }
96                }
97            },
98            {props.children}
99        }
100    }
101}