material_dioxus/
dialog.rs

1mod dialog_action;
2
3pub use dialog_action::*;
4
5use dioxus::prelude::*;
6use gloo::events::EventListener;
7use wasm_bindgen::prelude::*;
8use web_sys::Node;
9
10use crate::StaticCallback;
11
12#[wasm_bindgen(module = "/build/mwc-dialog.js")]
13extern "C" {
14    #[derive(Debug)]
15    #[wasm_bindgen(extends = Node)]
16    type Dialog;
17
18    #[wasm_bindgen(getter, static_method_of = Dialog)]
19    fn _dummy_loader() -> JsValue;
20
21    #[wasm_bindgen(method)]
22    fn focus(this: &Dialog);
23
24    #[wasm_bindgen(method)]
25    fn blur(this: &Dialog);
26
27    #[wasm_bindgen(method)]
28    fn show(this: &Dialog);
29
30    #[wasm_bindgen(method)]
31    fn close(this: &Dialog);
32}
33
34loader_hack!(Dialog);
35
36// /// The `mwc-dialog` component.
37// ///
38// /// [MWC Documentation](https://github.com/material-components/material-components-web-components/tree/v0.27.0/packages/dialog)
39// ///
40// /// ## Actions
41// ///
42// /// In order to pass actions, [`MatDialogAction`] component should be
43// /// used.
44// pub struct MatDialog {
45//     node_ref: NodeRef,
46//     opening_listener: Option<EventListener>,
47//     opened_listener: Option<EventListener>,
48//     closing_listener: Option<EventListener>,
49//     closed_listener: Option<EventListener>,
50// }
51
52/// Props for [`MatDialog`]
53///
54/// MWC Documentation:
55///
56/// - [Properties](https://github.com/material-components/material-components-web-components/tree/v0.27.0/packages/dialog#propertiesattributes)
57/// - [Events](https://github.com/material-components/material-components-web-components/tree/v0.27.0/packages/dialog#events)
58#[derive(Props)]
59pub struct DialogProps<'a> {
60    #[props(default)]
61    pub open: bool,
62    #[props(default)]
63    pub hide_actions: bool,
64    #[props(default)]
65    pub stacked: bool,
66    #[props(into)]
67    pub heading: Option<String>,
68    #[props(into)]
69    pub scrim_click_action: Option<String>,
70    #[props(into)]
71    pub escape_key_action: Option<String>,
72    #[props(into)]
73    pub default_action: Option<String>,
74    #[props(into)]
75    pub action_attribute: Option<String>,
76    #[props(into)]
77    pub initial_focus_attribute: Option<String>,
78    /// Binds to `opening` event on `mwc-dialog`
79    ///
80    /// See events docs to learn more.
81    #[props(into)]
82    pub _onopening: Option<StaticCallback<()>>,
83    /// Binds to `opened` event on `mwc-dialog`
84    ///
85    /// See events docs to learn more.
86    #[props(into)]
87    pub _onopened: Option<StaticCallback<()>>,
88    /// Binds to `closing` event on `mwc-dialog`
89    ///
90    /// See events docs to learn more.
91    #[props(into)]
92    pub _onclosing: Option<StaticCallback<String>>,
93    /// Binds to `closed` event on `mwc-dialog`
94    ///
95    /// See events docs to learn more.
96    #[props(into)]
97    pub _onclosed: Option<StaticCallback<String>>,
98    // TODO: make methods callable
99    // /// [`WeakComponentLink`] for `MatDialog` which provides the following
100    // /// methods:
101    // /// - ```focus(&self)```
102    // /// - ```blur(&self)```
103    // /// - ```show(&self)```
104    // /// - ```close(&self)```
105    // ///
106    // /// See [`WeakComponentLink`] documentation for more information
107    // #[props(default)]
108    // pub dialog_link: WeakComponentLink<MatDialog>,
109    pub children: Element<'a>,
110
111    #[props(into, default)]
112    pub style: String,
113    #[props(into, default)]
114    pub class: String,
115}
116
117fn render<'a>(cx: Scope<'a, DialogProps<'a>>) -> Element<'a> {
118    let id = crate::use_id(cx, "dialog");
119    let opening_listener = cx.use_hook(|| None);
120    let opened_listener = cx.use_hook(|| None);
121    let closing_listener = cx.use_hook(|| None);
122    let closed_listener = cx.use_hook(|| None);
123    if let Some(elem) = crate::get_elem_by_id(id) {
124        let target = elem;
125        if let Some(listener) = cx.props._onopening.clone() {
126            *opening_listener = Some(EventListener::new(&target, "opening", move |_| {
127                listener.call(())
128            }));
129        }
130        if let Some(listener) = cx.props._onopened.clone() {
131            *opened_listener = Some(EventListener::new(&target, "opened", move |_| {
132                listener.call(())
133            }));
134        }
135        if let Some(listener) = cx.props._onclosing.clone() {
136            *closing_listener = Some(EventListener::new(&target, "closing", move |event| {
137                listener.call(action_from_event(event))
138            }));
139        }
140        if let Some(listener) = cx.props._onclosed.clone() {
141            *closed_listener = Some(EventListener::new(&target, "closed", move |event| {
142                listener.call(action_from_event(event))
143            }));
144        }
145    }
146    render! {
147        mwc-dialog {
148            id: id,
149
150            open: bool_attr!(cx.props.open),
151            hideActions: bool_attr!(cx.props.hide_actions),
152            stacked: bool_attr!(cx.props.stacked),
153            heading: optional_string_attr!(cx.props.heading),
154            scrimClickAction: optional_string_attr!(cx.props.scrim_click_action),
155            escapeKeyAction: optional_string_attr!(cx.props.escape_key_action),
156            defaultAction: optional_string_attr!(cx.props.default_action),
157            actionAttribute: optional_string_attr!(cx.props.action_attribute),
158            initialFocusAttribute: optional_string_attr!(cx.props.initial_focus_attribute),
159
160            style: "position: absolute; {cx.props.style}",
161            class: string_attr!(cx.props.class),
162
163            &cx.props.children
164        }
165    }
166}
167
168component!('a, MatDialog, DialogProps, render, Dialog, "dialog");
169
170#[wasm_bindgen]
171extern "C" {
172    type DialogActionType;
173
174    #[wasm_bindgen(method, getter)]
175    fn action(this: &DialogActionType) -> String;
176}
177
178fn action_from_event(event: &web_sys::Event) -> String {
179    crate::event_details_into::<DialogActionType>(event).action()
180}