yew_styles/components/
button.rs1use crate::styles::{get_palette, get_size, get_style, Palette, Size, Style};
2use stylist::{css, StyleSource};
3use wasm_bindgen_test::*;
4use web_sys::window;
5use yew::prelude::*;
6use yew::{utils, App};
7
8pub struct Button {
71 link: ComponentLink<Self>,
72 props: ButtonProps,
73}
74
75#[derive(PartialEq)]
76struct ButtonProps {
77 button_palette: String,
78 button_size: String,
79 button_style: String,
80 class_name: String,
81 id: String,
82 key: String,
83 code_ref: NodeRef,
84 onclick_signal: Callback<MouseEvent>,
85 styles: StyleSource<'static>,
86 children: Children,
87}
88
89impl From<Props> for ButtonProps {
90 fn from(props: Props) -> Self {
91 ButtonProps {
92 button_palette: get_palette(props.button_palette),
93 button_size: get_size(props.button_size),
94 button_style: get_style(props.button_style),
95 class_name: props.class_name,
96 id: props.id,
97 key: props.key,
98 code_ref: props.code_ref,
99 onclick_signal: props.onclick_signal,
100 styles: props.styles,
101 children: props.children,
102 }
103 }
104}
105
106#[derive(Clone, Properties, PartialEq)]
107pub struct Props {
108 #[prop_or(Palette::Standard)]
110 pub button_palette: Palette,
111 #[prop_or_default]
113 pub class_name: String,
114 #[prop_or_default]
116 pub id: String,
117 #[prop_or_default]
119 pub code_ref: NodeRef,
120 #[prop_or_default]
122 pub key: String,
123 #[prop_or(Size::Medium)]
125 pub button_size: Size,
126 #[prop_or(Style::Regular)]
128 pub button_style: Style,
129 pub onclick_signal: Callback<MouseEvent>,
131 #[prop_or(css!(""))]
133 pub styles: StyleSource<'static>,
134 pub children: Children,
135}
136
137pub enum Msg {
138 Clicked(MouseEvent),
139}
140
141impl Component for Button {
142 type Message = Msg;
143 type Properties = Props;
144
145 fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
146 Self {
147 link,
148 props: ButtonProps::from(props),
149 }
150 }
151
152 fn update(&mut self, msg: Self::Message) -> ShouldRender {
153 match msg {
154 Msg::Clicked(mouse_event) => {
155 self.props.onclick_signal.emit(mouse_event);
156 }
157 };
158
159 true
160 }
161
162 fn change(&mut self, props: Self::Properties) -> ShouldRender {
163 let prop_mapped = ButtonProps::from(props);
164 if self.props != prop_mapped {
165 self.props = prop_mapped;
166 return true;
167 }
168 true
169 }
170
171 fn view(&self) -> Html {
172 html! {
173 <button
174 onclick=self.link.callback(Msg::Clicked)
175 class=classes!("button",
176 self.props.button_palette.clone(),
177 self.props.button_size.clone(),
178 self.props.button_style.clone(),
179 self.props.class_name.clone(),
180 self.props.styles.clone(),
181 )
182 key=self.props.key.clone()
183 ref=self.props.code_ref.clone()
184 id=self.props.id.clone()
185 > { self.props.children.clone() }
186 </button>
187 }
188 }
189}
190
191wasm_bindgen_test_configure!(run_in_browser);
192
193#[wasm_bindgen_test]
194fn should_trigger_action_when_button_clicked() {
195 let body = window().unwrap().document().unwrap().body().unwrap();
196
197 let element = window()
198 .unwrap()
199 .document()
200 .unwrap()
201 .create_element("div")
202 .unwrap();
203 element.set_text_content(Some("home"));
204 element.set_id("menu");
205
206 body.append_child(&element).unwrap();
207
208 let onchange_name = Callback::from(|_| {
209 let content = window()
210 .unwrap()
211 .document()
212 .unwrap()
213 .get_element_by_id("menu")
214 .unwrap();
215
216 content.set_text_content(Some("about"));
217 });
218
219 let props = Props {
220 class_name: String::from("test-button"),
221 id: String::from("button-id-test"),
222 key: "".to_string(),
223 code_ref: NodeRef::default(),
224 button_size: Size::Medium,
225 button_style: Style::Regular,
226 onclick_signal: onchange_name,
227 button_palette: Palette::Standard,
228 styles: css!("background-color: #918d94;"),
229 children: Children::new(vec![html! {<div id="submenu">{"another menu"}</div>}]),
230 };
231
232 let mouse_event = MouseEvent::new("click").unwrap();
233
234 props.onclick_signal.emit(mouse_event);
235
236 let updated_content = window()
237 .unwrap()
238 .document()
239 .unwrap()
240 .get_element_by_id("menu")
241 .unwrap()
242 .text_content()
243 .unwrap();
244
245 assert_eq!(updated_content, String::from("about"));
246}
247
248#[wasm_bindgen_test]
249fn should_create_button_component() {
250 let props = Props {
251 class_name: String::from("test-button"),
252 id: String::from("button-id-test"),
253 key: "".to_string(),
254 code_ref: NodeRef::default(),
255 button_size: Size::Medium,
256 button_style: Style::Regular,
257 onclick_signal: Callback::noop(),
258 button_palette: Palette::Standard,
259 styles: css!("background-color: #918d94;"),
260 children: Children::new(vec![html! {<div id="result">{"result"}</div>}]),
261 };
262
263 let button: App<Button> = App::new();
264 button.mount_with_props(
265 utils::document().get_element_by_id("output").unwrap(),
266 props,
267 );
268
269 let button_element = utils::document()
270 .get_elements_by_tag_name("button")
271 .get_with_index(0)
272 .unwrap();
273
274 let child = button_element.first_element_child().unwrap();
275
276 assert_eq!(button_element.tag_name(), "BUTTON");
277 assert_eq!(child.id(), "result");
278}