use leptos::ViewFn;
use leptos_dom::{DynChild, HydrationCtx, IntoView};
use leptos_macro::component;
#[allow(unused)]
use leptos_reactive::SharedContext;
#[cfg(any(feature = "csr", feature = "hydrate"))]
use leptos_reactive::SignalGet;
use leptos_reactive::{
create_memo, provide_context, SignalGetUntracked, SuspenseContext,
};
#[cfg(not(any(feature = "csr", feature = "hydrate")))]
use leptos_reactive::{with_owner, Owner};
use std::rc::Rc;
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
tracing::instrument(level = "trace", skip_all)
)]
#[component]
pub fn Suspense<V>(
#[prop(optional, into)]
fallback: ViewFn,
children: Rc<dyn Fn() -> V>,
) -> impl IntoView
where
V: IntoView + 'static,
{
#[cfg(all(
feature = "experimental-islands",
not(any(feature = "csr", feature = "hydrate"))
))]
let no_hydrate = SharedContext::no_hydrate();
let orig_children = children;
let context = SuspenseContext::new();
#[cfg(not(any(feature = "csr", feature = "hydrate")))]
let owner =
Owner::current().expect("<Suspense/> created with no reactive owner");
let current_id = HydrationCtx::next_component();
#[cfg(not(feature = "hydrate"))]
let children = create_memo({
let orig_children = Rc::clone(&orig_children);
move |_| {
provide_context(context);
orig_children().into_view()
}
});
#[cfg(feature = "hydrate")]
let children = create_memo({
let orig_children = Rc::clone(&orig_children);
move |_| {
provide_context(context);
if SharedContext::fragment_has_local_resources(
¤t_id.to_string(),
) {
HydrationCtx::with_hydration_off({
let orig_children = Rc::clone(&orig_children);
move || orig_children().into_view()
})
} else {
orig_children().into_view()
}
}
});
let fallback = create_memo({
move |_| {
provide_context(context);
fallback.run()
}
});
#[cfg(any(feature = "csr", feature = "hydrate"))]
let ready = context.ready();
let child = DynChild::new({
move || {
let children_rendered = children.get_untracked();
#[cfg(any(feature = "csr", feature = "hydrate"))]
{
if ready.get() {
children_rendered
} else {
fallback.get_untracked()
}
}
#[cfg(not(any(feature = "csr", feature = "hydrate")))]
{
use leptos_reactive::signal_prelude::*;
{
if context.none_pending() {
with_owner(owner, move || {
DynChild::new(move || children_rendered.clone())
.into_view()
})
} else if context.has_any_local() {
SharedContext::register_local_fragment(
current_id.to_string(),
);
fallback.get_untracked()
}
else {
HydrationCtx::continue_from(current_id);
let runtime = leptos_reactive::current_runtime();
SharedContext::register_suspense(
context,
¤t_id.to_string(),
{
let orig_children = Rc::clone(&orig_children);
move || {
leptos_reactive::set_current_runtime(
runtime,
);
#[cfg(feature = "experimental-islands")]
let prev_no_hydrate =
SharedContext::no_hydrate();
#[cfg(feature = "experimental-islands")]
{
SharedContext::set_no_hydrate(
no_hydrate,
);
}
let rendered = with_owner(owner, {
move || {
HydrationCtx::continue_from(
current_id,
);
DynChild::new({
move || {
orig_children().into_view()
}
})
.into_view()
.render_to_string()
.to_string()
}
});
#[cfg(feature = "experimental-islands")]
SharedContext::set_no_hydrate(
prev_no_hydrate,
);
#[allow(clippy::let_and_return)]
rendered
}
},
{
let orig_children = Rc::clone(&orig_children);
move || {
leptos_reactive::set_current_runtime(
runtime,
);
#[cfg(feature = "experimental-islands")]
let prev_no_hydrate =
SharedContext::no_hydrate();
#[cfg(feature = "experimental-islands")]
{
SharedContext::set_no_hydrate(
no_hydrate,
);
}
let rendered = with_owner(owner, {
move || {
HydrationCtx::continue_from(
current_id,
);
DynChild::new({
move || {
orig_children().into_view()
}
})
.into_view()
.into_stream_chunks()
}
});
#[cfg(feature = "experimental-islands")]
SharedContext::set_no_hydrate(
prev_no_hydrate,
);
#[allow(clippy::let_and_return)]
rendered
}
},
);
fallback.get_untracked()
}
}
}
}
})
.into_view();
let core_component = match child {
leptos_dom::View::CoreComponent(repr) => repr,
_ => unreachable!(),
};
HydrationCtx::continue_from(current_id);
HydrationCtx::next_component();
leptos_dom::View::Suspense(current_id, core_component)
}