1use crate::core::{SignalStrMarker, StrMarker};
2use leptos::prelude::{guards::ReadGuard, *};
3use send_wrapper::SendWrapper;
4use std::{ops::Deref, rc::Rc, time::Duration};
5use wasm_bindgen::JsCast;
6
7use crate::{
8 UseMutationObserverOptions, UseMutationObserverReturn, use_mutation_observer_with_options,
9};
10
11#[cfg_attr(not(debug_assertions), repr(transparent))]
21pub struct ElementsMaybeSignal<T: 'static> {
22 #[cfg(debug_assertions)]
23 defined_at: &'static std::panic::Location<'static>,
24 inner: ElementsMaybeSignalType<T>,
25}
26
27impl<T> Clone for ElementsMaybeSignal<T> {
28 fn clone(&self) -> Self {
29 *self
30 }
31}
32
33impl<T> Copy for ElementsMaybeSignal<T> {}
34
35pub struct ElementsMaybeSignalType<T: 'static>(Signal<Vec<Option<SendWrapper<T>>>>);
36
37impl<T> Clone for ElementsMaybeSignalType<T> {
38 fn clone(&self) -> Self {
39 *self
40 }
41}
42
43impl<T> Copy for ElementsMaybeSignalType<T> {}
44
45impl<T: 'static> Default for ElementsMaybeSignalType<T> {
46 fn default() -> Self {
47 Self(Signal::stored(vec![]))
48 }
49}
50
51impl<T> Default for ElementsMaybeSignal<T> {
52 fn default() -> Self {
53 Self {
54 inner: ElementsMaybeSignalType::default(),
55 #[cfg(debug_assertions)]
56 defined_at: std::panic::Location::caller(),
57 }
58 }
59}
60
61impl<T> DefinedAt for ElementsMaybeSignal<T> {
62 fn defined_at(&self) -> Option<&'static std::panic::Location<'static>> {
63 #[cfg(debug_assertions)]
64 {
65 Some(self.defined_at)
66 }
67 #[cfg(not(debug_assertions))]
68 {
69 None
70 }
71 }
72}
73
74impl<T> ReadUntracked for ElementsMaybeSignal<T> {
75 type Value = ReadGuard<
76 Vec<Option<SendWrapper<T>>>,
77 SignalReadGuard<Vec<Option<SendWrapper<T>>>, SyncStorage>,
78 >;
79
80 fn try_read_untracked(&self) -> Option<Self::Value> {
81 self.inner.0.try_read_untracked()
82 }
83}
84
85impl<T> Track for ElementsMaybeSignal<T> {
86 fn track(&self) {
87 self.inner.0.track();
88 }
89}
90
91pub trait IntoElementsMaybeSignal<T, Marker> {
92 fn into_elements_maybe_signal(self) -> ElementsMaybeSignal<T>;
93}
94
95impl<El, T, Marker> IntoElementsMaybeSignal<T, Marker> for El
96where
97 El: IntoElementsMaybeSignalType<T, Marker>,
98{
99 fn into_elements_maybe_signal(self) -> ElementsMaybeSignal<T> {
100 ElementsMaybeSignal {
101 inner: self.into_elements_maybe_signal_type(),
102 #[cfg(debug_assertions)]
103 defined_at: std::panic::Location::caller(),
104 }
105 }
106}
107
108pub trait IntoElementsMaybeSignalType<T, Marker> {
109 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T>;
110}
111
112impl<T, Js> IntoElementsMaybeSignalType<T, web_sys::Element> for Js
116where
117 T: From<Js> + Clone,
118{
119 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
120 ElementsMaybeSignalType(Signal::stored(vec![Some(SendWrapper::new(
121 T::from(self).clone(),
122 ))]))
123 }
124}
125
126impl<T, Js> IntoElementsMaybeSignalType<T, Option<web_sys::Element>> for Option<Js>
128where
129 T: From<Js> + Clone,
130{
131 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
132 ElementsMaybeSignalType(Signal::stored(vec![
133 self.map(|el| SendWrapper::new(T::from(el).clone())),
134 ]))
135 }
136}
137
138impl<T, E, Js> IntoElementsMaybeSignalType<T, Option<Option<web_sys::Element>>> for Js
140where
141 Js: Deref<Target = Option<E>>,
142 E: Clone,
143 T: From<E> + Clone,
144{
145 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
146 ElementsMaybeSignalType(Signal::stored(vec![
147 self.as_ref().map(|e| SendWrapper::new(T::from(e.clone()))),
148 ]))
149 }
150}
151
152impl<T, V> IntoElementsMaybeSignalType<T, StrMarker> for V
156where
157 V: AsRef<str>,
158 T: From<web_sys::Element> + Clone,
159{
160 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
161 if cfg!(feature = "ssr") {
162 ElementsMaybeSignalType(Signal::stored(vec![]))
163 } else {
164 ElementsMaybeSignalType(els_signal_by_sel::<T>(self.as_ref()))
165 }
166 }
167}
168
169impl<T, V, I> IntoElementsMaybeSignalType<T, SignalStrMarker> for V
171where
172 V: Get<Value = I> + Send + Sync + 'static,
173 I: AsRef<str>,
174 T: From<web_sys::Element> + Clone,
175{
176 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
177 if cfg!(feature = "ssr") {
178 ElementsMaybeSignalType(Signal::stored(vec![]))
179 } else {
180 ElementsMaybeSignalType(Signal::derive(move || {
181 vec![
182 document()
183 .query_selector(self.get().as_ref())
184 .unwrap_or_default()
185 .map(|el| SendWrapper::new(T::from(el).clone())),
186 ]
187 }))
188 }
189 }
190}
191
192pub struct ElementMarker;
195
196impl<'a, T, Js, C> IntoElementsMaybeSignalType<T, ElementMarker> for C
198where
199 Js: Clone + 'a,
200 T: From<Js>,
201 C: IntoIterator<Item = &'a Js>,
202{
203 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
204 ElementsMaybeSignalType(Signal::stored(
205 self.into_iter()
206 .map(|t| Some(SendWrapper::new(T::from(t.clone()))))
207 .collect(),
208 ))
209 }
210}
211
212impl<'a, T, Js, C> IntoElementsMaybeSignalType<T, &'a [Option<web_sys::Element>]> for C
214where
215 Js: Clone + 'a,
216 T: From<Js>,
217 C: IntoIterator<Item = &'a Option<Js>>,
218{
219 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
220 ElementsMaybeSignalType(Signal::stored(
221 self.into_iter()
222 .map(|t| t.clone().map(|js| SendWrapper::new(T::from(js))))
223 .collect(),
224 ))
225 }
226}
227
228impl<T, Js, C> IntoElementsMaybeSignalType<T, Vec<web_sys::Element>> for C
230where
231 T: From<Js> + Clone,
232 C: IntoIterator<Item = Js>,
233{
234 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
235 ElementsMaybeSignalType(Signal::stored(
236 self.into_iter()
237 .map(|t| Some(SendWrapper::new(T::from(t))))
238 .collect(),
239 ))
240 }
241}
242
243impl<T, Js, C> IntoElementsMaybeSignalType<T, Vec<Option<web_sys::Element>>> for C
245where
246 T: From<Js> + Clone,
247 C: IntoIterator<Item = Option<Js>>,
248{
249 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
250 ElementsMaybeSignalType(Signal::stored(
251 self.into_iter()
252 .map(|t| t.map(|js| SendWrapper::new(T::from(js))))
253 .collect(),
254 ))
255 }
256}
257
258pub struct StrIterMarker;
261
262pub fn els_by_sel<T>(sel: &str) -> Vec<Option<SendWrapper<T>>>
263where
264 T: From<web_sys::Element> + Clone,
265{
266 let mut els: Vec<web_sys::Element> = Vec::new();
267
268 if let Ok(queried_els) = document().query_selector_all(sel.as_ref()) {
269 for i in 0..queried_els.length() {
270 if let Ok(el) = queried_els.get(i).expect("checked length").dyn_into() {
271 els.push(el);
272 }
273 }
274 }
275 els.into_iter()
276 .map(|v| Some(SendWrapper::new(T::from(v))))
277 .collect()
278}
279
280pub fn els_signal_by_sel<T>(sel: &str) -> Signal<Vec<Option<SendWrapper<T>>>>
281where
282 T: From<web_sys::Element> + Clone + 'static,
283{
284 let (el_signal, set_el_signal) = signal(Vec::new());
285
286 let sel = sel.to_string();
287
288 set_timeout(
289 move || {
290 let els = els_by_sel::<T>(&sel);
291 if !els.is_empty() {
292 set_el_signal.set(els);
293 } else {
294 let stop_observer = StoredValue::new_local(Rc::new(|| {}) as Rc<dyn Fn()>);
295
296 let UseMutationObserverReturn { stop, .. } = use_mutation_observer_with_options(
297 document().body().unwrap(),
298 move |_, _| {
299 let els = els_by_sel(&sel);
300 if !els.is_empty() {
301 set_el_signal.set(els);
302 stop_observer.get_value()();
303 } else {
304 set_el_signal.set(Vec::new());
305 }
306 },
307 UseMutationObserverOptions::default()
308 .child_list(true)
309 .subtree(true),
310 );
311
312 stop_observer.set_value(Rc::new(stop));
313 }
314 },
315 Duration::ZERO,
316 );
317
318 el_signal.into()
319}
320
321impl<T, V, C> IntoElementsMaybeSignalType<T, StrIterMarker> for C
323where
324 V: AsRef<str>,
325 T: From<web_sys::Element> + Clone,
326 C: IntoIterator<Item = V>,
327{
328 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
329 if cfg!(feature = "ssr") {
330 ElementsMaybeSignalType(Signal::stored(vec![]))
331 } else {
332 ElementsMaybeSignalType(els_signal_by_sel::<T>(
333 &self
334 .into_iter()
335 .map(|sel| sel.as_ref().to_string())
336 .collect::<Vec<_>>()
337 .join(","),
338 ))
339 }
340 }
341}
342
343pub struct SignalVecMarker;
346
347impl<T, Js, C, G> IntoElementsMaybeSignalType<T, SignalVecMarker> for G
349where
350 T: From<Js> + Clone,
351 G: Get<Value = C> + Send + Sync + 'static,
352 C: IntoIterator<Item = Js>,
353{
354 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
355 ElementsMaybeSignalType(Signal::derive(move || {
356 self.get()
357 .into_iter()
358 .map(|t| Some(SendWrapper::new(T::from(t))))
359 .collect()
360 }))
361 }
362}
363
364pub struct SignalVecSendWrapperMarker;
365
366impl<T, Js, C, G> IntoElementsMaybeSignalType<T, SignalVecSendWrapperMarker> for G
368where
369 T: From<Js> + Clone,
370 G: Get<Value = C> + Send + Sync + 'static,
371 C: IntoIterator<Item = SendWrapper<Js>>,
372{
373 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
374 ElementsMaybeSignalType(Signal::derive(move || {
375 self.get()
376 .into_iter()
377 .map(|t| Some(SendWrapper::new(T::from(t.take()))))
378 .collect()
379 }))
380 }
381}
382
383pub struct SignalVecOptionMarker;
384
385impl<T, Js, C, G> IntoElementsMaybeSignalType<T, SignalVecOptionMarker> for G
387where
388 T: From<Js> + Clone,
389 G: Get<Value = C> + Send + Sync + 'static,
390 C: IntoIterator<Item = Option<Js>>,
391{
392 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
393 ElementsMaybeSignalType(Signal::derive(move || {
394 self.get()
395 .into_iter()
396 .map(|t| t.map(|js| SendWrapper::new(T::from(js))))
397 .collect()
398 }))
399 }
400}
401
402pub struct VecSignalMarker;
405
406impl<T, Js, C, G> IntoElementsMaybeSignalType<T, VecSignalMarker> for C
408where
409 T: From<Js> + Clone,
410 C: IntoIterator<Item = G> + Clone + Send + Sync + 'static,
411 G: Get<Value = Js>,
412{
413 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
414 let signals = self.clone();
415
416 ElementsMaybeSignalType(Signal::derive(move || {
417 signals
418 .clone()
419 .into_iter()
420 .map(|t| Some(SendWrapper::new(T::from(t.get()))))
421 .collect()
422 }))
423 }
424}
425
426pub struct VecSignalOptionMarker;
427
428impl<T, Js, C, G> IntoElementsMaybeSignalType<T, VecSignalOptionMarker> for C
430where
431 T: From<Js> + Clone,
432 C: IntoIterator<Item = G> + Clone + Send + Sync + 'static,
433 G: Get<Value = Option<Js>>,
434{
435 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
436 let signals = self.clone();
437
438 ElementsMaybeSignalType(Signal::derive(move || {
439 signals
440 .clone()
441 .into_iter()
442 .map(|t| t.get().map(|js| SendWrapper::new(T::from(js))))
443 .collect()
444 }))
445 }
446}
447
448pub struct VecSignalVecOptionMarker;
450
451impl<T, Js, C, G> IntoElementsMaybeSignalType<T, VecSignalVecOptionMarker> for C
452where
453 T: From<Js> + Clone,
454 C: IntoIterator<Item = G> + Clone + Send + Sync + 'static,
455 G: Get<Value = Vec<Option<Js>>>,
456{
457 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
458 let signals = self.clone();
459
460 ElementsMaybeSignalType(Signal::derive(move || {
461 signals
462 .clone()
463 .into_iter()
464 .flat_map(|t| t.get())
465 .map(|j| j.map(|j| SendWrapper::new(T::from(j))))
466 .collect()
467 }))
468 }
469}