1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use crate::core::impl_ssr_safe_method;
use crate::{use_document, UseDocument};
use cfg_if::cfg_if;
use std::ops::Deref;

#[cfg(not(feature = "ssr"))]
use leptos::*;

/// SSR safe `window()`.
/// This returns just a new-type wrapper around `Option<Window>`.
/// Calling this amounts to `None` on the server and `Some(Window)` on the client.
///
/// It provides some convenient methods for working with the window like `document()` and `navigator()`.
/// These will all return `None` on the server.
///
/// ## Usage
///
/// ```
/// # use leptos::*;
/// # use leptos_use::use_window;
/// #
/// # #[component]
/// # fn Demo() -> impl IntoView {
/// let window = use_window();
///
/// // Returns `None` on the server but will not panic.
/// let navigator = window.navigator();
/// #
/// # view! { }
/// # }
/// ```
pub fn use_window() -> UseWindow {
    cfg_if! { if #[cfg(feature = "ssr")] {
        UseWindow(None)
    } else {
        UseWindow(Some(window()))
    }}
}

/// Return type of [`use_window`].
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UseWindow(Option<web_sys::Window>);

impl Deref for UseWindow {
    type Target = Option<web_sys::Window>;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl UseWindow {
    impl_ssr_safe_method!(
        /// Returns `Some(Navigator)` in the Browser. `None` otherwise.
        navigator(&self) -> Option<web_sys::Navigator>
    );

    /// Returns the same as [`use_document`].
    #[inline(always)]
    pub fn document(&self) -> UseDocument {
        use_document()
    }

    impl_ssr_safe_method!(
        /// Returns the same as `window().match_media()` in the Browser. `Ok(None)` otherwise.
        match_media(&self, query: &str) -> Result<Option<web_sys::MediaQueryList>, wasm_bindgen::JsValue>;
        .unwrap_or(Ok(None))
    );
}