use cfg_if::cfg_if;
use leptos_dom::{DynChild, Fragment, HydrationCtx, IntoView};
use leptos_macro::component;
use leptos_reactive::{provide_context, Scope, SuspenseContext};
use std::rc::Rc;
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
tracing::instrument(level = "info", skip_all)
)]
#[component(transparent)]
pub fn Suspense<F, E>(
cx: Scope,
fallback: F,
children: Box<dyn Fn(Scope) -> Fragment>,
) -> impl IntoView
where
F: Fn() -> E + 'static,
E: IntoView,
{
let context = SuspenseContext::new(cx);
provide_context(cx, context);
let orig_child = Rc::new(children);
let before_me = HydrationCtx::peek();
let current_id = HydrationCtx::next_component();
let child = DynChild::new({
#[cfg(not(any(feature = "csr", feature = "hydrate")))]
let current_id = current_id.clone();
move || {
cfg_if! {
if #[cfg(any(feature = "csr", feature = "hydrate"))] {
if context.ready() {
Fragment::lazy(Box::new(|| vec![orig_child(cx).into_view(cx)])).into_view(cx)
} else {
Fragment::lazy(Box::new(|| vec![fallback().into_view(cx)])).into_view(cx)
}
} else {
use leptos_reactive::signal_prelude::*;
let child = orig_child(cx).into_view(cx);
let after_original_child = HydrationCtx::id();
let initial = {
if context.pending_resources.get() == 0 {
child
}
else {
let orig_child = Rc::clone(&orig_child);
cx.register_suspense(
context,
¤t_id.to_string(),
{
let current_id = current_id.clone();
let orig_child = Rc::clone(&orig_child);
move || {
HydrationCtx::continue_from(current_id.clone());
Fragment::lazy(Box::new(move || {
vec![DynChild::new(move || orig_child(cx)).into_view(cx)]
}))
.into_view(cx)
.render_to_string(cx)
.to_string()
}
},
{
let current_id = current_id.clone();
move || {
HydrationCtx::continue_from(current_id.clone());
Fragment::lazy(Box::new(move || {
vec![DynChild::new(move || orig_child(cx)).into_view(cx)]
}))
.into_view(cx)
.into_stream_chunks(cx)
}
},
);
fallback().into_view(cx)
}
};
HydrationCtx::continue_from(after_original_child);
initial
}
}
}
})
.into_view(cx);
let core_component = match child {
leptos_dom::View::CoreComponent(repr) => repr,
_ => unreachable!(),
};
HydrationCtx::continue_from(before_me);
leptos_dom::View::Suspense(current_id, core_component)
}