use crate::{children::ViewFn, IntoView};
use leptos_macro::component;
#[cfg(not(all(feature = "nightly", rustc_nightly)))]
use reactive_graph::traits::Get;
use std::{marker::PhantomData, sync::Arc};
use tachys::either::Either;
#[component(transparent)]
pub fn ShowLet<T, ChFn, V, M>(
children: ChFn,
some: impl IntoOptionGetter<T, M>,
#[prop(optional, into)]
fallback: ViewFn,
#[prop(optional)]
_marker: PhantomData<(T, M)>,
) -> impl IntoView
where
ChFn: Fn(T) -> V + Send + Clone + 'static,
V: IntoView + 'static,
T: 'static,
{
let getter = some.into_option_getter();
move || {
let children = children.clone();
let fallback = fallback.clone();
getter
.run()
.map(move |t| Either::Left(children(t)))
.unwrap_or_else(move || Either::Right(fallback.run()))
}
}
pub struct OptionGetter<T>(Arc<dyn Fn() -> Option<T> + Send + Sync + 'static>);
impl<T> Clone for OptionGetter<T> {
fn clone(&self) -> Self {
Self(Arc::clone(&self.0))
}
}
impl<T> OptionGetter<T> {
pub fn run(&self) -> Option<T> {
(self.0)()
}
}
pub trait IntoOptionGetter<T, M> {
fn into_option_getter(self) -> OptionGetter<T>;
}
pub struct FunctionMarker;
impl<T, F> IntoOptionGetter<T, FunctionMarker> for F
where
F: Fn() -> Option<T> + Send + Sync + 'static,
{
fn into_option_getter(self) -> OptionGetter<T> {
OptionGetter(Arc::new(self))
}
}
pub struct SignalMarker;
#[cfg(not(all(feature = "nightly", rustc_nightly)))]
impl<T, S> IntoOptionGetter<T, SignalMarker> for S
where
S: Get<Value = Option<T>> + Clone + Send + Sync + 'static,
{
fn into_option_getter(self) -> OptionGetter<T> {
let cloned = self.clone();
OptionGetter(Arc::new(move || cloned.get()))
}
}
pub struct StaticMarker;
impl<T> IntoOptionGetter<T, StaticMarker> for Option<T>
where
T: Clone + Send + Sync + 'static,
{
fn into_option_getter(self) -> OptionGetter<T> {
OptionGetter(Arc::new(move || self.clone()))
}
}