dioxus_web/events/
mounted.rs

1use dioxus_html::{
2    geometry::euclid::{Point2D, Size2D},
3    MountedData,
4};
5use wasm_bindgen::JsCast;
6
7use super::{Synthetic, WebEventExt};
8
9impl dioxus_html::RenderedElementBacking for Synthetic<web_sys::Element> {
10    fn get_scroll_offset(
11        &self,
12    ) -> std::pin::Pin<
13        Box<
14            dyn std::future::Future<
15                Output = dioxus_html::MountedResult<dioxus_html::geometry::PixelsVector2D>,
16            >,
17        >,
18    > {
19        let left = self.event.scroll_left();
20        let top = self.event.scroll_top();
21        let result = Ok(dioxus_html::geometry::PixelsVector2D::new(
22            left as f64,
23            top as f64,
24        ));
25        Box::pin(async { result })
26    }
27
28    fn get_scroll_size(
29        &self,
30    ) -> std::pin::Pin<
31        Box<
32            dyn std::future::Future<
33                Output = dioxus_html::MountedResult<dioxus_html::geometry::PixelsSize>,
34            >,
35        >,
36    > {
37        let width = self.event.scroll_width();
38        let height = self.event.scroll_height();
39        let result = Ok(dioxus_html::geometry::PixelsSize::new(
40            width as f64,
41            height as f64,
42        ));
43        Box::pin(async { result })
44    }
45
46    fn get_client_rect(
47        &self,
48    ) -> std::pin::Pin<
49        Box<
50            dyn std::future::Future<
51                Output = dioxus_html::MountedResult<dioxus_html::geometry::PixelsRect>,
52            >,
53        >,
54    > {
55        let rect = self.event.get_bounding_client_rect();
56        let result = Ok(dioxus_html::geometry::PixelsRect::new(
57            Point2D::new(rect.left(), rect.top()),
58            Size2D::new(rect.width(), rect.height()),
59        ));
60        Box::pin(async { result })
61    }
62
63    fn as_any(&self) -> &dyn std::any::Any {
64        &self.event
65    }
66
67    fn scroll_to(
68        &self,
69        input_options: dioxus_html::ScrollToOptions,
70    ) -> std::pin::Pin<Box<dyn std::future::Future<Output = dioxus_html::MountedResult<()>>>> {
71        let options = web_sys::ScrollIntoViewOptions::new();
72        options.set_behavior(match input_options.behavior {
73            dioxus_html::ScrollBehavior::Instant => web_sys::ScrollBehavior::Instant,
74            dioxus_html::ScrollBehavior::Smooth => web_sys::ScrollBehavior::Smooth,
75        });
76        options.set_block(match input_options.vertical {
77            dioxus_html::ScrollLogicalPosition::Start => web_sys::ScrollLogicalPosition::Start,
78            dioxus_html::ScrollLogicalPosition::Center => web_sys::ScrollLogicalPosition::Center,
79            dioxus_html::ScrollLogicalPosition::End => web_sys::ScrollLogicalPosition::End,
80            dioxus_html::ScrollLogicalPosition::Nearest => web_sys::ScrollLogicalPosition::Nearest,
81        });
82        options.set_inline(match input_options.horizontal {
83            dioxus_html::ScrollLogicalPosition::Start => web_sys::ScrollLogicalPosition::Start,
84            dioxus_html::ScrollLogicalPosition::Center => web_sys::ScrollLogicalPosition::Center,
85            dioxus_html::ScrollLogicalPosition::End => web_sys::ScrollLogicalPosition::End,
86            dioxus_html::ScrollLogicalPosition::Nearest => web_sys::ScrollLogicalPosition::Nearest,
87        });
88        self.event
89            .scroll_into_view_with_scroll_into_view_options(&options);
90
91        Box::pin(async { Ok(()) })
92    }
93
94    fn scroll(
95        &self,
96        coordinates: dioxus_html::geometry::PixelsVector2D,
97        behavior: dioxus_html::ScrollBehavior,
98    ) -> std::pin::Pin<Box<dyn std::future::Future<Output = dioxus_html::MountedResult<()>>>> {
99        let options = web_sys::ScrollToOptions::new();
100        options.set_top(coordinates.y);
101        options.set_left(coordinates.x);
102        match behavior {
103            dioxus_html::ScrollBehavior::Instant => {
104                options.set_behavior(web_sys::ScrollBehavior::Instant);
105            }
106            dioxus_html::ScrollBehavior::Smooth => {
107                options.set_behavior(web_sys::ScrollBehavior::Smooth);
108            }
109        }
110        self.event.scroll_with_scroll_to_options(&options);
111
112        Box::pin(async { Ok(()) })
113    }
114
115    fn set_focus(
116        &self,
117        focus: bool,
118    ) -> std::pin::Pin<Box<dyn std::future::Future<Output = dioxus_html::MountedResult<()>>>> {
119        #[derive(Debug)]
120        struct FocusError(wasm_bindgen::JsValue);
121
122        impl std::fmt::Display for FocusError {
123            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124                write!(f, "failed to focus element {:?}", self.0)
125            }
126        }
127
128        impl std::error::Error for FocusError {}
129
130        let result = self
131            .event
132            .dyn_ref::<web_sys::HtmlElement>()
133            .ok_or_else(|| {
134                dioxus_html::MountedError::OperationFailed(Box::new(FocusError(
135                    self.event.clone().into(),
136                )))
137            })
138            .and_then(|e| {
139                (if focus { e.focus() } else { e.blur() }).map_err(|err| {
140                    dioxus_html::MountedError::OperationFailed(Box::new(FocusError(err)))
141                })
142            });
143        Box::pin(async { result })
144    }
145}
146
147impl WebEventExt for MountedData {
148    type WebEvent = web_sys::Element;
149
150    #[inline(always)]
151    fn try_as_web_event(&self) -> Option<web_sys::Element> {
152        self.downcast::<web_sys::Element>().cloned()
153    }
154}