Skip to main content

maud_ui/primitives/
toggle.rs

1//! Toggle component — two-state button (pressed/unpressed)
2use maud::{html, Markup};
3
4#[derive(Clone, Debug, Default, PartialEq)]
5pub enum Size {
6    #[default]
7    Md,
8    Sm,
9}
10
11#[derive(Clone, Debug, Default, PartialEq)]
12pub enum Variant {
13    #[default]
14    Default,
15    Outline,
16}
17
18#[derive(Clone, Debug)]
19pub struct Props {
20    pub label: String,
21    pub pressed: bool,
22    pub disabled: bool,
23    pub id: String,
24    pub size: Size,
25    pub variant: Variant,
26}
27
28impl Default for Props {
29    fn default() -> Self {
30        Self {
31            label: "Toggle".to_string(),
32            pressed: false,
33            disabled: false,
34            id: "toggle".to_string(),
35            size: Size::Md,
36            variant: Variant::Default,
37        }
38    }
39}
40
41pub fn render(props: Props) -> Markup {
42    let aria_pressed = if props.pressed { "true" } else { "false" };
43    let size_cls = match props.size {
44        Size::Md => "mui-toggle--md",
45        Size::Sm => "mui-toggle--sm",
46    };
47    let variant_cls = match props.variant {
48        Variant::Default => "",
49        Variant::Outline => "mui-toggle--outline",
50    };
51
52    html! {
53        button type="button"
54            class={"mui-toggle " (size_cls) " " (variant_cls)}
55            aria-pressed=(aria_pressed)
56            id=(props.id)
57            data-mui="toggle"
58            disabled[props.disabled]
59        {
60            (props.label)
61        }
62    }
63}
64
65pub fn showcase() -> Markup {
66    html! {
67        div.mui-showcase__grid {
68            // Text-editor toolbar context
69            section {
70                h2 { "Text Editor Toolbar" }
71                p.mui-showcase__caption { "Default variant — formatting controls" }
72                div.mui-showcase__row {
73                    (render(Props {
74                        label: "B".to_string(),
75                        pressed: true,
76                        id: "toolbar-bold".to_string(),
77                        ..Default::default()
78                    }))
79                    (render(Props {
80                        label: "I".to_string(),
81                        pressed: false,
82                        id: "toolbar-italic".to_string(),
83                        ..Default::default()
84                    }))
85                    (render(Props {
86                        label: "U".to_string(),
87                        pressed: false,
88                        id: "toolbar-underline".to_string(),
89                        ..Default::default()
90                    }))
91                }
92                p.mui-showcase__caption { "Outline variant" }
93                div.mui-showcase__row {
94                    (render(Props {
95                        label: "B".to_string(),
96                        pressed: true,
97                        variant: Variant::Outline,
98                        id: "toolbar-outline-bold".to_string(),
99                        ..Default::default()
100                    }))
101                    (render(Props {
102                        label: "I".to_string(),
103                        pressed: false,
104                        variant: Variant::Outline,
105                        id: "toolbar-outline-italic".to_string(),
106                        ..Default::default()
107                    }))
108                    (render(Props {
109                        label: "U".to_string(),
110                        pressed: false,
111                        variant: Variant::Outline,
112                        id: "toolbar-outline-underline".to_string(),
113                        ..Default::default()
114                    }))
115                }
116            }
117
118            // Sizes
119            section {
120                h2 { "Sizes" }
121                div.mui-showcase__row {
122                    span.mui-showcase__label { "md" }
123                    (render(Props {
124                        label: "B".to_string(),
125                        pressed: true,
126                        id: "size-md-b".to_string(),
127                        ..Default::default()
128                    }))
129                    (render(Props {
130                        label: "I".to_string(),
131                        pressed: false,
132                        id: "size-md-i".to_string(),
133                        ..Default::default()
134                    }))
135                }
136                div.mui-showcase__row {
137                    span.mui-showcase__label { "sm" }
138                    (render(Props {
139                        label: "B".to_string(),
140                        pressed: true,
141                        size: Size::Sm,
142                        id: "size-sm-b".to_string(),
143                        ..Default::default()
144                    }))
145                    (render(Props {
146                        label: "I".to_string(),
147                        pressed: false,
148                        size: Size::Sm,
149                        id: "size-sm-i".to_string(),
150                        ..Default::default()
151                    }))
152                }
153            }
154
155            // Disabled
156            section {
157                h2 { "Disabled" }
158                div.mui-showcase__row {
159                    (render(Props {
160                        label: "Off".to_string(),
161                        disabled: true,
162                        id: "toggle-dis-off".to_string(),
163                        ..Default::default()
164                    }))
165                    (render(Props {
166                        label: "On".to_string(),
167                        pressed: true,
168                        disabled: true,
169                        id: "toggle-dis-on".to_string(),
170                        ..Default::default()
171                    }))
172                }
173            }
174        }
175    }
176}