1use crate::core::{SignalMarker, SignalStrMarker};
2use leptos::prelude::*;
3use leptos::reactive::wrappers::read::Signal;
4use std::ops::Deref;
5
6#[cfg_attr(not(debug_assertions), repr(transparent))]
16pub struct ElementsMaybeSignal<T: 'static> {
17 #[cfg(debug_assertions)]
18 defined_at: &'static std::panic::Location<'static>,
19 inner: ElementsMaybeSignalType<T>,
20}
21
22impl<T> Clone for ElementsMaybeSignal<T> {
23 fn clone(&self) -> Self {
24 *self
25 }
26}
27
28impl<T> Copy for ElementsMaybeSignal<T> {}
29
30pub enum ElementsMaybeSignalType<T: 'static> {
31 Static(StoredValue<Vec<Option<T>>, LocalStorage>),
32 Dynamic(Signal<Vec<Option<T>>, LocalStorage>),
33}
34
35impl<T> Clone for ElementsMaybeSignalType<T> {
36 fn clone(&self) -> Self {
37 *self
38 }
39}
40
41impl<T> Copy for ElementsMaybeSignalType<T> {}
42
43impl<T: 'static> Default for ElementsMaybeSignalType<T> {
44 fn default() -> Self {
45 Self::Static(StoredValue::new_local(vec![]))
46 }
47}
48
49impl<T> Default for ElementsMaybeSignal<T> {
50 fn default() -> Self {
51 Self {
52 inner: ElementsMaybeSignalType::default(),
53 #[cfg(debug_assertions)]
54 defined_at: std::panic::Location::caller(),
55 }
56 }
57}
58
59impl<T> DefinedAt for ElementsMaybeSignal<T> {
60 fn defined_at(&self) -> Option<&'static std::panic::Location<'static>> {
61 #[cfg(debug_assertions)]
62 {
63 Some(self.defined_at)
64 }
65 #[cfg(not(debug_assertions))]
66 {
67 None
68 }
69 }
70}
71
72impl<T> With for ElementsMaybeSignal<T> {
73 type Value = Vec<Option<T>>;
74
75 fn try_with<O>(&self, f: impl FnOnce(&Vec<Option<T>>) -> O) -> Option<O> {
76 match &self.inner {
77 ElementsMaybeSignalType::Static(v) => v.try_with_value(f),
78 ElementsMaybeSignalType::Dynamic(s) => s.try_with(f),
79 }
80 }
81}
82
83impl<T> WithUntracked for ElementsMaybeSignal<T> {
84 type Value = Vec<Option<T>>;
85
86 fn try_with_untracked<O>(&self, f: impl FnOnce(&Vec<Option<T>>) -> O) -> Option<O> {
87 match self.inner {
88 ElementsMaybeSignalType::Static(t) => t.try_with_value(f),
89 ElementsMaybeSignalType::Dynamic(s) => s.try_with_untracked(f),
90 }
91 }
92}
93
94pub trait IntoElementsMaybeSignal<T, Marker: ?Sized> {
95 fn into_elements_maybe_signal(self) -> ElementsMaybeSignal<T>;
96}
97
98impl<El, T, Marker: ?Sized> IntoElementsMaybeSignal<T, Marker> for El
99where
100 El: IntoElementsMaybeSignalType<T, Marker>,
101{
102 fn into_elements_maybe_signal(self) -> ElementsMaybeSignal<T> {
103 ElementsMaybeSignal {
104 inner: self.into_elements_maybe_signal_type(),
105 #[cfg(debug_assertions)]
106 defined_at: std::panic::Location::caller(),
107 }
108 }
109}
110
111pub trait IntoElementsMaybeSignalType<T, Marker: ?Sized> {
112 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T>;
113}
114
115impl<T, Js> IntoElementsMaybeSignalType<T, web_sys::Element> for Js
119where
120 T: From<Js> + Clone,
121{
122 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
123 ElementsMaybeSignalType::Static(StoredValue::new_local(vec![Some(T::from(self).clone())]))
124 }
125}
126
127impl<T, Js> IntoElementsMaybeSignalType<T, Option<web_sys::Element>> for Option<Js>
129where
130 T: From<Js> + Clone,
131{
132 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
133 ElementsMaybeSignalType::Static(StoredValue::new_local(vec![
134 self.map(|el| T::from(el).clone())
135 ]))
136 }
137}
138
139impl<T, E, Js> IntoElementsMaybeSignalType<T, Option<Option<web_sys::Element>>> for Js
141where
142 Js: Deref<Target = Option<E>>,
143 E: Clone,
144 T: From<E> + Clone,
145{
146 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
147 ElementsMaybeSignalType::Static(StoredValue::new_local(vec![self
148 .as_ref()
149 .map(|e| T::from(e.clone()))]))
150 }
151}
152
153impl<T, V> IntoElementsMaybeSignalType<T, str> for V
157where
158 V: AsRef<str>,
159 T: From<web_sys::Element> + Clone,
160{
161 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
162 if cfg!(feature = "ssr") {
163 ElementsMaybeSignalType::Static(StoredValue::new_local(vec![]))
164 } else {
165 ElementsMaybeSignalType::Static(StoredValue::new_local(vec![document()
166 .query_selector(self.as_ref())
167 .unwrap_or_default()
168 .map(|el| T::from(el).clone())]))
169 }
170 }
171}
172
173impl<T, V, I> IntoElementsMaybeSignalType<T, SignalStrMarker> for V
175where
176 V: Get<Value = I> + 'static,
177 I: AsRef<str>,
178 T: From<web_sys::Element> + Clone,
179{
180 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
181 if cfg!(feature = "ssr") {
182 ElementsMaybeSignalType::Static(StoredValue::new_local(vec![]))
183 } else {
184 ElementsMaybeSignalType::Dynamic(Signal::derive_local(move || {
185 vec![document()
186 .query_selector(self.get().as_ref())
187 .unwrap_or_default()
188 .map(|el| T::from(el).clone())]
189 }))
190 }
191 }
192}
193
194impl<T, V, E> IntoElementsMaybeSignalType<T, SignalMarker> for V
198where
199 V: Get<Value = E> + 'static,
200 T: From<E> + Clone,
201{
202 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
203 ElementsMaybeSignalType::Dynamic(Signal::derive_local(move || {
204 vec![Some(T::from(self.get()))]
205 }))
206 }
207}
208
209impl<'a, T, Js, C> IntoElementsMaybeSignalType<T, &'a [web_sys::Element]> for C
213where
214 Js: Clone + 'a,
215 T: From<Js>,
216 C: IntoIterator<Item = &'a Js>,
217{
218 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
219 ElementsMaybeSignalType::Static(StoredValue::new_local(
220 self.into_iter().map(|t| Some(T::from(t.clone()))).collect(),
221 ))
222 }
223}
224
225impl<'a, T, Js, C> IntoElementsMaybeSignalType<T, &'a [Option<web_sys::Element>]> for C
227where
228 Js: Clone + 'a,
229 T: From<Js>,
230 C: IntoIterator<Item = &'a Option<Js>>,
231{
232 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
233 ElementsMaybeSignalType::Static(StoredValue::new_local(
234 self.into_iter().map(|t| t.clone().map(T::from)).collect(),
235 ))
236 }
237}
238
239impl<T, Js, C> IntoElementsMaybeSignalType<T, Vec<web_sys::Element>> for C
241where
242 T: From<Js> + Clone,
243 C: IntoIterator<Item = Js>,
244{
245 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
246 ElementsMaybeSignalType::Static(StoredValue::new_local(
247 self.into_iter().map(|t| Some(T::from(t))).collect(),
248 ))
249 }
250}
251
252impl<T, Js, C> IntoElementsMaybeSignalType<T, Vec<Option<web_sys::Element>>> for C
254where
255 T: From<Js> + Clone,
256 C: IntoIterator<Item = Option<Js>>,
257{
258 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
259 ElementsMaybeSignalType::Static(StoredValue::new_local(
260 self.into_iter().map(|t| t.map(T::from)).collect(),
261 ))
262 }
263}
264
265impl<T, V, C> IntoElementsMaybeSignalType<T, &[&str]> for C
269where
270 V: AsRef<str>,
271 T: From<web_sys::Element> + Clone,
272 C: IntoIterator<Item = V>,
273{
274 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
275 if cfg!(feature = "ssr") {
276 ElementsMaybeSignalType::Static(StoredValue::new_local(vec![]))
277 } else {
278 ElementsMaybeSignalType::Static(StoredValue::new_local(
279 self.into_iter()
280 .map(|sel| {
281 document()
282 .query_selector(sel.as_ref())
283 .unwrap_or_default()
284 .map(|el| T::from(el).clone())
285 })
286 .collect(),
287 ))
288 }
289 }
290}
291
292pub struct SignalVecMarker;
295
296impl<T, Js, C, G> IntoElementsMaybeSignalType<T, SignalVecMarker> for G
298where
299 T: From<Js> + Clone,
300 G: Get<Value = C> + 'static,
301 C: IntoIterator<Item = Js>,
302{
303 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
304 ElementsMaybeSignalType::Dynamic(Signal::derive_local(move || {
305 self.get().into_iter().map(|t| Some(T::from(t))).collect()
306 }))
307 }
308}
309
310pub struct SignalVecOptionMarker;
311
312impl<T, Js, C, G> IntoElementsMaybeSignalType<T, SignalVecOptionMarker> for G
314where
315 T: From<Js> + Clone,
316 G: Get<Value = C> + 'static,
317 C: IntoIterator<Item = Option<Js>>,
318{
319 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
320 ElementsMaybeSignalType::Dynamic(Signal::derive_local(move || {
321 self.get().into_iter().map(|t| t.map(T::from)).collect()
322 }))
323 }
324}
325
326pub struct VecSignalMarker;
329
330impl<T, Js, C, G> IntoElementsMaybeSignalType<T, VecSignalMarker> for C
332where
333 T: From<Js> + Clone,
334 C: IntoIterator<Item = G> + Clone + 'static,
335 G: Get<Value = Js>,
336{
337 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
338 let signals = self.clone();
339
340 ElementsMaybeSignalType::Dynamic(Signal::derive_local(move || {
341 signals
342 .clone()
343 .into_iter()
344 .map(|t| Some(T::from(t.get())))
345 .collect()
346 }))
347 }
348}
349
350pub struct VecSignalOptionMarker;
351
352impl<T, Js, C, G> IntoElementsMaybeSignalType<T, VecSignalOptionMarker> for C
354where
355 T: From<Js> + Clone,
356 C: IntoIterator<Item = G> + Clone + 'static,
357 G: Get<Value = Option<Js>>,
358{
359 fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
360 let signals = self.clone();
361
362 ElementsMaybeSignalType::Dynamic(Signal::derive_local(move || {
363 signals
364 .clone()
365 .into_iter()
366 .map(|t| t.get().map(T::from))
367 .collect()
368 }))
369 }
370}