use crate::core::{SignalMarker, SignalStrMarker};
use leptos::prelude::*;
use leptos::reactive::wrappers::read::Signal;
use std::ops::Deref;
#[cfg_attr(not(debug_assertions), repr(transparent))]
pub struct ElementsMaybeSignal<T: 'static> {
#[cfg(debug_assertions)]
defined_at: &'static std::panic::Location<'static>,
inner: ElementsMaybeSignalType<T>,
}
impl<T> Clone for ElementsMaybeSignal<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for ElementsMaybeSignal<T> {}
pub enum ElementsMaybeSignalType<T: 'static> {
Static(StoredValue<Vec<Option<T>>, LocalStorage>),
Dynamic(Signal<Vec<Option<T>>, LocalStorage>),
}
impl<T> Clone for ElementsMaybeSignalType<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for ElementsMaybeSignalType<T> {}
impl<T: 'static> Default for ElementsMaybeSignalType<T> {
fn default() -> Self {
Self::Static(StoredValue::new_local(vec![]))
}
}
impl<T> Default for ElementsMaybeSignal<T> {
fn default() -> Self {
Self {
inner: ElementsMaybeSignalType::default(),
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
}
impl<T> DefinedAt for ElementsMaybeSignal<T> {
fn defined_at(&self) -> Option<&'static std::panic::Location<'static>> {
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(debug_assertions))]
{
None
}
}
}
impl<T> With for ElementsMaybeSignal<T> {
type Value = Vec<Option<T>>;
fn try_with<O>(&self, f: impl FnOnce(&Vec<Option<T>>) -> O) -> Option<O> {
match &self.inner {
ElementsMaybeSignalType::Static(v) => v.try_with_value(f),
ElementsMaybeSignalType::Dynamic(s) => s.try_with(f),
}
}
}
impl<T> WithUntracked for ElementsMaybeSignal<T> {
type Value = Vec<Option<T>>;
fn try_with_untracked<O>(&self, f: impl FnOnce(&Vec<Option<T>>) -> O) -> Option<O> {
match self.inner {
ElementsMaybeSignalType::Static(t) => t.try_with_value(f),
ElementsMaybeSignalType::Dynamic(s) => s.try_with_untracked(f),
}
}
}
pub trait IntoElementsMaybeSignal<T, Marker: ?Sized> {
fn into_elements_maybe_signal(self) -> ElementsMaybeSignal<T>;
}
impl<El, T, Marker: ?Sized> IntoElementsMaybeSignal<T, Marker> for El
where
El: IntoElementsMaybeSignalType<T, Marker>,
{
fn into_elements_maybe_signal(self) -> ElementsMaybeSignal<T> {
ElementsMaybeSignal {
inner: self.into_elements_maybe_signal_type(),
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
}
pub trait IntoElementsMaybeSignalType<T, Marker: ?Sized> {
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T>;
}
impl<T, Js> IntoElementsMaybeSignalType<T, web_sys::Element> for Js
where
T: From<Js> + Clone,
{
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
ElementsMaybeSignalType::Static(StoredValue::new_local(vec![Some(T::from(self).clone())]))
}
}
impl<T, Js> IntoElementsMaybeSignalType<T, Option<web_sys::Element>> for Option<Js>
where
T: From<Js> + Clone,
{
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
ElementsMaybeSignalType::Static(StoredValue::new_local(vec![
self.map(|el| T::from(el).clone())
]))
}
}
impl<T, E, Js> IntoElementsMaybeSignalType<T, Option<Option<web_sys::Element>>> for Js
where
Js: Deref<Target = Option<E>>,
E: Clone,
T: From<E> + Clone,
{
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
ElementsMaybeSignalType::Static(StoredValue::new_local(vec![self
.as_ref()
.map(|e| T::from(e.clone()))]))
}
}
impl<T, V> IntoElementsMaybeSignalType<T, str> for V
where
V: AsRef<str>,
T: From<web_sys::Element> + Clone,
{
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
if cfg!(feature = "ssr") {
ElementsMaybeSignalType::Static(StoredValue::new_local(vec![]))
} else {
ElementsMaybeSignalType::Static(StoredValue::new_local(vec![document()
.query_selector(self.as_ref())
.unwrap_or_default()
.map(|el| T::from(el).clone())]))
}
}
}
impl<T, V, I> IntoElementsMaybeSignalType<T, SignalStrMarker> for V
where
V: Get<Value = I> + 'static,
I: AsRef<str>,
T: From<web_sys::Element> + Clone,
{
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
if cfg!(feature = "ssr") {
ElementsMaybeSignalType::Static(StoredValue::new_local(vec![]))
} else {
ElementsMaybeSignalType::Dynamic(Signal::derive_local(move || {
vec![document()
.query_selector(self.get().as_ref())
.unwrap_or_default()
.map(|el| T::from(el).clone())]
}))
}
}
}
impl<T, V, E> IntoElementsMaybeSignalType<T, SignalMarker> for V
where
V: Get<Value = E> + 'static,
T: From<E> + Clone,
{
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
ElementsMaybeSignalType::Dynamic(Signal::derive_local(move || {
vec![Some(T::from(self.get()))]
}))
}
}
impl<'a, T, Js, C> IntoElementsMaybeSignalType<T, &'a [web_sys::Element]> for C
where
Js: Clone + 'a,
T: From<Js>,
C: IntoIterator<Item = &'a Js>,
{
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
ElementsMaybeSignalType::Static(StoredValue::new_local(
self.into_iter().map(|t| Some(T::from(t.clone()))).collect(),
))
}
}
impl<'a, T, Js, C> IntoElementsMaybeSignalType<T, &'a [Option<web_sys::Element>]> for C
where
Js: Clone + 'a,
T: From<Js>,
C: IntoIterator<Item = &'a Option<Js>>,
{
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
ElementsMaybeSignalType::Static(StoredValue::new_local(
self.into_iter().map(|t| t.clone().map(T::from)).collect(),
))
}
}
impl<T, Js, C> IntoElementsMaybeSignalType<T, Vec<web_sys::Element>> for C
where
T: From<Js> + Clone,
C: IntoIterator<Item = Js>,
{
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
ElementsMaybeSignalType::Static(StoredValue::new_local(
self.into_iter().map(|t| Some(T::from(t))).collect(),
))
}
}
impl<T, Js, C> IntoElementsMaybeSignalType<T, Vec<Option<web_sys::Element>>> for C
where
T: From<Js> + Clone,
C: IntoIterator<Item = Option<Js>>,
{
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
ElementsMaybeSignalType::Static(StoredValue::new_local(
self.into_iter().map(|t| t.map(T::from)).collect(),
))
}
}
impl<T, V, C> IntoElementsMaybeSignalType<T, &[&str]> for C
where
V: AsRef<str>,
T: From<web_sys::Element> + Clone,
C: IntoIterator<Item = V>,
{
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
if cfg!(feature = "ssr") {
ElementsMaybeSignalType::Static(StoredValue::new_local(vec![]))
} else {
ElementsMaybeSignalType::Static(StoredValue::new_local(
self.into_iter()
.map(|sel| {
document()
.query_selector(sel.as_ref())
.unwrap_or_default()
.map(|el| T::from(el).clone())
})
.collect(),
))
}
}
}
pub struct SignalVecMarker;
impl<T, Js, C, G> IntoElementsMaybeSignalType<T, SignalVecMarker> for G
where
T: From<Js> + Clone,
G: Get<Value = C> + 'static,
C: IntoIterator<Item = Js>,
{
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
ElementsMaybeSignalType::Dynamic(Signal::derive_local(move || {
self.get().into_iter().map(|t| Some(T::from(t))).collect()
}))
}
}
pub struct SignalVecOptionMarker;
impl<T, Js, C, G> IntoElementsMaybeSignalType<T, SignalVecOptionMarker> for G
where
T: From<Js> + Clone,
G: Get<Value = C> + 'static,
C: IntoIterator<Item = Option<Js>>,
{
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
ElementsMaybeSignalType::Dynamic(Signal::derive_local(move || {
self.get().into_iter().map(|t| t.map(T::from)).collect()
}))
}
}
pub struct VecSignalMarker;
impl<T, Js, C, G> IntoElementsMaybeSignalType<T, VecSignalMarker> for C
where
T: From<Js> + Clone,
C: IntoIterator<Item = G> + Clone + 'static,
G: Get<Value = Js>,
{
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
let signals = self.clone();
ElementsMaybeSignalType::Dynamic(Signal::derive_local(move || {
signals
.clone()
.into_iter()
.map(|t| Some(T::from(t.get())))
.collect()
}))
}
}
pub struct VecSignalOptionMarker;
impl<T, Js, C, G> IntoElementsMaybeSignalType<T, VecSignalOptionMarker> for C
where
T: From<Js> + Clone,
C: IntoIterator<Item = G> + Clone + 'static,
G: Get<Value = Option<Js>>,
{
fn into_elements_maybe_signal_type(self) -> ElementsMaybeSignalType<T> {
let signals = self.clone();
ElementsMaybeSignalType::Dynamic(Signal::derive_local(move || {
signals
.clone()
.into_iter()
.map(|t| t.get().map(T::from))
.collect()
}))
}
}