material_dioxus/
radio.rs

1use std::marker::PhantomData;
2
3use dioxus::prelude::*;
4use gloo::events::EventListener;
5use wasm_bindgen::prelude::*;
6use web_sys::Node;
7
8use crate::utils::StaticCallback;
9
10#[wasm_bindgen(module = "/build/mwc-radio.js")]
11extern "C" {
12    #[derive(Debug)]
13    #[wasm_bindgen(extends = Node)]
14    type Radio;
15
16    #[wasm_bindgen(getter, static_method_of = Radio)]
17    fn _dummy_loader() -> JsValue;
18
19    #[wasm_bindgen(method, getter)]
20    fn checked(this: &Radio) -> bool;
21
22    #[wasm_bindgen(method, setter)]
23    fn set_checked(this: &Radio, value: bool);
24}
25
26loader_hack!(Radio);
27
28/// Props for [`MatRadio`]
29///
30/// MWC Documentation:
31///
32/// - [Properties](https://github.com/material-components/material-components-web-components/tree/v0.27.0/packages/radio#propertiesattributes)
33/// - [Events](https://github.com/material-components/material-components-web-components/tree/v0.27.0/packages/radio#events)
34#[derive(Props)]
35pub struct RadioProps<'a> {
36    #[props(default)]
37    pub checked: bool,
38    #[props(default)]
39    pub disabled: bool,
40    #[props(into)]
41    pub name: Option<String>,
42    #[props(into)]
43    pub value: Option<String>,
44    #[props(default)]
45    pub global: bool,
46    #[props(default)]
47    pub reduced_touch_target: bool,
48    /// Binds to `change`.
49    ///
50    /// Callback's parameter of type denotes if the radio is checked or not.
51    ///
52    /// See events docs to learn more.
53    #[props(into)]
54    // the name cannot start with `on` or dioxus will expect an `EventHandler` which aren't static
55    // and thus cannot be used here
56    pub _onchange: Option<StaticCallback<bool>>,
57    _lifetime: Option<PhantomData<&'a ()>>,
58
59    #[props(into, default)]
60    pub style: String,
61    #[props(into, default)]
62    pub class: String,
63    #[props(into)]
64    pub slot: Option<String>,
65    #[props(default)]
66    pub dialog_initial_focus: bool,
67}
68
69fn render<'a>(cx: Scope<'a, RadioProps<'a>>) -> Element<'a> {
70    let id = crate::use_id(cx, "radio");
71    let change_listener = cx.use_hook(|| None);
72    if let Some(elem) = crate::get_elem_by_id(id) {
73        let target = elem.clone();
74        let radio = JsValue::from(elem).dyn_into::<Radio>().unwrap();
75        radio.set_checked(cx.props.checked);
76        if let Some(listener) = cx.props._onchange.clone() {
77            *change_listener = Some(EventListener::new(&target, "change", move |_| {
78                listener.call(radio.checked())
79            }));
80        }
81    }
82    render! {
83        mwc-radio {
84            id: id,
85
86            disabled: bool_attr!(cx.props.disabled),
87            name: optional_string_attr!(cx.props.name),
88            value: optional_string_attr!(cx.props.value),
89            global: bool_attr!(cx.props.global),
90            reducedTouchTarget: bool_attr!(cx.props.reduced_touch_target),
91
92            style: string_attr!(cx.props.style),
93            class: string_attr!(cx.props.class),
94            slot: optional_string_attr!(cx.props.slot),
95            dialogInitialFocus: bool_attr!(cx.props.dialog_initial_focus),
96        }
97    }
98}
99
100component!('a, MatRadio, RadioProps, render, Radio, "radio");