yew_bootstrap/component/button.rs
1use crate::util::Color;
2use yew::prelude::*;
3
4#[derive(Clone, PartialEq, Eq)]
5pub enum ButtonSize {
6 Large,
7 Normal,
8 Small,
9}
10
11impl Default for ButtonSize {
12 fn default() -> Self {
13 ButtonSize::Normal
14 }
15}
16
17/// # Button component
18/// Button with various properties, including support for opening or closing a modal
19/// dialog [crate::component::Modal].
20///
21/// Buttons can be grouped in a [crate::component::ButtonGroup].
22///
23/// See [ButtonProps] for a listing of properties.
24///
25/// ## Example
26/// Example of a simple button:
27///
28/// ```rust
29/// use yew::prelude::*;
30/// use yew_bootstrap::component::Button;
31/// use yew_bootstrap::util::Color;
32/// fn test() -> Html {
33/// html!{
34/// <Button style={Color::Primary} text={ "Button text" }/>
35/// }
36/// }
37/// ```
38///
39/// A button can be linked to a [crate::component::Modal] dialog or
40/// close this modal.
41///
42/// ```rust
43/// use yew::prelude::*;
44/// use yew_bootstrap::component::Button;
45/// use yew_bootstrap::component::Modal;
46/// use yew_bootstrap::util::Color;
47/// fn test() -> Html {
48/// html ! {
49/// <>
50/// <Modal id="ExampleModal">
51/// <Button modal_dismiss={true}>{ "Close the modal" }</Button>
52/// </Modal>
53/// <Button style={Color::Primary} modal_target={ "ExampleModal" }>
54/// { "Open Modal" }
55/// </Button>
56/// </>
57/// }
58/// }
59/// ```
60///
61/// A button may also link to a web page.
62///
63/// ```rust
64/// use yew::prelude::*;
65/// use yew_bootstrap::component::Button;
66/// use yew_bootstrap::util::Color;
67/// fn test() -> Html {
68/// html!{
69/// <Button style={Color::Primary} text={ "Button text" } url={ "https://getbootstrap.com/docs/5.3/components/buttons/#button-tags" } target={"_blank"} />
70/// }
71/// }
72/// ```
73pub struct Button {}
74
75/// # Properties for [Button]
76#[derive(Properties, Clone, PartialEq)]
77pub struct ButtonProps {
78 /// CSS class
79 #[prop_or_default]
80 pub class: String,
81
82 /// Optional children
83 #[prop_or_default]
84 pub children: Children,
85
86 /// Treat button as block that spans the full width of the parent
87 #[prop_or_default]
88 pub block: bool,
89
90 /// Status of the button. Disabled buttons cannot be clicked.
91 #[prop_or_default]
92 pub disabled: bool,
93
94 /// Name of the component
95 #[prop_or_default]
96 pub name: String,
97
98 /// Event called when the button is clicked
99 #[prop_or_default]
100 pub onclick: Callback<MouseEvent>,
101
102 /// Show button as outlined instead of filled
103 #[prop_or_default]
104 pub outline: bool,
105
106 /// Size of the button
107 #[prop_or_default]
108 pub size: ButtonSize,
109
110 /// Color of the button, default [Color::Primary]
111 #[prop_or(Color::Primary)]
112 pub style: Color,
113
114 /// Text displayed in the button
115 #[prop_or_default]
116 pub text: String,
117
118 /// if provided, we will set data-bs-toggle and data-bs-target for modal opening
119 #[prop_or_default]
120 pub modal_target: Option<String>,
121
122 /// true if this button dismisses the modal that contains it
123 #[prop_or_default]
124 pub modal_dismiss: bool,
125
126 /// URL to direct to when the button is clicked. This turns the button into
127 /// an `<a>` element.
128 ///
129 /// This property is ignored if the button is `disabled` to
130 /// [avoid link functionality caveats][0], which may result in
131 /// [slightly different rendering on some browsers / platforms][1].
132 ///
133 /// [0]: https://getbootstrap.com/docs/5.3/components/buttons/#link-functionality-caveat
134 /// [1]: https://getbootstrap.com/docs/5.3/components/buttons/#button-tags
135 #[prop_or_default]
136 pub url: Option<AttrValue>,
137
138 /// Target frame or window ID for the link. Only used if `url` is set and
139 /// the button is not `disabled`.
140 #[prop_or_default]
141 pub target: Option<AttrValue>,
142
143 /// Reference to the [NodeRef] of the button's underlying `<button>` or
144 /// `<a>` element.
145 ///
146 /// Used by components which add custom event handlers directly to the DOM.
147 ///
148 /// See [*Node Refs* in the Yew documentation][0] for more information.
149 ///
150 /// [0]: https://yew.rs/docs/concepts/function-components/node-refs
151 #[prop_or_default]
152 pub node_ref: NodeRef,
153
154 /// Optional HTML element ID for the underlying `<button>` or `<a>` element.
155 #[prop_or_default]
156 pub id: Option<AttrValue>,
157}
158
159impl Component for Button {
160 type Message = ();
161 type Properties = ButtonProps;
162
163 fn create(_ctx: &Context<Self>) -> Self {
164 Self {}
165 }
166
167 fn view(&self, ctx: &Context<Self>) -> Html {
168 let props = ctx.props();
169 let mut classes = Classes::new();
170 classes.push("btn");
171 if props.outline {
172 classes.push(format!("btn-outline-{}", props.style));
173 } else {
174 classes.push(format!("btn-{}", props.style));
175 }
176 match props.size {
177 ButtonSize::Large => classes.push("btn-lg"),
178 ButtonSize::Small => classes.push("btn-sm"),
179 _ => (),
180 }
181 if props.block {
182 classes.push("btn-block");
183 }
184 classes.push(props.class.clone());
185
186 let modal_dismiss = match props.modal_dismiss {
187 true => "modal",
188 false => "",
189 };
190
191 if let Some(target) = &props.modal_target {
192 html! {
193 <button
194 class={classes}
195 disabled={props.disabled}
196 name={props.name.clone()}
197 onclick={props.onclick.clone()}
198 data-bs-toggle="modal"
199 data-bs-target={format!("#{}",target.clone())}
200 ref={props.node_ref.clone()}
201 id={props.id.clone()}
202 >
203 { &props.text }
204 { for props.children.iter() }
205 </button>
206 }
207 } else if let Some(url) = props.url.as_ref().filter(|_| !props.disabled) {
208 html! {
209 <a
210 class={classes}
211 disabled={props.disabled}
212 name={props.name.clone()}
213 onclick={props.onclick.clone()}
214 data-bs-dismiss={modal_dismiss}
215 href={url.clone()}
216 target={props.target.clone()}
217 ref={props.node_ref.clone()}
218 id={props.id.clone()}
219 >
220 { &props.text }
221 { for props.children.iter() }
222 </a>
223 }
224 } else {
225 html! {
226 <button
227 class={classes}
228 disabled={props.disabled}
229 name={props.name.clone()}
230 onclick={props.onclick.clone()}
231 data-bs-dismiss={modal_dismiss}
232 ref={props.node_ref.clone()}
233 id={props.id.clone()}
234 >
235 { &props.text }
236 { for props.children.iter() }
237 </button>
238 }
239 }
240 }
241}