leptos_use/core/
element_maybe_signal.rs1use leptos::prelude::{guards::ReadGuard, *};
2use leptos::reactive::wrappers::read::Signal;
3use send_wrapper::SendWrapper;
4use std::{ops::Deref, rc::Rc, time::Duration};
5
6use crate::{
7 UseMutationObserverOptions, UseMutationObserverReturn, use_mutation_observer_with_options,
8};
9
10#[cfg_attr(not(debug_assertions), repr(transparent))]
60pub struct ElementMaybeSignal<T: 'static> {
61 #[cfg(debug_assertions)]
62 defined_at: &'static std::panic::Location<'static>,
63 inner: ElementMaybeSignalType<T>,
64}
65
66impl<T> Clone for ElementMaybeSignal<T> {
67 fn clone(&self) -> Self {
68 *self
69 }
70}
71
72impl<T> Copy for ElementMaybeSignal<T> {}
73
74pub struct ElementMaybeSignalType<T: 'static>(Signal<Option<SendWrapper<T>>>);
75
76impl<T> Clone for ElementMaybeSignalType<T> {
77 fn clone(&self) -> Self {
78 *self
79 }
80}
81
82impl<T> Copy for ElementMaybeSignalType<T> {}
83
84impl<T: 'static> Default for ElementMaybeSignalType<T> {
85 fn default() -> Self {
86 Self(Signal::stored(None))
87 }
88}
89
90impl<T> Default for ElementMaybeSignal<T> {
91 fn default() -> Self {
92 Self {
93 inner: ElementMaybeSignalType::default(),
94 #[cfg(debug_assertions)]
95 defined_at: std::panic::Location::caller(),
96 }
97 }
98}
99
100impl<T> DefinedAt for ElementMaybeSignal<T> {
101 fn defined_at(&self) -> Option<&'static std::panic::Location<'static>> {
102 #[cfg(debug_assertions)]
103 {
104 Some(self.defined_at)
105 }
106 #[cfg(not(debug_assertions))]
107 {
108 None
109 }
110 }
111}
112
113impl<T> ReadUntracked for ElementMaybeSignal<T> {
114 type Value =
115 ReadGuard<Option<SendWrapper<T>>, SignalReadGuard<Option<SendWrapper<T>>, SyncStorage>>;
116
117 fn try_read_untracked(&self) -> Option<Self::Value> {
118 self.inner.0.try_read_untracked()
119 }
120}
121
122impl<T> Track for ElementMaybeSignal<T> {
123 fn track(&self) {
124 self.inner.0.track();
125 }
126}
127
128pub trait IntoElementMaybeSignal<T, Marker> {
129 fn into_element_maybe_signal(self) -> ElementMaybeSignal<T>;
130}
131
132impl<El, T, Marker> IntoElementMaybeSignal<T, Marker> for El
133where
134 El: IntoElementMaybeSignalType<T, Marker>,
135{
136 fn into_element_maybe_signal(self) -> ElementMaybeSignal<T> {
137 ElementMaybeSignal {
138 inner: self.into_element_maybe_signal_type(),
139 #[cfg(debug_assertions)]
140 defined_at: std::panic::Location::caller(),
141 }
142 }
143}
144
145pub trait IntoElementMaybeSignalType<T, Marker> {
146 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T>;
147}
148
149impl<T, Js> IntoElementMaybeSignalType<T, web_sys::Element> for Js
153where
154 T: From<Js> + Clone,
155{
156 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
157 ElementMaybeSignalType(Signal::stored(Some(SendWrapper::new(
158 T::from(self).clone(),
159 ))))
160 }
161}
162
163impl<T, Js> IntoElementMaybeSignalType<T, Option<web_sys::Element>> for Option<Js>
165where
166 T: From<Js> + Clone,
167{
168 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
169 ElementMaybeSignalType(Signal::stored(
170 self.map(|el| SendWrapper::new(T::from(el).clone())),
171 ))
172 }
173}
174
175impl<T, E, Js> IntoElementMaybeSignalType<T, Option<Option<web_sys::Element>>> for Js
177where
178 Js: Deref<Target = Option<E>>,
179 E: Clone,
180 T: From<E> + Clone,
181{
182 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
183 ElementMaybeSignalType(Signal::stored(
184 self.as_ref().map(|e| SendWrapper::new(T::from(e.clone()))),
185 ))
186 }
187}
188
189pub struct StrMarker;
192
193impl<T, V> IntoElementMaybeSignalType<T, StrMarker> for V
195where
196 V: AsRef<str>,
197 T: From<web_sys::Element> + Clone,
198{
199 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
200 if cfg!(feature = "ssr") {
201 ElementMaybeSignalType(Signal::stored(None))
202 } else {
203 ElementMaybeSignalType(el_signal_by_sel(self.as_ref()))
204 }
205 }
206}
207
208pub fn el_by_sel<T>(sel: &str) -> Option<T>
209where
210 T: From<web_sys::Element> + Clone,
211{
212 document()
213 .query_selector(sel)
214 .unwrap_or_default()
215 .map(|el| T::from(el).clone())
216}
217
218pub fn el_signal_by_sel<T>(sel: &str) -> Signal<Option<SendWrapper<T>>>
219where
220 T: From<web_sys::Element> + Clone + 'static,
221{
222 let (el_signal, set_el_signal) = signal(None);
223
224 let sel = sel.to_string();
225
226 set_timeout(
227 move || {
228 if let Some(el) = el_by_sel(&sel) {
229 set_el_signal.set(Some(SendWrapper::new(el)));
230 } else {
231 let stop_observer = StoredValue::new_local(Rc::new(|| {}) as Rc<dyn Fn()>);
232
233 let UseMutationObserverReturn { stop, .. } = use_mutation_observer_with_options(
234 document().body().unwrap(),
235 move |_, _| {
236 if let Some(el) = el_by_sel(&sel) {
237 set_el_signal.set(Some(SendWrapper::new(el)));
238 stop_observer.get_value()();
239 } else {
240 set_el_signal.set(None)
241 }
242 },
243 UseMutationObserverOptions::default()
244 .child_list(true)
245 .subtree(true),
246 );
247
248 stop_observer.set_value(Rc::new(stop));
249 }
250 },
251 Duration::ZERO,
252 );
253
254 el_signal.into()
255}
256
257pub struct SignalStrMarker;
258
259impl<T, V, I> IntoElementMaybeSignalType<T, SignalStrMarker> for V
261where
262 V: Get<Value = I> + Send + Sync + 'static,
263 I: AsRef<str>,
264 T: From<web_sys::Element> + Clone,
265{
266 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
267 if cfg!(feature = "ssr") {
268 ElementMaybeSignalType(Signal::stored(None))
269 } else {
270 ElementMaybeSignalType(Signal::derive(move || {
271 document()
272 .query_selector(self.get().as_ref())
273 .unwrap_or_default()
274 .map(|el| SendWrapper::new(T::from(el).clone()))
275 }))
276 }
277 }
278}
279
280pub struct SignalMarker;
283
284pub struct SendWrapperSignalMarker;
285
286impl<T, V, E> IntoElementMaybeSignalType<T, SendWrapperSignalMarker> for V
288where
289 E: Clone,
290 V: Get<Value = SendWrapper<E>> + Send + Sync + 'static,
291 T: From<E> + Clone,
292{
293 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
294 if cfg!(feature = "ssr") {
295 ElementMaybeSignalType(Signal::stored(None))
296 } else {
297 ElementMaybeSignalType(Signal::derive(move || {
298 Some(SendWrapper::new(T::from((self.get().take()).clone())))
299 }))
300 }
301 }
302}
303
304pub struct OptionSignalMarker;
305
306impl<T, V, E> IntoElementMaybeSignalType<T, OptionSignalMarker> for V
308where
309 V: Get<Value = Option<E>> + Send + Sync + 'static,
310 T: From<E> + Clone,
311{
312 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
313 ElementMaybeSignalType(Signal::derive(move || {
314 self.get().map(|v| SendWrapper::new(T::from(v)))
315 }))
316 }
317}
318
319pub struct OptionSendWrapperSignalMarker;
320
321impl<T, V, E> IntoElementMaybeSignalType<T, OptionSendWrapperSignalMarker> for V
323where
324 V: Get<Value = Option<SendWrapper<E>>> + Send + Sync + 'static,
325 T: From<E> + Clone,
326{
327 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
328 ElementMaybeSignalType(Signal::derive(move || {
329 self.get().map(|v| SendWrapper::new(T::from(v.take())))
330 }))
331 }
332}