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 if cfg!(feature = "ssr") {
375 ElementsMaybeSignalType(Signal::stored(vec![]))
376 } else {
377 ElementsMaybeSignalType(Signal::derive(move || {
378 self.get()
379 .into_iter()
380 .map(|t| Some(SendWrapper::new(T::from(t.take()))))
381 .collect()
382 }))
383 }
384 }
385}
386
387pub struct SignalVecOptionMarker;
388
389impl<T, Js, C, G> IntoElementsMaybeSignalType<T, SignalVecOptionMarker> for G
391where
392 T: From<Js> + Clone,
393 G: Get<Value = C> + Send + Sync + 'static,
394 C: IntoIterator<Item = Option<Js>>,
395{
396 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
397 ElementsMaybeSignalType(Signal::derive(move || {
398 self.get()
399 .into_iter()
400 .map(|t| t.map(|js| SendWrapper::new(T::from(js))))
401 .collect()
402 }))
403 }
404}
405
406pub struct VecSignalMarker;
409
410impl<T, Js, C, G> IntoElementsMaybeSignalType<T, VecSignalMarker> for C
412where
413 T: From<Js> + Clone,
414 C: IntoIterator<Item = G> + Clone + Send + Sync + 'static,
415 G: Get<Value = Js>,
416{
417 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
418 let signals = self.clone();
419
420 ElementsMaybeSignalType(Signal::derive(move || {
421 signals
422 .clone()
423 .into_iter()
424 .map(|t| Some(SendWrapper::new(T::from(t.get()))))
425 .collect()
426 }))
427 }
428}
429
430pub struct VecSignalOptionMarker;
431
432impl<T, Js, C, G> IntoElementsMaybeSignalType<T, VecSignalOptionMarker> for C
434where
435 T: From<Js> + Clone,
436 C: IntoIterator<Item = G> + Clone + Send + Sync + 'static,
437 G: Get<Value = Option<Js>>,
438{
439 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
440 let signals = self.clone();
441
442 ElementsMaybeSignalType(Signal::derive(move || {
443 signals
444 .clone()
445 .into_iter()
446 .map(|t| t.get().map(|js| SendWrapper::new(T::from(js))))
447 .collect()
448 }))
449 }
450}
451
452pub struct VecSignalVecOptionMarker;
454
455impl<T, Js, C, G> IntoElementsMaybeSignalType<T, VecSignalVecOptionMarker> for C
456where
457 T: From<Js> + Clone,
458 C: IntoIterator<Item = G> + Clone + Send + Sync + 'static,
459 G: Get<Value = Vec<Option<Js>>>,
460{
461 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
462 let signals = self.clone();
463
464 ElementsMaybeSignalType(Signal::derive(move || {
465 signals
466 .clone()
467 .into_iter()
468 .flat_map(|t| t.get())
469 .map(|j| j.map(|j| SendWrapper::new(T::from(j))))
470 .collect()
471 }))
472 }
473}