fix: the position is messed up when switching DatePicker panels (#240)

This commit is contained in:
luoxiaozero 2024-08-24 16:20:00 +08:00 committed by GitHub
parent b476835c11
commit 7b29f7da37
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 63 additions and 17 deletions

View file

@ -1,8 +1,9 @@
use super::PanelVariant; use super::PanelVariant;
use crate::{Button, ButtonAppearance, ButtonSize, CalendarItemDate}; use crate::{Button, ButtonAppearance, ButtonSize, CalendarItemDate};
use chrono::{Datelike, Days, Month, Months, NaiveDate}; use chrono::{Datelike, Days, Month, Months, NaiveDate};
use leptos::prelude::*; use leptos::{html, prelude::*};
use std::ops::Deref; use std::ops::Deref;
use thaw_components::FollowerInjection;
use thaw_utils::{now_date, ArcOneCallback}; use thaw_utils::{now_date, ArcOneCallback};
#[component] #[component]
@ -12,6 +13,14 @@ pub fn DatePanel(
close_panel: ArcOneCallback<Option<NaiveDate>>, close_panel: ArcOneCallback<Option<NaiveDate>>,
panel_variant: RwSignal<PanelVariant>, panel_variant: RwSignal<PanelVariant>,
) -> impl IntoView { ) -> impl IntoView {
let follower = FollowerInjection::expect_context();
let panel_ref = NodeRef::<html::Div>::new();
Effect::new(move || {
let Some(_) = panel_ref.get() else {
return;
};
follower.refresh_position();
});
let dates = Memo::new(move |_| { let dates = Memo::new(move |_| {
let show_date = show_date.get(); let show_date = show_date.get();
let show_date_month = show_date.month(); let show_date_month = show_date.month();
@ -87,7 +96,7 @@ pub fn DatePanel(
} }
}; };
view! { view! {
<div> <div class="thaw-date-picker-date-panel" node_ref=panel_ref>
<div class="thaw-date-picker-date-panel__calendar"> <div class="thaw-date-picker-date-panel__calendar">
<div class="thaw-date-picker-date-panel__header"> <div class="thaw-date-picker-date-panel__header">
<Button <Button

View file

@ -1,13 +1,23 @@
use super::PanelVariant; use super::PanelVariant;
use crate::{Button, ButtonAppearance, ButtonSize}; use crate::{Button, ButtonAppearance, ButtonSize};
use chrono::{Datelike, Month, Months, NaiveDate}; use chrono::{Datelike, Month, Months, NaiveDate};
use leptos::prelude::*; use leptos::{html, prelude::*};
use thaw_components::FollowerInjection;
#[component] #[component]
pub fn MonthPanel( pub fn MonthPanel(
date_panel_show_date: RwSignal<NaiveDate>, date_panel_show_date: RwSignal<NaiveDate>,
panel_variant: RwSignal<PanelVariant>, panel_variant: RwSignal<PanelVariant>,
) -> impl IntoView { ) -> impl IntoView {
let follower = FollowerInjection::expect_context();
let panel_ref = NodeRef::<html::Div>::new();
Effect::new(move || {
let Some(_) = panel_ref.get() else {
return;
};
follower.refresh_position();
});
let show_date = RwSignal::new(date_panel_show_date.get_untracked()); let show_date = RwSignal::new(date_panel_show_date.get_untracked());
let previous_year = move |_| { let previous_year = move |_| {
show_date.update(|date| { show_date.update(|date| {
@ -20,7 +30,7 @@ pub fn MonthPanel(
}); });
}; };
view! { view! {
<div class="thaw-date-picker-month-panel"> <div class="thaw-date-picker-month-panel" node_ref=panel_ref>
<div class="thaw-date-picker-month-panel__header"> <div class="thaw-date-picker-month-panel__header">
<Button <Button
appearance=ButtonAppearance::Transparent appearance=ButtonAppearance::Transparent

View file

@ -1,7 +1,8 @@
use super::PanelVariant; use super::PanelVariant;
use crate::{Button, ButtonAppearance, ButtonSize}; use crate::{Button, ButtonAppearance, ButtonSize};
use chrono::{Datelike, NaiveDate}; use chrono::{Datelike, NaiveDate};
use leptos::prelude::*; use leptos::{html, prelude::*};
use thaw_components::FollowerInjection;
const MAX_YEAR: i32 = (i32::MAX >> 13) / 10 - 1; const MAX_YEAR: i32 = (i32::MAX >> 13) / 10 - 1;
const MIN_YEAR: i32 = (i32::MIN >> 13) / 10 + 1; const MIN_YEAR: i32 = (i32::MIN >> 13) / 10 + 1;
@ -11,6 +12,14 @@ pub fn YearPanel(
date_panel_show_date: RwSignal<NaiveDate>, date_panel_show_date: RwSignal<NaiveDate>,
panel_variant: RwSignal<PanelVariant>, panel_variant: RwSignal<PanelVariant>,
) -> impl IntoView { ) -> impl IntoView {
let follower = FollowerInjection::expect_context();
let panel_ref = NodeRef::<html::Div>::new();
Effect::new(move || {
let Some(_) = panel_ref.get() else {
return;
};
follower.refresh_position();
});
let show_min_year = RwSignal::new(date_panel_show_date.get_untracked().year() / 10); let show_min_year = RwSignal::new(date_panel_show_date.get_untracked().year() / 10);
let previous_year_range = move |_| { let previous_year_range = move |_| {
show_min_year.update(|year| { show_min_year.update(|year| {
@ -27,7 +36,7 @@ pub fn YearPanel(
}); });
}; };
view! { view! {
<div> <div class="thaw-date-picker-year-panel" node_ref=panel_ref>
<div class="thaw-date-picker-year-panel__header"> <div class="thaw-date-picker-year-panel__header">
<Button <Button
appearance=ButtonAppearance::Transparent appearance=ButtonAppearance::Transparent

View file

@ -8,6 +8,7 @@ use web_sys::wasm_bindgen::JsCast;
use crate::Teleport; use crate::Teleport;
use get_placement_style::{get_follower_placement_offset, FollowerPlacementOffset}; use get_placement_style::{get_follower_placement_offset, FollowerPlacementOffset};
use leptos::{ use leptos::{
context::Provider,
ev, ev,
html::{self, ElementType}, html::{self, ElementType},
leptos_dom::helpers::WindowListenerHandle, leptos_dom::helpers::WindowListenerHandle,
@ -187,23 +188,40 @@ where
} }
}); });
on_cleanup(move || { Owner::on_cleanup(move || {
remove_listener(); remove_listener();
}); });
let follower_injection = FollowerInjection(Callback::new(move |_| sync_position()));
view! { view! {
{children()} {children()}
<Teleport immediate=follower_show> <Teleport immediate=follower_show>
<div class="thaw-binder-follower-container"> <Provider value=follower_injection>
<div <div class="thaw-binder-follower-container">
class="thaw-binder-follower-content" <div
data-thaw-placement=move || placement_str.get() class="thaw-binder-follower-content"
node_ref=content_ref data-thaw-placement=move || placement_str.get()
style=move || content_style.get() node_ref=content_ref
> style=move || content_style.get()
{follower_children()} >
{follower_children()}
</div>
</div> </div>
</div> </Provider>
</Teleport> </Teleport>
} }
} }
#[derive(Debug, Clone)]
pub struct FollowerInjection(Callback<()>);
impl FollowerInjection {
pub fn expect_context() -> Self {
expect_context()
}
pub fn refresh_position(&self) {
self.0.run(());
}
}

View file

@ -5,7 +5,7 @@ mod if_comp;
mod option_comp; mod option_comp;
mod teleport; mod teleport;
pub use binder::{Binder, Follower, FollowerPlacement, FollowerWidth}; pub use binder::{Binder, Follower, FollowerInjection, FollowerPlacement, FollowerWidth};
pub use css_transition::CSSTransition; pub use css_transition::CSSTransition;
pub use focus_trap::FocusTrap; pub use focus_trap::FocusTrap;
pub use if_comp::{ElseIf, If, Then}; pub use if_comp::{ElseIf, If, Then};