From c57910948fc58690f0e37f330f8f72c29257ddb4 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Sun, 12 Nov 2023 01:58:26 +0800 Subject: [PATCH] feat: binder component add placement --- src/auto_complete/mod.rs | 4 +- src/components/binder/get_placement_style.rs | 65 ++++++++++++++++++++ src/components/binder/mod.rs | 32 +++++++--- 3 files changed, 91 insertions(+), 10 deletions(-) create mode 100644 src/components/binder/get_placement_style.rs diff --git a/src/auto_complete/mod.rs b/src/auto_complete/mod.rs index 94eaaed..8d6fa83 100644 --- a/src/auto_complete/mod.rs +++ b/src/auto_complete/mod.rs @@ -1,7 +1,7 @@ mod theme; use crate::{ - components::{Binder, Follower}, + components::{Binder, Follower, FollowerPlacement}, mount_style, use_theme, utils::StoredMaybeSignal, Input, Theme, @@ -61,7 +61,7 @@ pub fn AutoComplete( allow_value /> - +
Option { + // TODO: Implements FollowerPlacement more properties + _ = placement; + let mut style = String::new(); + let left = target_rect.x(); + let top = { + let follower_height = follower_rect.height(); + let target_y = target_rect.y(); + let target_height = target_rect.height(); + let mut top = target_y + target_height; + + let Some(inner_height) = window_inner_height() else { + return None; + }; + + if top + follower_height > inner_height { + if target_y - follower_height >= 0.0 { + top = target_y - follower_height + } + } + + top + }; + + style.push_str(&format!( + "transform: translateX({left}px) translateY({top}px);" + )); + + Some(style) +} + +fn window_inner_height() -> Option { + let Ok(inner_height) = window().inner_height() else { + return None; + }; + let Some(inner_height) = inner_height.as_f64() else { + return None; + }; + Some(inner_height) +} diff --git a/src/components/binder/mod.rs b/src/components/binder/mod.rs index c6f36b8..15990d9 100644 --- a/src/components/binder/mod.rs +++ b/src/components/binder/mod.rs @@ -1,8 +1,12 @@ +mod get_placement_style; + use crate::{ mount_style, teleport::Teleport, utils::{add_event_listener, EventListenerHandle}, }; +use get_placement_style::get_follower_placement_style; +pub use get_placement_style::FollowerPlacement; use leptos::{ html::{AnyElement, ElementDescriptor, ToHtmlElement}, leptos_dom::helpers::WindowListenerHandle, @@ -13,6 +17,7 @@ use leptos::{ pub struct Follower { #[prop(into)] show: MaybeSignal, + placement: FollowerPlacement, children: Children, } @@ -25,6 +30,7 @@ pub fn Binder( mount_style("binder", include_str!("./binder.css")); let Follower { show: follower_show, + placement: follower_placement, children: follower_children, } = follower; @@ -102,6 +108,7 @@ pub fn Binder( ( fn FollowerContainer( show: MaybeSignal, target_ref: NodeRef, + placement: FollowerPlacement, #[prop(into)] add_scroll_listener: Callback>, #[prop(into)] remove_scroll_listener: Callback<()>, #[prop(into)] add_resize_listener: Callback>, @@ -125,18 +133,24 @@ fn FollowerContainer( let content_ref = create_node_ref::(); let content_style = create_rw_signal(String::new()); let sync_position: Callback<()> = Callback::new(move |_| { - let Some(target_ref) = target_ref.get().map(|target| target.into_any()) else { + let Some(content_ref) = content_ref.get_untracked() else { + return; + }; + let Some(target_ref) = target_ref.get_untracked().map(|target| target.into_any()) else { return; }; let target_rect = target_ref.get_bounding_client_rect(); - + let content_rect = content_ref.get_bounding_client_rect(); let mut style = String::new(); style.push_str(&format!("width: {}px;", target_rect.width())); - style.push_str(&format!( - "transform: translateX({}px) translateY({}px);", - target_rect.x(), - target_rect.y() + target_rect.height() - )); + if let Some(placement_style) = + get_follower_placement_style(placement, target_rect, content_rect) + { + style.push_str(&placement_style); + } else { + logging::error!("Thaw-Binder: get_follower_placement_style return None"); + } + content_style.set(style); }); @@ -149,7 +163,9 @@ fn FollowerContainer( } let is_show = show.get(); if is_show { - sync_position.call(()); + request_animation_frame(move || { + sync_position.call(()); + }); add_scroll_listener.call(sync_position); add_resize_listener.call(sync_position); } else {