use silex_core::reactivity::SuspenseContext;
use silex_core::reactivity::{Effect, create_scope, provide_context};
use silex_dom::view::View;
use silex_html::div;
use web_sys::Node;
#[derive(Clone)]
pub struct Suspense<V, F> {
children: V,
fallback: F,
}
pub fn suspense() -> Suspense<(), ()> {
Suspense {
children: (),
fallback: (),
}
}
impl<V, F> Suspense<V, F> {
pub fn children<NewV>(self, children: NewV) -> Suspense<NewV, F> {
Suspense {
children,
fallback: self.fallback,
}
}
pub fn fallback<NewF>(self, fallback: NewF) -> Suspense<V, NewF> {
Suspense {
children: self.children,
fallback,
}
}
}
impl<V, F, VRes, FRes> View for Suspense<V, F>
where
V: Fn() -> VRes + 'static,
VRes: View + 'static,
F: Fn() -> FRes + 'static,
FRes: View + 'static,
{
fn mount(self, parent: &Node) {
let children_fn = self.children;
let fallback_fn = self.fallback;
let parent_clone = parent.clone();
create_scope(move || {
let ctx = SuspenseContext::new();
provide_context(ctx);
let count = ctx.count;
let content_wrapper = div(()).class("suspense-content");
let _ = content_wrapper.clone().style(move || {
if count.get() > 0 {
"display: none"
} else {
"display: block"
}
});
content_wrapper.clone().mount(&parent_clone);
let content_root = content_wrapper.element;
Effect::new(move |_| {
let view = children_fn();
content_root.set_inner_html("");
view.mount(&content_root);
});
let fallback_wrapper = div(()).class("suspense-fallback");
let _ = fallback_wrapper.clone().style(move || {
if count.get() > 0 {
"display: block"
} else {
"display: none"
}
});
fallback_wrapper.clone().mount(&parent_clone);
let fallback_root = fallback_wrapper.element;
Effect::new(move |_| {
let view = fallback_fn();
fallback_root.set_inner_html("");
view.mount(&fallback_root);
});
});
}
}