Skip to main content

euv_ui/hook/use_resize_observer/
impl.rs

1use super::*;
2
3/// Inherent implementation of [`UseResizeObserver`].
4impl UseResizeObserver {
5    /// Creates a handle with the size starting at zero.
6    ///
7    /// # Returns
8    ///
9    /// - `UseResizeObserver` - The fresh handle.
10    pub(crate) fn new() -> Self {
11        Self {
12            target: NodeRef::new(),
13            width: Signal::create(0.0),
14            height: Signal::create(0.0),
15            teardown: Rc::new(RefCell::new(None)),
16        }
17    }
18
19    /// Returns the current width as a snapshot.
20    ///
21    /// # Returns
22    ///
23    /// - `f64` - The content-box width in CSS pixels.
24    pub fn current_width(&self) -> f64 {
25        self.get_width().get()
26    }
27
28    /// Returns the current height as a snapshot.
29    ///
30    /// # Returns
31    ///
32    /// - `f64` - The content-box height in CSS pixels.
33    pub fn current_height(&self) -> f64 {
34        self.get_height().get()
35    }
36
37    /// Creates the observer and starts watching the element.
38    ///
39    /// The element does not exist while the first render is being
40    /// built, so the `observe` call is deferred until after the DOM
41    /// has been committed.
42    pub(crate) fn attach(&self) {
43        #[cfg(target_arch = "wasm32")]
44        {
45            let width: Signal<f64> = self.get_width();
46            let height: Signal<f64> = self.get_height();
47            let closure: Closure<dyn FnMut(Array)> =
48                Closure::wrap(Box::new(move |entries: Array| {
49                    for entry in entries.iter() {
50                        let Ok(entry) = entry.dyn_into::<ResizeObserverEntry>() else {
51                            continue;
52                        };
53                        let rect: DomRectReadOnly = entry.content_rect();
54                        width.set(rect.width());
55                        height.set(rect.height());
56                    }
57                }));
58            let Ok(observer) = ResizeObserver::new(closure.as_ref().unchecked_ref()) else {
59                return;
60            };
61            let target: NodeRef<Element> = self.get_target().clone();
62            let observed: ResizeObserver = observer.clone();
63            after_mount(move || {
64                if let Some(element) = target.get_cloned() {
65                    observed.observe(&element);
66                }
67            });
68            let disconnect: Rc<RefCell<Option<ResizeObserver>>> =
69                Rc::new(RefCell::new(Some(observer)));
70            *self.get_teardown().borrow_mut() = Some(Box::new(move || {
71                if let Some(observer) = disconnect.borrow_mut().take() {
72                    observer.disconnect();
73                }
74            }));
75        }
76    }
77
78    /// Disconnects the observer.
79    pub(crate) fn detach(&self) {
80        let taken: Option<Box<dyn Fn()>> = self.get_teardown().borrow_mut().take();
81        if let Some(teardown) = taken {
82            teardown();
83        }
84    }
85}