leptos_use/
use_media_query.rs1#![cfg_attr(feature = "ssr", allow(unused_variables, unused_imports, dead_code))]
2
3use crate::use_event_listener;
4use cfg_if::cfg_if;
5use leptos::ev::change;
6use leptos::prelude::*;
7use leptos::reactive::wrappers::read::Signal;
8use std::cell::RefCell;
9use std::rc::Rc;
10
11pub fn use_media_query(query: impl Into<Signal<String>>) -> Signal<bool> {
44 let query = query.into();
45
46 let (matches, set_matches) = signal(false);
47
48 cfg_if! { if #[cfg(not(feature = "ssr"))] {
49 let media_query: Rc<RefCell<Option<web_sys::MediaQueryList>>> = Rc::new(RefCell::new(None));
50 let remove_listener: RemoveListener = Rc::new(RefCell::new(None));
51
52 let listener = Rc::new(RefCell::new(Rc::new(|_| {}) as Rc<dyn Fn(web_sys::Event)>));
53
54 let cleanup = {
55 let remove_listener = Rc::clone(&remove_listener);
56
57 move || {
58 if let Some(remove_listener) = remove_listener.take().as_ref() {
59 remove_listener();
60 }
61 }
62 };
63
64 let update = {
65 let cleanup = cleanup.clone();
66 let listener = Rc::clone(&listener);
67
68 Rc::new(move || {
69 cleanup();
70
71 let mut media_query = media_query.borrow_mut();
72 *media_query = window().match_media(&query.get()).unwrap_or(None);
73
74 if let Some(media_query) = media_query.as_ref() {
75 set_matches.set(media_query.matches());
76
77 let listener = Rc::clone(&*listener.borrow());
78
79 remove_listener.replace(Some(Box::new(use_event_listener(
80 media_query.clone(),
81 change,
82 move |e| listener(e),
83 ))));
84 } else {
85 set_matches.set(false);
86 }
87 })
88 };
89
90 {
91 let update = Rc::clone(&update);
92 listener.replace(Rc::new(move |_| update()) as Rc<dyn Fn(web_sys::Event)>);
93 }
94
95 Effect::new(move |_| update());
96
97 on_cleanup({
98 let cleanup = send_wrapper::SendWrapper::new(cleanup);
99 #[allow(clippy::redundant_closure)]
100 move || cleanup()
101 });
102 }}
103
104 matches.into()
105}
106
107type RemoveListener = Rc<RefCell<Option<Box<dyn Fn()>>>>;