leptos_use/core/
element_maybe_signal.rs1use leptos::prelude::*;
2use leptos::reactive::wrappers::read::Signal;
3use std::ops::Deref;
4
5#[cfg_attr(not(debug_assertions), repr(transparent))]
15pub struct ElementMaybeSignal<T: 'static> {
16 #[cfg(debug_assertions)]
17 defined_at: &'static std::panic::Location<'static>,
18 inner: ElementMaybeSignalType<T>,
19}
20
21impl<T> Clone for ElementMaybeSignal<T> {
22 fn clone(&self) -> Self {
23 *self
24 }
25}
26
27impl<T> Copy for ElementMaybeSignal<T> {}
28
29pub enum ElementMaybeSignalType<T: 'static> {
30 Static(StoredValue<Option<T>, LocalStorage>),
31 Dynamic(Signal<Option<T>, LocalStorage>),
32}
33
34impl<T> Clone for ElementMaybeSignalType<T> {
35 fn clone(&self) -> Self {
36 *self
37 }
38}
39
40impl<T> Copy for ElementMaybeSignalType<T> {}
41
42impl<T: 'static> Default for ElementMaybeSignalType<T> {
43 fn default() -> Self {
44 Self::Static(StoredValue::new_local(None))
45 }
46}
47
48impl<T> Default for ElementMaybeSignal<T> {
49 fn default() -> Self {
50 Self {
51 inner: ElementMaybeSignalType::default(),
52 #[cfg(debug_assertions)]
53 defined_at: std::panic::Location::caller(),
54 }
55 }
56}
57
58impl<T> DefinedAt for ElementMaybeSignal<T> {
59 fn defined_at(&self) -> Option<&'static std::panic::Location<'static>> {
60 #[cfg(debug_assertions)]
61 {
62 Some(self.defined_at)
63 }
64 #[cfg(not(debug_assertions))]
65 {
66 None
67 }
68 }
69}
70
71impl<T> With for ElementMaybeSignal<T> {
72 type Value = Option<T>;
73
74 fn try_with<O>(&self, f: impl FnOnce(&Option<T>) -> O) -> Option<O> {
75 match &self.inner {
76 ElementMaybeSignalType::Static(v) => v.try_with_value(f),
77 ElementMaybeSignalType::Dynamic(s) => s.try_with(f),
78 }
79 }
80}
81
82impl<T> WithUntracked for ElementMaybeSignal<T> {
83 type Value = Option<T>;
84
85 fn try_with_untracked<O>(&self, f: impl FnOnce(&Option<T>) -> O) -> Option<O> {
86 match &self.inner {
87 ElementMaybeSignalType::Static(t) => t.try_with_value(f),
88 ElementMaybeSignalType::Dynamic(s) => s.try_with_untracked(f),
89 }
90 }
91}
92
93pub trait IntoElementMaybeSignal<T, Marker: ?Sized> {
94 fn into_element_maybe_signal(self) -> ElementMaybeSignal<T>;
95}
96
97impl<El, T, Marker: ?Sized> IntoElementMaybeSignal<T, Marker> for El
98where
99 El: IntoElementMaybeSignalType<T, Marker>,
100{
101 fn into_element_maybe_signal(self) -> ElementMaybeSignal<T> {
102 ElementMaybeSignal {
103 inner: self.into_element_maybe_signal_type(),
104 #[cfg(debug_assertions)]
105 defined_at: std::panic::Location::caller(),
106 }
107 }
108}
109
110pub trait IntoElementMaybeSignalType<T, Marker: ?Sized> {
111 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T>;
112}
113
114impl<T, Js> IntoElementMaybeSignalType<T, web_sys::Element> for Js
118where
119 T: From<Js> + Clone,
120{
121 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
122 ElementMaybeSignalType::Static(StoredValue::new_local(Some(T::from(self).clone())))
123 }
124}
125
126impl<T, Js> IntoElementMaybeSignalType<T, Option<web_sys::Element>> for Option<Js>
128where
129 T: From<Js> + Clone,
130{
131 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
132 ElementMaybeSignalType::Static(StoredValue::new_local(self.map(|el| T::from(el).clone())))
133 }
134}
135
136impl<T, E, Js> IntoElementMaybeSignalType<T, Option<Option<web_sys::Element>>> for Js
138where
139 Js: Deref<Target = Option<E>>,
140 E: Clone,
141 T: From<E> + Clone,
142{
143 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
144 ElementMaybeSignalType::Static(StoredValue::new_local(
145 self.as_ref().map(|e| T::from(e.clone())),
146 ))
147 }
148}
149
150impl<T, V> IntoElementMaybeSignalType<T, str> for V
154where
155 V: AsRef<str>,
156 T: From<web_sys::Element> + Clone,
157{
158 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
159 if cfg!(feature = "ssr") {
160 ElementMaybeSignalType::Static(StoredValue::new_local(None))
161 } else {
162 ElementMaybeSignalType::Static(StoredValue::new_local(
163 document()
164 .query_selector(self.as_ref())
165 .unwrap_or_default()
166 .map(|el| T::from(el).clone()),
167 ))
168 }
169 }
170}
171
172pub struct SignalStrMarker;
173
174impl<T, V, I> IntoElementMaybeSignalType<T, SignalStrMarker> for V
176where
177 V: Get<Value = I> + 'static,
178 I: AsRef<str>,
179 T: From<web_sys::Element> + Clone,
180{
181 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
182 if cfg!(feature = "ssr") {
183 ElementMaybeSignalType::Static(StoredValue::new_local(None))
184 } else {
185 ElementMaybeSignalType::Dynamic(Signal::derive_local(move || {
186 document()
187 .query_selector(self.get().as_ref())
188 .unwrap_or_default()
189 .map(|el| T::from(el).clone())
190 }))
191 }
192 }
193}
194
195pub struct SignalMarker;
198
199impl<T, V, E> IntoElementMaybeSignalType<T, SignalMarker> for V
201where
202 V: Get<Value = E> + 'static,
203 T: From<E> + Clone,
204{
205 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
206 ElementMaybeSignalType::Dynamic(Signal::derive_local(move || Some(T::from(self.get()))))
207 }
208}
209
210pub struct OptionSignalMarker;
211
212impl<T, V, E> IntoElementMaybeSignalType<T, OptionSignalMarker> for V
214where
215 V: Get<Value = Option<E>> + 'static,
216 T: From<E> + Clone,
217{
218 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
219 ElementMaybeSignalType::Dynamic(Signal::derive_local(move || self.get().map(T::from)))
220 }
221}