//! Formatting + small browser helpers. use leptos::prelude::*; use wasm_bindgen::JsCast; use wasm_bindgen::closure::Closure; /// A window event listener that is removed when the current owner is disposed. /// /// Leptos' `window_event_listener` returns a `WindowListenerHandle` with no /// `Drop` impl — if the owning component is unmounted without an explicit /// `remove()`, the listener keeps firing on `window` and panics by reading /// the component's now-disposed signals. pub fn owned_window_listener( event: E, cb: impl Fn(E::EventType) + 'static, ) where E::EventType: wasm_bindgen::JsCast, { let handle = window_event_listener(event, cb); on_cleanup(move || handle.remove()); } /// Same as [`owned_window_listener`], but registered in the capture phase, /// so it runs before the bubble-phase window listeners (registration order /// otherwise decides, and that depends on component creation order). pub fn owned_window_listener_capture( event: E, cb: impl Fn(E::EventType) + 'static, ) where E::EventType: wasm_bindgen::JsCast, { let closure = Closure::::new({ move |e: web_sys::Event| cb(e.unchecked_into::()) }); let add_options = web_sys::AddEventListenerOptions::new(); add_options.set_capture(true); let remove_options = web_sys::EventListenerOptions::new(); remove_options.set_capture(true); let name = event.name(); web_sys::window() .expect("window") .add_event_listener_with_callback_and_add_event_listener_options( &name, closure.as_ref().unchecked_ref(), &add_options, ) .expect("failed to add window event listener"); let closure_js = closure.into_js_value(); on_cleanup(move || { let closure: js_sys::Function = closure_js.unchecked_into(); let _ = web_sys::window() .expect("window") .remove_event_listener_with_callback_and_event_listener_options( &name, &closure, &remove_options, ); }); } /// The value of a `