From 6798cf215f0e2ad448c03fe1164a21d54a4ce285 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Thu, 9 Nov 2023 23:11:30 +0800 Subject: [PATCH] feat: binder --- src/components/binder.rs | 103 +++++++++++++++++++++++++++++++++++++++ src/components/mod.rs | 1 + src/loading_bar/mod.rs | 6 +-- 3 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 src/components/binder.rs diff --git a/src/components/binder.rs b/src/components/binder.rs new file mode 100644 index 0000000..456ac06 --- /dev/null +++ b/src/components/binder.rs @@ -0,0 +1,103 @@ +use crate::teleport::Teleport; +use leptos::{ + html::{AnyElement, ToHtmlElement}, + *, +}; + +#[slot] +pub struct Follower { + show: MaybeSignal, + children: Children, +} + +#[component] +pub fn Binder( + target: NodeRef, + follower: Follower, + children: Children, +) -> impl IntoView { + let scrollable_element_vec = store_value::>>(vec![]); + let ensure_scroll_listener = move || { + let mut cursor = target.get_untracked(); + loop { + cursor = get_scroll_parent(cursor); + if let Some(cursor) = cursor.take() { + scrollable_element_vec.update_value(|vec| vec.push(cursor)); + } else { + break; + } + } + scrollable_element_vec.with_value(|vec| { + vec.iter().for_each(|ele| { + _ = ele.clone().on(ev::scroll, move |_| {}); + }) + }); + }; + + view! { + {children()} + +
+
+ {(follower.children)()} +
+
+
+ } +} + +fn get_scroll_parent(element: Option>) -> Option> { + let Some(element) = element else { + return None; + }; + + fn get_parent_element(element: HtmlElement) -> Option> { + if element.node_type() == 9 { + None + } else { + element.parent_element().map(|ele| ele.to_leptos_element()) + } + } + let Some(parent_element) = get_parent_element(element) else { + return None; + }; + + if parent_element.node_type() == 9 { + return Some(parent_element); + } + + if parent_element.node_type() == 1 { + fn get_overflow( + parent_element: &HtmlElement, + ) -> Option<(String, String, String)> { + let Ok(Some(css_style_declaration)) = window().get_computed_style(parent_element) + else { + return None; + }; + let Ok(overflow) = css_style_declaration.get_property_value("overflow") else { + return None; + }; + let Ok(overflow_x) = css_style_declaration.get_property_value("overflowX") else { + return None; + }; + let Ok(overflow_y) = css_style_declaration.get_property_value("overflowY") else { + return None; + }; + Some((overflow, overflow_x, overflow_y)) + } + if let Some((overflow, overflow_x, overflow_y)) = get_overflow(&parent_element) { + let overflow = format!("{overflow}{overflow_x}{overflow_y}"); + if overflow.contains("auto") { + return Some(parent_element); + } + if overflow.contains("scroll") { + return Some(parent_element); + } + if overflow.contains("overlay") { + return Some(parent_element); + } + } + } + + get_scroll_parent(Some(parent_element)) +} diff --git a/src/components/mod.rs b/src/components/mod.rs index 4f92fcf..e0d6b10 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -1,3 +1,4 @@ +mod binder; mod if_comp; mod option_comp; diff --git a/src/loading_bar/mod.rs b/src/loading_bar/mod.rs index 3db30ec..d205a93 100644 --- a/src/loading_bar/mod.rs +++ b/src/loading_bar/mod.rs @@ -52,7 +52,7 @@ pub(crate) fn LoadingBar(#[prop(optional)] comp_ref: ComponentRef .style("transition", "none") .style("max-width", "0"); _ = loading_bar_ref.offset_width(); - loading_bar_ref + _ = loading_bar_ref .style("transition", "max-width 4s linear") .style("max-width", "80%"); } @@ -66,7 +66,7 @@ pub(crate) fn LoadingBar(#[prop(optional)] comp_ref: ComponentRef }; let finish = Callback::new(move |_| { if let Some(loading_bar_ref) = loading_bar_ref.get_untracked() { - loading_bar_ref + _ = loading_bar_ref .style("background-color", "var(--thaw-background-color)") .style("transition", "max-width 0.5s linear") .style("max-width", "100%"); @@ -83,7 +83,7 @@ pub(crate) fn LoadingBar(#[prop(optional)] comp_ref: ComponentRef .style("max-width", "0"); _ = loading_bar_ref.offset_width(); } - loading_bar_ref + _ = loading_bar_ref .style("background-color", "var(--thaw-background-color-error)") .style("transition", "max-width 0.5s linear") .style("max-width", "100%");