yew_bs/components/
button.rs

1use yew::prelude::*;
2use crate::components::common::{Size, Variant};
3#[derive(Clone, Copy, PartialEq, Debug)]
4pub enum ButtonGroupSize {
5    Small,
6    Large,
7}
8impl ButtonGroupSize {
9    pub fn as_str(&self) -> &'static str {
10        match self {
11            ButtonGroupSize::Small => "btn-group-sm",
12            ButtonGroupSize::Large => "btn-group-lg",
13        }
14    }
15}
16/// Props for the Button component
17#[derive(Properties, PartialEq)]
18pub struct ButtonProps {
19    /// Button children (label)
20    #[prop_or_default]
21    pub children: Children,
22    /// Button variant (color)
23    #[prop_or(Variant::Primary)]
24    pub variant: Variant,
25    /// Button size
26    #[prop_or_default]
27    pub size: Option<Size>,
28    /// Whether to use outline style
29    #[prop_or_default]
30    pub outline: bool,
31    /// Button type attribute
32    #[prop_or_default]
33    pub button_type: Option<String>,
34    /// Whether the button is disabled
35    #[prop_or_default]
36    pub disabled: bool,
37    /// Whether the button is active
38    #[prop_or_default]
39    pub active: bool,
40    /// Click event handler
41    #[prop_or_default]
42    pub onclick: Option<Callback<MouseEvent>>,
43    /// Additional CSS classes
44    #[prop_or_default]
45    pub class: Option<AttrValue>,
46    /// Additional HTML attributes
47    #[prop_or_default]
48    pub node_ref: NodeRef,
49}
50/// Bootstrap Button component
51#[function_component(Button)]
52pub fn button(props: &ButtonProps) -> Html {
53    let mut classes = Classes::new();
54    classes.push("btn");
55    if props.outline {
56        classes.push(format!("btn-outline-{}", props.variant.as_str()));
57    } else {
58        classes.push(format!("btn-{}", props.variant.as_str()));
59    }
60    if let Some(size) = &props.size {
61        let size_str = size.as_str();
62        if !size_str.is_empty() {
63            classes.push(format!("btn-{}", size_str));
64        }
65    }
66    if props.active {
67        classes.push("active");
68    }
69    if let Some(class) = &props.class {
70        classes.push(class.to_string());
71    }
72    let button_type = props.button_type.clone().unwrap_or_else(|| "button".to_string());
73    html! {
74        < button type = { button_type } class = { classes } disabled = { props.disabled }
75        onclick = { props.onclick.clone() } ref = { props.node_ref.clone() } > { for
76        props.children.iter() } </ button >
77    }
78}
79/// Props for the ButtonGroup component
80#[derive(Properties, PartialEq)]
81pub struct ButtonGroupProps {
82    /// Button group children (buttons)
83    #[prop_or_default]
84    pub children: Children,
85    /// Whether the button group should be vertical
86    #[prop_or_default]
87    pub vertical: bool,
88    /// Button group size
89    #[prop_or_default]
90    pub size: Option<ButtonGroupSize>,
91    /// Additional CSS classes
92    #[prop_or_default]
93    pub class: Option<AttrValue>,
94    /// ARIA label for accessibility
95    #[prop_or_default]
96    pub aria_label: Option<AttrValue>,
97    /// Role attribute (defaults to "group")
98    #[prop_or_default]
99    pub role: Option<String>,
100}
101/// Bootstrap ButtonGroup component
102#[function_component(ButtonGroup)]
103pub fn button_group(props: &ButtonGroupProps) -> Html {
104    let mut classes = Classes::new();
105    if props.vertical {
106        classes.push("btn-group-vertical");
107    } else {
108        classes.push("btn-group");
109    }
110    if let Some(size) = &props.size {
111        classes.push(size.as_str());
112    }
113    if let Some(class) = &props.class {
114        classes.push(class.to_string());
115    }
116    let role = props.role.clone().unwrap_or_else(|| "group".to_string());
117    html! {
118        < div class = { classes } role = { role } aria - label = { props.aria_label
119        .clone() } > { for props.children.iter() } </ div >
120    }
121}
122/// Props for the ButtonToolbar component
123#[derive(Properties, PartialEq)]
124pub struct ButtonToolbarProps {
125    /// Button toolbar children (button groups)
126    #[prop_or_default]
127    pub children: Children,
128    /// Additional CSS classes
129    #[prop_or_default]
130    pub class: Option<AttrValue>,
131    /// ARIA label for accessibility
132    #[prop_or_default]
133    pub aria_label: Option<AttrValue>,
134    /// Role attribute (defaults to "toolbar")
135    #[prop_or_default]
136    pub role: Option<String>,
137}
138/// Bootstrap ButtonToolbar component
139#[function_component(ButtonToolbar)]
140pub fn button_toolbar(props: &ButtonToolbarProps) -> Html {
141    let mut classes = Classes::new();
142    classes.push("btn-toolbar");
143    if let Some(class) = &props.class {
144        classes.push(class.to_string());
145    }
146    let role = props.role.clone().unwrap_or_else(|| "toolbar".to_string());
147    html! {
148        < div class = { classes } role = { role } aria - label = { props.aria_label
149        .clone() } > { for props.children.iter() } </ div >
150    }
151}