feat: Lazy mount (#161)

* feat: Drawer lazy mount

* feat: Binder lazy mount
This commit is contained in:
luoxiaozero 2024-04-09 21:46:22 +08:00 committed by GitHub
parent f1c3882b72
commit 1af5b2573a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 64 additions and 41 deletions

View file

@ -204,6 +204,7 @@ pub fn AutoComplete(
<CSSTransition <CSSTransition
node_ref=menu_ref node_ref=menu_ref
name="fade-in-scale-up-transition" name="fade-in-scale-up-transition"
appear=is_show_menu.get_untracked()
show=is_show_menu show=is_show_menu
let:display let:display
> >

View file

@ -152,6 +152,7 @@ pub fn ColorPicker(
<CSSTransition <CSSTransition
node_ref=popover_ref node_ref=popover_ref
name="fade-in-scale-up-transition" name="fade-in-scale-up-transition"
appear=is_show_popover.get_untracked()
show=is_show_popover show=is_show_popover
let:display let:display
> >

View file

@ -93,6 +93,7 @@ pub fn Panel(
<CSSTransition <CSSTransition
node_ref=panel_ref node_ref=panel_ref
name="fade-in-scale-up-transition" name="fade-in-scale-up-transition"
appear=is_show_panel.get_untracked()
show=is_show_panel show=is_show_panel
let:display let:display
> >

View file

@ -87,6 +87,7 @@ pub fn Drawer(
<div class="thaw-drawer-container" style=move || style.get()> <div class="thaw-drawer-container" style=move || style.get()>
<CSSTransition <CSSTransition
node_ref=mask_ref node_ref=mask_ref
appear=show.get_untracked()
show=show.signal() show=show.signal()
name="fade-in-transition" name="fade-in-transition"
let:display let:display
@ -100,6 +101,7 @@ pub fn Drawer(
</CSSTransition> </CSSTransition>
<CSSTransition <CSSTransition
node_ref=drawer_ref node_ref=drawer_ref
appear=show.get_untracked()
show=show.signal() show=show.signal()
name=Memo::new(move |_| { name=Memo::new(move |_| {
format!("slide-in-from-{}-transition", placement.get()) format!("slide-in-from-{}-transition", placement.get())
@ -137,7 +139,7 @@ pub fn Drawer(
view! { <DrawerInnr show mask_closeable close_on_esc title placement class style children/> } view! { <DrawerInnr show mask_closeable close_on_esc title placement class style children/> }
} }
DrawerMount::Body => view! { DrawerMount::Body => view! {
<Teleport> <Teleport immediate=show.signal()>
<DrawerInnr show mask_closeable close_on_esc title placement class style children/> <DrawerInnr show mask_closeable close_on_esc title placement class style children/>
</Teleport> </Teleport>
}, },

View file

@ -64,7 +64,7 @@ pub fn Modal(
}); });
view! { view! {
<Teleport> <Teleport immediate=show.signal()>
<FocusTrap disabled=!close_on_esc active=show.signal() on_esc> <FocusTrap disabled=!close_on_esc active=show.signal() on_esc>
<div <div
class="thaw-modal-container" class="thaw-modal-container"
@ -78,6 +78,7 @@ pub fn Modal(
> >
<CSSTransition <CSSTransition
node_ref=mask_ref node_ref=mask_ref
appear=show.get_untracked()
show=show.signal() show=show.signal()
name="fade-in-transition" name="fade-in-transition"
let:display let:display
@ -91,6 +92,7 @@ pub fn Modal(
</CSSTransition> </CSSTransition>
<CSSTransition <CSSTransition
node_ref=modal_ref node_ref=modal_ref
appear=show.get_untracked()
show=show.signal() show=show.signal()
name="fade-in-scale-up-transition" name="fade-in-scale-up-transition"
on_enter on_enter

View file

@ -110,7 +110,6 @@ pub fn Popover(
children: trigger_children, children: trigger_children,
} = popover_trigger; } = popover_trigger;
let follower_enabled = RwSignal::new(false);
view! { view! {
<Binder target_ref> <Binder target_ref>
<div <div
@ -121,13 +120,12 @@ pub fn Popover(
> >
{trigger_children()} {trigger_children()}
</div> </div>
<Follower slot show=follower_enabled placement> <Follower slot show=is_show_popover placement>
<CSSTransition <CSSTransition
node_ref=popover_ref node_ref=popover_ref
name="popover-transition" name="popover-transition"
appear=is_show_popover.get_untracked()
show=is_show_popover show=is_show_popover
on_enter=move |_| follower_enabled.set(true)
on_after_leave=move |_| follower_enabled.set(false)
let:display let:display
> >
<div <div

View file

@ -337,6 +337,6 @@ pub struct ScrollbarRef {
impl ScrollbarRef { impl ScrollbarRef {
pub fn container_scroll_top(&self) -> i32 { pub fn container_scroll_top(&self) -> i32 {
self.container_scroll_top.get() self.container_scroll_top.get_untracked()
} }
} }

View file

@ -127,6 +127,7 @@ where
<CSSTransition <CSSTransition
node_ref=menu_ref node_ref=menu_ref
name="fade-in-scale-up-transition" name="fade-in-scale-up-transition"
appear=is_show_menu.get_untracked()
show=is_show_menu show=is_show_menu
let:display let:display
> >

View file

@ -178,6 +178,7 @@ fn Panel(
<CSSTransition <CSSTransition
node_ref=panel_ref node_ref=panel_ref
name="fade-in-scale-up-transition" name="fade-in-scale-up-transition"
appear=is_show_panel.get_untracked()
show=is_show_panel show=is_show_panel
let:display let:display
> >

View file

@ -239,7 +239,7 @@ fn FollowerContainer<El: ElementDescriptor + Clone + 'static>(
) )
}); });
view! { <Teleport element=children/> } view! { <Teleport element=children immediate=show/> }
} }
fn get_scroll_parent(element: Option<HtmlElement<AnyElement>>) -> Option<HtmlElement<AnyElement>> { fn get_scroll_parent(element: Option<HtmlElement<AnyElement>>) -> Option<HtmlElement<AnyElement>> {

View file

@ -4,46 +4,62 @@ use leptos::{html::AnyElement, *};
/// https://github.com/solidjs/solid/blob/main/packages/solid/web/src/index.ts#L56 /// https://github.com/solidjs/solid/blob/main/packages/solid/web/src/index.ts#L56
#[component] #[component]
pub fn Teleport( pub fn Teleport(
#[prop(default = true.into(), into)] immediate: MaybeSignal<bool>,
#[prop(into, optional)] mount: Option<web_sys::Element>, #[prop(into, optional)] mount: Option<web_sys::Element>,
#[prop(optional, into)] element: Option<HtmlElement<AnyElement>>, #[prop(optional, into)] element: Option<HtmlElement<AnyElement>>,
#[prop(optional)] children: Option<Children>, #[prop(optional)] children: Option<Children>,
) -> impl IntoView { ) -> impl IntoView {
cfg_if! { if #[cfg(all(target_arch = "wasm32", any(feature = "csr", feature = "hydrate")))] { cfg_if! { if #[cfg(all(target_arch = "wasm32", any(feature = "csr", feature = "hydrate")))] {
use leptos::wasm_bindgen::JsCast; let mount_fn = StoredValue::new(None::<Box<dyn FnOnce() -> ()>>);
use leptos::leptos_dom::Mountable;
use thaw_utils::with_hydration_off;
let mount = mount.unwrap_or_else(|| { mount_fn.set_value(Some(Box::new(move || {
document() let mount = mount.unwrap_or_else(|| {
.body() use leptos::wasm_bindgen::JsCast;
.expect("body element to exist") document()
.unchecked_into() .body()
.expect("body element to exist")
.unchecked_into()
});
if let Some(element) = element {
let render_root = element;
let _ = mount.append_child(&render_root);
on_cleanup(move || {
let _ = mount.remove_child(&render_root);
});
} else if let Some(children) = children {
let container = document()
.create_element("div")
.expect("element creation to work");
thaw_utils::with_hydration_off(|| {
use leptos::leptos_dom::Mountable;
let _ = container.append_child(&children().into_view().get_mountable_node());
});
let render_root = container;
let _ = mount.append_child(&render_root);
on_cleanup(move || {
let _ = mount.remove_child(&render_root);
});
}
})));
let owner = Owner::current();
Effect::new(move |_| {
if immediate.get() {
mount_fn.update_value(|mount_fn| {
if let Some(f) = mount_fn.take() {
with_owner(owner.unwrap(), move || {
f();
});
}
});
}
}); });
if let Some(element) = element {
let render_root = element;
let _ = mount.append_child(&render_root);
on_cleanup(move || {
let _ = mount.remove_child(&render_root);
});
} else if let Some(children) = children {
let container = document()
.create_element("div")
.expect("element creation to work");
with_hydration_off(|| {
let _ = container.append_child(&children().into_view().get_mountable_node());
});
let render_root = container;
let _ = mount.append_child(&render_root);
on_cleanup(move || {
let _ = mount.remove_child(&render_root);
});
} else {
return;
};
} else { } else {
let _ = mount; let _ = mount;
let _ = immediate;
#[cfg(not(feature = "ssr"))] #[cfg(not(feature = "ssr"))]
{ {
let _ = element; let _ = element;
@ -51,9 +67,9 @@ pub fn Teleport(
} }
#[cfg(feature = "ssr")] #[cfg(feature = "ssr")]
if element.is_none() { if element.is_none() {
if let Some(children) = children { if let Some(children) = children {
// Consumed hydration `id` // Consumed hydration `id`
let _ = children(); let _ = children();
} }
} }
}} }}