leptos_use/core/
element_maybe_signal.rs1use leptos::prelude::*;
2use leptos::reactive::wrappers::read::Signal;
3use send_wrapper::SendWrapper;
4use std::ops::Deref;
5
6#[cfg_attr(not(debug_assertions), repr(transparent))]
54pub struct ElementMaybeSignal<T: 'static> {
55 #[cfg(debug_assertions)]
56 defined_at: &'static std::panic::Location<'static>,
57 inner: ElementMaybeSignalType<T>,
58}
59
60impl<T> Clone for ElementMaybeSignal<T> {
61 fn clone(&self) -> Self {
62 *self
63 }
64}
65
66impl<T> Copy for ElementMaybeSignal<T> {}
67
68pub enum ElementMaybeSignalType<T: 'static> {
69 Static(StoredValue<Option<T>, LocalStorage>),
70 Dynamic(Signal<Option<T>, LocalStorage>),
71}
72
73impl<T> Clone for ElementMaybeSignalType<T> {
74 fn clone(&self) -> Self {
75 *self
76 }
77}
78
79impl<T> Copy for ElementMaybeSignalType<T> {}
80
81impl<T: 'static> Default for ElementMaybeSignalType<T> {
82 fn default() -> Self {
83 Self::Static(StoredValue::new_local(None))
84 }
85}
86
87impl<T> Default for ElementMaybeSignal<T> {
88 fn default() -> Self {
89 Self {
90 inner: ElementMaybeSignalType::default(),
91 #[cfg(debug_assertions)]
92 defined_at: std::panic::Location::caller(),
93 }
94 }
95}
96
97impl<T> DefinedAt for ElementMaybeSignal<T> {
98 fn defined_at(&self) -> Option<&'static std::panic::Location<'static>> {
99 #[cfg(debug_assertions)]
100 {
101 Some(self.defined_at)
102 }
103 #[cfg(not(debug_assertions))]
104 {
105 None
106 }
107 }
108}
109
110impl<T> With for ElementMaybeSignal<T> {
111 type Value = Option<T>;
112
113 fn try_with<O>(&self, f: impl FnOnce(&Option<T>) -> O) -> Option<O> {
114 match &self.inner {
115 ElementMaybeSignalType::Static(v) => v.try_with_value(f),
116 ElementMaybeSignalType::Dynamic(s) => s.try_with(f),
117 }
118 }
119}
120
121impl<T> WithUntracked for ElementMaybeSignal<T> {
122 type Value = Option<T>;
123
124 fn try_with_untracked<O>(&self, f: impl FnOnce(&Option<T>) -> O) -> Option<O> {
125 match &self.inner {
126 ElementMaybeSignalType::Static(t) => t.try_with_value(f),
127 ElementMaybeSignalType::Dynamic(s) => s.try_with_untracked(f),
128 }
129 }
130}
131
132pub trait IntoElementMaybeSignal<T, Marker: ?Sized> {
133 fn into_element_maybe_signal(self) -> ElementMaybeSignal<T>;
134}
135
136impl<El, T, Marker: ?Sized> IntoElementMaybeSignal<T, Marker> for El
137where
138 El: IntoElementMaybeSignalType<T, Marker>,
139{
140 fn into_element_maybe_signal(self) -> ElementMaybeSignal<T> {
141 ElementMaybeSignal {
142 inner: self.into_element_maybe_signal_type(),
143 #[cfg(debug_assertions)]
144 defined_at: std::panic::Location::caller(),
145 }
146 }
147}
148
149pub trait IntoElementMaybeSignalType<T, Marker: ?Sized> {
150 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T>;
151}
152
153impl<T, Js> IntoElementMaybeSignalType<T, web_sys::Element> for Js
157where
158 T: From<Js> + Clone,
159{
160 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
161 ElementMaybeSignalType::Static(StoredValue::new_local(Some(T::from(self).clone())))
162 }
163}
164
165impl<T, Js> IntoElementMaybeSignalType<T, Option<web_sys::Element>> for Option<Js>
167where
168 T: From<Js> + Clone,
169{
170 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
171 ElementMaybeSignalType::Static(StoredValue::new_local(self.map(|el| T::from(el).clone())))
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::Static(StoredValue::new_local(
184 self.as_ref().map(|e| T::from(e.clone())),
185 ))
186 }
187}
188
189impl<T, V> IntoElementMaybeSignalType<T, str> for V
193where
194 V: AsRef<str>,
195 T: From<web_sys::Element> + Clone,
196{
197 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
198 if cfg!(feature = "ssr") {
199 ElementMaybeSignalType::Static(StoredValue::new_local(None))
200 } else {
201 ElementMaybeSignalType::Static(StoredValue::new_local(
202 document()
203 .query_selector(self.as_ref())
204 .unwrap_or_default()
205 .map(|el| T::from(el).clone()),
206 ))
207 }
208 }
209}
210
211pub struct SignalStrMarker;
212
213impl<T, V, I> IntoElementMaybeSignalType<T, SignalStrMarker> for V
215where
216 V: Get<Value = I> + 'static,
217 I: AsRef<str>,
218 T: From<web_sys::Element> + Clone,
219{
220 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
221 if cfg!(feature = "ssr") {
222 ElementMaybeSignalType::Static(StoredValue::new_local(None))
223 } else {
224 ElementMaybeSignalType::Dynamic(Signal::derive_local(move || {
225 document()
226 .query_selector(self.get().as_ref())
227 .unwrap_or_default()
228 .map(|el| T::from(el).clone())
229 }))
230 }
231 }
232}
233
234pub struct SignalMarker;
237
238impl<T, V, E> IntoElementMaybeSignalType<T, SignalMarker> for V
240where
241 V: Get<Value = E> + 'static,
242 T: From<E> + Clone,
243{
244 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
245 ElementMaybeSignalType::Dynamic(Signal::derive_local(move || Some(T::from(self.get()))))
246 }
247}
248
249pub struct SendWrapperSignalMarker;
250
251impl<T, V, E> IntoElementMaybeSignalType<T, SendWrapperSignalMarker> for V
253where
254 E: Clone,
255 V: Get<Value = SendWrapper<E>> + 'static,
256 T: From<E> + Clone,
257{
258 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
259 ElementMaybeSignalType::Dynamic(Signal::derive_local(move || {
260 Some(T::from((*self.get()).clone()))
261 }))
262 }
263}
264
265pub struct OptionSignalMarker;
266
267impl<T, V, E> IntoElementMaybeSignalType<T, OptionSignalMarker> for V
269where
270 V: Get<Value = Option<E>> + 'static,
271 T: From<E> + Clone,
272{
273 fn into_element_maybe_signal_type(self) -> ElementMaybeSignalType<T> {
274 ElementMaybeSignalType::Dynamic(Signal::derive_local(move || self.get().map(T::from)))
275 }
276}