fix: Binder component sync position

This commit is contained in:
luoxiao 2024-09-11 22:37:26 +08:00 committed by luoxiaozero
parent 3e59f506dd
commit b04feef0d1
14 changed files with 87 additions and 74 deletions

View file

@ -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());
{

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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();
}

View file

@ -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()
>
<Provider value=follower_injection>
{follower_children()}
</Provider>
<Provider value=follower_injection>{follower_children()}</Provider>
</div>
</div>
</Teleport>

View file

@ -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()
})
}

View file

@ -1,16 +1,35 @@
use leptos::prelude::*;
use web_sys::Element;
use wasm_bindgen::JsCast;
use web_sys::{Element, Node};
pub fn get_scroll_parent(element: &Element) -> Option<Element> {
let Some(parent_element) = get_parent_element(element) else {
return None;
};
pub fn get_scroll_parent_node(node: &Node) -> Option<Node> {
let parent_node = node.parent_node()?;
if parent_element.node_type() == 9 {
return Some(parent_element);
let node_type = parent_node.node_type();
if node_type == Node::ELEMENT_NODE {
let el = parent_node.clone().dyn_into::<Element>().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_node);
}
if overflow.contains("scroll") {
return Some(parent_node);
}
if overflow.contains("overlay") {
return Some(parent_node);
}
}
} else if node_type == Node::DOCUMENT_NODE {
return Some(document().into());
}
if parent_element.node_type() == 1 {
get_scroll_parent_node(&parent_node)
}
pub fn get_scroll_parent_element(element: &Element) -> Option<Element> {
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") {
@ -23,17 +42,8 @@ pub fn get_scroll_parent(element: &Element) -> Option<Element> {
return Some(parent_element);
}
}
}
get_scroll_parent(&parent_element)
}
fn get_parent_element(element: &Element) -> Option<Element> {
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)> {

View file

@ -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;

View file

@ -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() {

View file

@ -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<E>(
target: Element,
target: impl Into<EventTarget>,
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<EventTarget>,
event_name: &str,
cb: impl Fn(web_sys::Event) + 'static,
) -> EventListenerHandle {
fn wel(
target: Element,
target: EventTarget,
cb: Box<dyn FnMut(web_sys::Event)>,
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<E: ev::EventDescriptor + 'static>(
target: impl IntoEventTarget,
target: impl Into<EventTarget>,
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::<E::EventType>()),
use_capture,
@ -75,7 +75,7 @@ where
}
fn add_event_listener_untyped_with_bool(
target: EventTarget,
target: impl Into<EventTarget>,
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<AnyElement> {
// fn into_event_target(self) -> EventTarget {

View file

@ -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;

View file

@ -58,7 +58,9 @@ impl<T: Send + Sync> OptionModel<T> {
pub fn with_untracked<O>(&self, fun: impl FnOnce(OptionModelWithValue<T>) -> 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)))
}
}
}
}

View file

@ -67,10 +67,7 @@ impl<T: Send + Sync> VecModel<T> {
}
}
pub fn with<O>(
&self,
fun: impl FnOnce(VecModelWithValue<T>) -> O,
) -> O {
pub fn with<O>(&self, fun: impl FnOnce(VecModelWithValue<T>) -> O) -> O {
match self {
Self::T(read, _, _) => read.with(|value| fun(VecModelWithValue::T(value))),
Self::Option(read, _, _) => read.with(|value| fun(VecModelWithValue::Option(value))),