yew_more_hooks/hooks/
breakpoint.rs

1use yew::prelude::*;
2use yew_hooks::use_event_with_window;
3
4/// A trait characterizing breakpoints for viewport sizes.
5///
6/// ## Example
7///
8/// ```
9/// use yew_more_hooks::prelude::Breakpoint;
10///
11/// #[derive(PartialEq, Clone, Copy)]
12/// enum AppBreakpoint {
13///     Small,
14///     Large,
15/// }
16///
17/// impl Breakpoint for AppBreakpoint {
18///     fn from_screen_width(pixels: usize) -> Self {
19///         if pixels < Self::Large.as_pixels() {
20///             Self::Small
21///         } else {
22///             Self::Large
23///         }
24///     }
25///
26///     fn as_pixels(&self) -> usize {
27///         match self {
28///             Self::Small => 0,
29///             Self::Large => 1280,
30///         }
31///     }
32/// }
33/// ```
34pub trait Breakpoint: PartialEq + Sized {
35    fn as_pixels(&self) -> usize;
36
37    fn from_screen_width(pixels: usize) -> Self;
38
39    fn current() -> Self {
40        let width = web_sys::window()
41            .expect("Couldn't get window")
42            .inner_width()
43            .expect("Couldn't retrieve width of window")
44            .as_f64()
45            .expect("Couldn't convert window size to number")
46            .round();
47        Self::from_screen_width(width as usize)
48    }
49}
50
51/// Causes a rerender of a component when the viewport width is changed beyond a breakpoint.
52///
53/// ## Example
54/// ```
55/// # use yew_more_hooks::prelude::Breakpoint;
56/// use yew_more_hooks::prelude::use_breakpoint;
57/// use yew::prelude::*;
58/// #
59/// # #[derive(PartialEq, Clone, Copy)]
60/// # enum AppBreakpoint {
61/// #    Small,
62/// #    Large,
63/// # }
64/// #
65/// # impl Breakpoint for AppBreakpoint {
66/// #    fn from_screen_width(pixels: usize) -> Self {
67/// #        if pixels < Self::Large.as_pixels() {
68/// #            Self::Small
69/// #        } else {
70/// #            Self::Large
71/// #        }
72/// #    }
73/// #
74/// #    fn as_pixels(&self) -> usize {
75/// #        match self {
76/// #            Self::Small => 0,
77/// #            Self::Large => 1280,
78/// #        }
79/// #    }
80/// # }
81///
82/// #[function_component(Example)]
83/// fn example() -> Html {
84///     let breakpoint = use_breakpoint::<AppBreakpoint>();
85///     let label = use_memo(breakpoint.clone(), |breakpoint| match **breakpoint {
86///         AppBreakpoint::Small => html!("Label"),
87///         AppBreakpoint::Large => html!("A very long descriptive label"),
88///     });
89///     (*label).clone()
90/// }
91/// ```
92#[hook]
93pub fn use_breakpoint<T: Breakpoint + 'static>() -> UseStateHandle<T> {
94    let state: UseStateHandle<T> = use_state_eq(Breakpoint::current);
95    {
96        let state = state.clone();
97        use_event_with_window("resize", move |_: Event| {
98            state.set(Breakpoint::current());
99        });
100    }
101    state.clone()
102}