telegram_webapp_sdk/yew/
bottom_button.rs1use yew::prelude::*;
5
6use crate::webapp::{BottomButton as TgBottomButton, TelegramWebApp};
7
8#[component]
26pub fn BottomButton(props: &BottomButtonProps) -> Html {
27 use_effect_with(props.clone(), |props| {
28 if let Some(app) = TelegramWebApp::instance() {
29 if let Some(color) = props.color.as_ref() {
30 let _ = app.set_bottom_button_color(TgBottomButton::Main, color.as_ref());
31 }
32 if let Some(text_color) = props.text_color.as_ref() {
33 let _ =
34 app.set_bottom_button_text_color(TgBottomButton::Main, text_color.as_ref());
35 }
36 let _ = app.set_bottom_button_text(TgBottomButton::Main, props.text.as_ref());
37
38 let cb = props.on_click.clone();
39 let handle = app
40 .set_bottom_button_callback(TgBottomButton::Main, move || cb.emit(()))
41 .ok();
42 let _ = app.show_bottom_button(TgBottomButton::Main);
43
44 return Box::new(move || {
45 if let Some(h) = handle
46 && let Some(app) = TelegramWebApp::instance()
47 {
48 let _ = app.remove_bottom_button_callback(h);
49 let _ = app.hide_bottom_button(TgBottomButton::Main);
50 }
51 }) as Box<dyn FnOnce()>;
52 }
53
54 Box::new(|| {}) as Box<dyn FnOnce()>
55 });
56
57 Html::default()
58}
59
60#[derive(Properties, PartialEq, Clone)]
62pub struct BottomButtonProps {
63 pub text: AttrValue,
65 #[prop_or_default]
67 pub color: Option<AttrValue>,
68 #[prop_or_default]
70 pub text_color: Option<AttrValue>,
71 pub on_click: Callback<()>
73}
74
75#[cfg(all(test, feature = "yew"))]
76mod tests {
77 use std::rc::Rc;
78
79 use js_sys::{Function, Object, Reflect};
80 use wasm_bindgen::{JsCast, JsValue};
81 use wasm_bindgen_test::{wasm_bindgen_test, wasm_bindgen_test_configure};
82 use web_sys::window;
83
84 use super::*;
85
86 wasm_bindgen_test_configure!(run_in_browser);
87
88 #[allow(dead_code)]
89 fn setup_webapp() -> Object {
90 let win = window().expect("window should be available");
91 let telegram = Object::new();
92 let webapp = Object::new();
93 let _ = Reflect::set(&win, &"Telegram".into(), &telegram);
94 let _ = Reflect::set(&telegram, &"WebApp".into(), &webapp);
95 webapp
96 }
97
98 #[wasm_bindgen_test]
99 #[allow(dead_code)]
100 fn renders_and_registers_callback() {
101 let webapp = setup_webapp();
102 let main = Object::new();
103
104 let show = Function::new_with_args("", "this.show_called = true;");
105 let set_text = Function::new_with_args("t", "this.text = t;");
106 let set_color = Function::new_with_args("c", "this.color = c;");
107 let set_text_color = Function::new_with_args("c", "this.text_color = c;");
108 let on_click = Function::new_with_args("cb", "this.cb = cb;");
109 let off_click = Function::new_with_args("", "this.cb = undefined;");
110 let _ = Reflect::set(&main, &"show".into(), &show);
111 let _ = Reflect::set(&main, &"setText".into(), &set_text);
112 let _ = Reflect::set(&main, &"setColor".into(), &set_color);
113 let _ = Reflect::set(&main, &"setTextColor".into(), &set_text_color);
114 let _ = Reflect::set(&main, &"onClick".into(), &on_click);
115 let _ = Reflect::set(&main, &"offClick".into(), &off_click);
116 let _ = Reflect::set(&webapp, &"MainButton".into(), &main);
117
118 let clicked = Rc::new(std::cell::Cell::new(false));
119 let clicked_clone = Rc::clone(&clicked);
120 let props = BottomButtonProps {
121 text: AttrValue::from("Press"),
122 color: Some(AttrValue::from("#000000")),
123 text_color: Some(AttrValue::from("#ffffff")),
124 on_click: Callback::from(move |_| clicked_clone.set(true))
125 };
126 let document = window().unwrap().document().unwrap();
127 yew::Renderer::<BottomButton>::with_root_and_props(document.body().unwrap().into(), props)
128 .render();
129
130 let show_called = Reflect::get(&main, &"show_called".into())
131 .unwrap_or(JsValue::FALSE)
132 .as_bool()
133 .unwrap_or(false);
134 assert!(show_called);
135
136 let text = Reflect::get(&main, &"text".into())
137 .unwrap_or(JsValue::NULL)
138 .as_string()
139 .unwrap();
140 assert_eq!(text, "Press");
141
142 let cb = Reflect::get(&main, &"cb".into())
143 .unwrap()
144 .dyn_into::<Function>()
145 .unwrap();
146 let _ = cb.call0(&JsValue::NULL);
147 assert!(clicked.get());
148 }
149}