floating_ui/floating_ui/dom/
auto_update.rs

1use js_sys::Object;
2use wasm_bindgen::prelude::*;
3use web_sys::HtmlElement;
4
5use crate::{
6    error::{Error, Result},
7    utils_::object_utils,
8};
9
10#[wasm_bindgen(js_namespace=["window", "FloatingUIDOM"])]
11extern "C" {
12    #[wasm_bindgen]
13    fn autoUpdate(
14        reference: HtmlElement,
15        floating: HtmlElement,
16        update: &Closure<dyn Fn()>,
17        options: JsValue,
18    );
19}
20
21pub fn auto_update<F>(
22    reference: HtmlElement,
23    floating: HtmlElement,
24    update: F,
25    options: AutoUpdateOptions,
26) -> Result<()>
27where
28    F: Fn() + 'static,
29{
30    let update: Closure<dyn Fn()> = Closure::new(update);
31    let options: JsValue = options.try_into()?;
32
33    // TODO cleanup type
34    let cleanup = autoUpdate(reference, floating, &update, options);
35
36    update.forget();
37
38    Ok(cleanup)
39}
40pub struct AutoUpdateOptions {
41    ancestor_scroll: Option<bool>,
42    ancestor_resize: Option<bool>,
43    element_resize: Option<bool>,
44    layout_shift: Option<bool>,
45    animation_frame: Option<bool>,
46}
47
48impl AutoUpdateOptions {
49    pub fn new() -> Self {
50        Self {
51            ancestor_scroll: None,
52            ancestor_resize: None,
53            element_resize: None,
54            layout_shift: None,
55            animation_frame: None,
56        }
57    }
58
59    pub fn ancestor_scroll(&mut self) -> &mut Self {
60        self.ancestor_scroll = Some(true);
61        self
62    }
63
64    pub fn ancestor_resize(&mut self) -> &mut Self {
65        self.ancestor_resize = Some(true);
66        self
67    }
68
69    pub fn element_resize(&mut self) -> &mut Self {
70        self.element_resize = Some(true);
71        self
72    }
73
74    pub fn layout_shift(&mut self) -> &mut Self {
75        self.layout_shift = Some(true);
76        self
77    }
78
79    pub fn animation_frame(&mut self) -> &mut Self {
80        self.animation_frame = Some(true);
81        self
82    }
83}
84
85impl TryInto<JsValue> for AutoUpdateOptions {
86    type Error = Error;
87
88    fn try_into(self) -> Result<JsValue> {
89        let obj = Object::new();
90
91        object_utils::set_option_bool(&obj, "ancestorScroll", self.ancestor_scroll)?;
92        object_utils::set_option_bool(&obj, "ancestorResize", self.ancestor_resize)?;
93        object_utils::set_option_bool(&obj, "elementResize", self.element_resize)?;
94        object_utils::set_option_bool(&obj, "layoutShift", self.layout_shift)?;
95        object_utils::set_option_bool(&obj, "animationFrame", self.animation_frame)?;
96
97        Ok(obj.into())
98    }
99}