From b04feef0d17d86a13f6590e725f47f4b2797cc60 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Wed, 11 Sep 2024 22:37:26 +0800 Subject: [PATCH] fix: Binder component sync position --- thaw/src/back_top/mod.rs | 4 +- thaw/src/combobox/combobox.rs | 2 +- thaw/src/menu/mod.rs | 2 +- thaw/src/popover/mod.rs | 2 +- thaw/src/upload/mod.rs | 2 +- thaw_components/src/binder/mod.rs | 14 +++-- thaw_components/src/css_transition/mod.rs | 12 ++--- thaw_utils/src/dom/get_scroll_parent.rs | 56 ++++++++++++-------- thaw_utils/src/dom/mod.rs | 2 +- thaw_utils/src/dom/scroll_into_view.rs | 4 +- thaw_utils/src/event_listener.rs | 50 +++++++++-------- thaw_utils/src/signals/mod.rs | 2 +- thaw_utils/src/signals/model/option_model.rs | 4 +- thaw_utils/src/signals/model/vec_model.rs | 5 +- 14 files changed, 87 insertions(+), 74 deletions(-) diff --git a/thaw/src/back_top/mod.rs b/thaw/src/back_top/mod.rs index 0f96885..e4c7195 100644 --- a/thaw/src/back_top/mod.rs +++ b/thaw/src/back_top/mod.rs @@ -2,7 +2,7 @@ use crate::{ConfigInjection, Icon}; use leptos::{either::Either, ev, html, prelude::*}; use thaw_components::{CSSTransition, Teleport}; use thaw_utils::{ - add_event_listener, class_list, get_scroll_parent, mount_style, BoxCallback, + add_event_listener, class_list, get_scroll_parent_element, mount_style, BoxCallback, EventListenerHandle, }; @@ -43,7 +43,7 @@ pub fn BackTop( }; request_animation_frame(move || { - let scroll_el = get_scroll_parent(&placeholder_el) + let scroll_el = get_scroll_parent_element(&placeholder_el) .unwrap_or_else(|| document().document_element().unwrap()); { diff --git a/thaw/src/combobox/combobox.rs b/thaw/src/combobox/combobox.rs index 7701b74..bf95e2a 100644 --- a/thaw/src/combobox/combobox.rs +++ b/thaw/src/combobox/combobox.rs @@ -55,7 +55,7 @@ pub fn Combobox( let Some(clear_icon_el) = clear_icon_ref.get() else { return; }; - let handler = add_event_listener(clear_icon_el.into(), ev::click, move |e| { + let handler = add_event_listener(clear_icon_el, ev::click, move |e| { if disabled.get_untracked() { return; } diff --git a/thaw/src/menu/mod.rs b/thaw/src/menu/mod.rs index e2fdb7d..b6f5669 100644 --- a/thaw/src/menu/mod.rs +++ b/thaw/src/menu/mod.rs @@ -80,7 +80,7 @@ pub fn Menu( let Some(target_el) = target_ref.get() else { return; }; - let handler = add_event_listener(target_el.into(), ev::click, move |event| { + let handler = add_event_listener(target_el, ev::click, move |event| { if trigger_type != MenuTriggerType::Click { return; } diff --git a/thaw/src/popover/mod.rs b/thaw/src/popover/mod.rs index f452e2d..d4a29d2 100644 --- a/thaw/src/popover/mod.rs +++ b/thaw/src/popover/mod.rs @@ -99,7 +99,7 @@ pub fn Popover( let Some(target_el) = target_ref.get() else { return; }; - let handler = add_event_listener(target_el.into(), ev::click, move |event| { + let handler = add_event_listener(target_el, ev::click, move |event| { if trigger_type != PopoverTriggerType::Click { return; } diff --git a/thaw/src/upload/mod.rs b/thaw/src/upload/mod.rs index 442f5d7..c8c1530 100644 --- a/thaw/src/upload/mod.rs +++ b/thaw/src/upload/mod.rs @@ -34,7 +34,7 @@ pub fn Upload( let Some(trigger_el) = trigger_ref.get() else { return; }; - let handle = add_event_listener(trigger_el.into(), ev::click, move |_| { + let handle = add_event_listener(trigger_el, ev::click, move |_| { if let Some(input_ref) = input_ref.get_untracked() { input_ref.click(); } diff --git a/thaw_components/src/binder/mod.rs b/thaw_components/src/binder/mod.rs index 6d7edfa..9e22344 100644 --- a/thaw_components/src/binder/mod.rs +++ b/thaw_components/src/binder/mod.rs @@ -14,7 +14,7 @@ use leptos::{ leptos_dom::helpers::WindowListenerHandle, prelude::*, }; -use thaw_utils::{add_event_listener, get_scroll_parent, mount_style, EventListenerHandle}; +use thaw_utils::{add_event_listener, get_scroll_parent_node, mount_style, EventListenerHandle}; #[slot] pub struct Follower { @@ -141,12 +141,12 @@ where }; let mut handle_vec = vec![]; - let mut cursor = get_scroll_parent(&el); + let mut cursor = get_scroll_parent_node(&el); loop { - if let Some(el) = cursor.take() { - cursor = get_scroll_parent(&el); + if let Some(node) = cursor.take() { + cursor = get_scroll_parent_node(&node); - let handle = add_event_listener(el, ev::scroll, move |_| { + let handle = add_event_listener(node, ev::scroll, move |_| { sync_position(); }); handle_vec.push(handle); @@ -213,9 +213,7 @@ where node_ref=content_ref style=move || content_style.get() > - - {follower_children()} - + {follower_children()} diff --git a/thaw_components/src/css_transition/mod.rs b/thaw_components/src/css_transition/mod.rs index 9838fa7..73bb28b 100644 --- a/thaw_components/src/css_transition/mod.rs +++ b/thaw_components/src/css_transition/mod.rs @@ -92,13 +92,13 @@ where } }; let handle = match types { - AnimationTypes::Transition => add_event_listener( - el.deref().clone().into(), - ev::transitionend, - move |_| event_listener(), - ), + AnimationTypes::Transition => { + add_event_listener(el.deref().clone(), ev::transitionend, move |_| { + event_listener() + }) + } AnimationTypes::Animation => { - add_event_listener(el.deref().clone().into(), ev::animationend, move |_| { + add_event_listener(el.deref().clone(), ev::animationend, move |_| { event_listener() }) } diff --git a/thaw_utils/src/dom/get_scroll_parent.rs b/thaw_utils/src/dom/get_scroll_parent.rs index 9b977c8..7393cf2 100644 --- a/thaw_utils/src/dom/get_scroll_parent.rs +++ b/thaw_utils/src/dom/get_scroll_parent.rs @@ -1,39 +1,49 @@ use leptos::prelude::*; -use web_sys::Element; +use wasm_bindgen::JsCast; +use web_sys::{Element, Node}; -pub fn get_scroll_parent(element: &Element) -> Option { - let Some(parent_element) = get_parent_element(element) else { - return None; - }; +pub fn get_scroll_parent_node(node: &Node) -> Option { + let parent_node = node.parent_node()?; - if parent_element.node_type() == 9 { - return Some(parent_element); - } - - if parent_element.node_type() == 1 { - if let Some((overflow, overflow_x, overflow_y)) = get_overflow(&parent_element) { + let node_type = parent_node.node_type(); + if node_type == Node::ELEMENT_NODE { + let el = parent_node.clone().dyn_into::().unwrap(); + if let Some((overflow, overflow_x, overflow_y)) = get_overflow(&el) { let overflow = format!("{overflow}{overflow_x}{overflow_y}"); if overflow.contains("auto") { - return Some(parent_element); + return Some(parent_node); } if overflow.contains("scroll") { - return Some(parent_element); + return Some(parent_node); } if overflow.contains("overlay") { - return Some(parent_element); + return Some(parent_node); } } + } else if node_type == Node::DOCUMENT_NODE { + return Some(document().into()); + } + + get_scroll_parent_node(&parent_node) +} + +pub fn get_scroll_parent_element(element: &Element) -> Option { + let parent_element = element.parent_element()?; + + 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(&parent_element) -} - -fn get_parent_element(element: &Element) -> Option { - if element.node_type() == 9 { - None - } else { - element.parent_element() - } + get_scroll_parent_element(&parent_element) } fn get_overflow(parent_element: &Element) -> Option<(String, String, String)> { diff --git a/thaw_utils/src/dom/mod.rs b/thaw_utils/src/dom/mod.rs index df361b7..0f5174e 100644 --- a/thaw_utils/src/dom/mod.rs +++ b/thaw_utils/src/dom/mod.rs @@ -2,6 +2,6 @@ mod get_scroll_parent; mod mount_style; mod scroll_into_view; -pub use get_scroll_parent::get_scroll_parent; +pub use get_scroll_parent::{get_scroll_parent_element, get_scroll_parent_node}; pub use mount_style::{mount_dynamic_style, mount_style}; pub use scroll_into_view::scroll_into_view; diff --git a/thaw_utils/src/dom/scroll_into_view.rs b/thaw_utils/src/dom/scroll_into_view.rs index ad6c3c1..045944c 100644 --- a/thaw_utils/src/dom/scroll_into_view.rs +++ b/thaw_utils/src/dom/scroll_into_view.rs @@ -3,8 +3,8 @@ use web_sys::HtmlElement; pub fn scroll_into_view(el: &HtmlElement) { cfg_if! { if #[cfg(all(target_arch = "wasm32", any(feature = "csr", feature = "hydrate")))] { - use super::get_scroll_parent; - if let Some(parent) = get_scroll_parent(el) { + use super::get_scroll_parent_element; + if let Some(parent) = get_scroll_parent_element(el) { let parent_rect = parent.get_bounding_client_rect(); let el_rect = el.get_bounding_client_rect(); if el_rect.y() < parent_rect.y() { diff --git a/thaw_utils/src/event_listener.rs b/thaw_utils/src/event_listener.rs index 485d2d0..21c1d92 100644 --- a/thaw_utils/src/event_listener.rs +++ b/thaw_utils/src/event_listener.rs @@ -1,9 +1,9 @@ use ::wasm_bindgen::{prelude::Closure, JsCast}; use leptos::ev; -use web_sys::{Element, EventTarget}; +use web_sys::EventTarget; pub fn add_event_listener( - target: Element, + target: impl Into, event: E, cb: impl Fn(E::EventType) + 'static, ) -> EventListenerHandle @@ -31,12 +31,12 @@ impl EventListenerHandle { } fn add_event_listener_untyped( - target: Element, + target: impl Into, event_name: &str, cb: impl Fn(web_sys::Event) + 'static, ) -> EventListenerHandle { fn wel( - target: Element, + target: EventTarget, cb: Box, event_name: &str, ) -> EventListenerHandle { @@ -54,11 +54,11 @@ fn add_event_listener_untyped( }) } - wel(target, Box::new(cb), event_name) + wel(target.into(), Box::new(cb), event_name) } pub fn add_event_listener_with_bool( - target: impl IntoEventTarget, + target: impl Into, event: E, cb: impl Fn(E::EventType) + 'static, use_capture: bool, @@ -67,7 +67,7 @@ where E::EventType: JsCast, { add_event_listener_untyped_with_bool( - target.into_event_target(), + target, &event.name(), move |e| cb(e.unchecked_into::()), use_capture, @@ -75,7 +75,7 @@ where } fn add_event_listener_untyped_with_bool( - target: EventTarget, + target: impl Into, event_name: &str, cb: impl Fn(web_sys::Event) + 'static, use_capture: bool, @@ -107,24 +107,30 @@ fn add_event_listener_untyped_with_bool( }) } - wel(target, Box::new(cb), event_name, use_capture) + wel(target.into(), Box::new(cb), event_name, use_capture) } -pub trait IntoEventTarget { - fn into_event_target(self) -> EventTarget; -} +// pub trait IntoEventTarget { +// fn into_event_target(self) -> EventTarget; +// } -impl IntoEventTarget for EventTarget { - fn into_event_target(self) -> EventTarget { - self - } -} +// impl IntoEventTarget for EventTarget { +// fn into_event_target(self) -> EventTarget { +// self +// } +// } -impl IntoEventTarget for web_sys::Document { - fn into_event_target(self) -> EventTarget { - self.into() - } -} +// impl IntoEventTarget for web_sys::Document { +// fn into_event_target(self) -> EventTarget { +// self.into() +// } +// } + +// impl IntoEventTarget for Element { +// fn into_event_target(self) -> EventTarget { +// self.into() +// } +// } // impl IntoEventTarget for HtmlElement { // fn into_event_target(self) -> EventTarget { diff --git a/thaw_utils/src/signals/mod.rs b/thaw_utils/src/signals/mod.rs index 3d2ef48..b9b560a 100644 --- a/thaw_utils/src/signals/mod.rs +++ b/thaw_utils/src/signals/mod.rs @@ -4,6 +4,6 @@ mod signal_watch; mod stored_maybe_signal; pub use component_ref::ComponentRef; -pub use model::{Model, OptionModel, VecModel, VecModelWithValue, OptionModelWithValue}; +pub use model::{Model, OptionModel, OptionModelWithValue, VecModel, VecModelWithValue}; pub use signal_watch::SignalWatch; pub use stored_maybe_signal::StoredMaybeSignal; diff --git a/thaw_utils/src/signals/model/option_model.rs b/thaw_utils/src/signals/model/option_model.rs index a56e45f..9ec14e9 100644 --- a/thaw_utils/src/signals/model/option_model.rs +++ b/thaw_utils/src/signals/model/option_model.rs @@ -58,7 +58,9 @@ impl OptionModel { pub fn with_untracked(&self, fun: impl FnOnce(OptionModelWithValue) -> O) -> O { match self { Self::T(read, _, _) => read.with_untracked(|value| fun(OptionModelWithValue::T(value))), - Self::Option(read, _, _) => read.with_untracked(|value| fun(OptionModelWithValue::Option(value))), + Self::Option(read, _, _) => { + read.with_untracked(|value| fun(OptionModelWithValue::Option(value))) + } } } } diff --git a/thaw_utils/src/signals/model/vec_model.rs b/thaw_utils/src/signals/model/vec_model.rs index 61427b2..d498fcb 100644 --- a/thaw_utils/src/signals/model/vec_model.rs +++ b/thaw_utils/src/signals/model/vec_model.rs @@ -67,10 +67,7 @@ impl VecModel { } } - pub fn with( - &self, - fun: impl FnOnce(VecModelWithValue) -> O, - ) -> O { + pub fn with(&self, fun: impl FnOnce(VecModelWithValue) -> O) -> O { match self { Self::T(read, _, _) => read.with(|value| fun(VecModelWithValue::T(value))), Self::Option(read, _, _) => read.with(|value| fun(VecModelWithValue::Option(value))),