From 938342ab1f6e86458f6ec1d2182f0f21bb92149e Mon Sep 17 00:00:00 2001 From: luoxiao Date: Tue, 4 Jun 2024 23:12:21 +0800 Subject: [PATCH] feat: tab select --- thaw/src/tabs/mod.rs | 30 ++++++++++++++--------------- thaw/src/tabs/tab.css | 25 ++++++++++++++++++++++++ thaw/src/tabs/tab.rs | 41 +++++++++++++++++++++++++++++++++++++++- thaw/src/theme/common.rs | 4 ++++ 4 files changed, 84 insertions(+), 16 deletions(-) diff --git a/thaw/src/tabs/mod.rs b/thaw/src/tabs/mod.rs index 68cc5c7..6cb6458 100644 --- a/thaw/src/tabs/mod.rs +++ b/thaw/src/tabs/mod.rs @@ -8,26 +8,19 @@ use thaw_utils::{class_list, mount_style, Model}; #[component] pub fn TabList( - #[prop(optional, into)] selected_value: Model, #[prop(optional, into)] class: MaybeProp, + /// The value of the currently selected tab. + #[prop(optional, into)] + selected_value: Model, children: Children, ) -> impl IntoView { mount_style("tab-list", include_str!("./tab-list.css")); let registered_tabs = RwSignal::new(HashMap::new()); - // request_animation_frame(move || { - // let list_rect = label_list.get_bounding_client_rect(); - // let rect = label.get_bounding_client_rect(); - // label_line - // .set( - // Some(TabsLabelLine { - // width: rect.width(), - // left: rect.left() - list_rect.left(), - // }), - // ); - // }); + view! { @@ -43,8 +36,9 @@ pub fn TabList( #[derive(Clone)] pub(crate) struct TabListInjection { + pub previous_selected_value: StoredValue, pub selected_value: Model, - registered_tabs: RwSignal>, + pub registered_tabs: RwSignal>, } impl Copy for TabListInjection {} @@ -65,9 +59,15 @@ impl TabListInjection { map.remove(value); }); } + + pub fn on_select(&self, value: String) { + self.previous_selected_value + .set_value(self.selected_value.get_untracked()); + self.selected_value.set(value); + } } pub(crate) struct TabRegisterData { - value: String, - tab_ref: NodeRef, + pub value: String, + pub tab_ref: NodeRef, } diff --git a/thaw/src/tabs/tab.css b/thaw/src/tabs/tab.css index b934239..4f9fd7d 100644 --- a/thaw/src/tabs/tab.css +++ b/thaw/src/tabs/tab.css @@ -59,3 +59,28 @@ .thaw-tab:active .thaw-tab__content { color: var(--colorNeutralForeground2Pressed); } + +.thaw-tab--selected { + overflow: visible; +} + +.thaw-tab--selected .thaw-tab__content { + font-weight: var(--fontWeightSemibold); +} + +.thaw-tab--selected::after { + position: absolute; + content: ""; + transform: translateX(var(--thaw-tab__indicator--offset)) + scaleX(var(--thaw-tab__indicator--scale)); + transform-origin: left center; + transition-timing-function: var(--curveDecelerateMax); + transition-duration: var(--durationSlow); + transition-property: transform; + right: var(--spacingHorizontalM); + left: var(--spacingHorizontalM); + height: var(--strokeWidthThicker); + bottom: 0px; + background-color: var(--colorCompoundBrandStroke); + border-radius: var(--borderRadiusCircular); +} diff --git a/thaw/src/tabs/tab.rs b/thaw/src/tabs/tab.rs index 8781775..32d4484 100644 --- a/thaw/src/tabs/tab.rs +++ b/thaw/src/tabs/tab.rs @@ -1,5 +1,6 @@ use super::{TabListInjection, TabRegisterData}; use leptos::*; +use std::ops::Deref; use thaw_utils::{class_list, mount_style}; #[component] @@ -27,14 +28,52 @@ pub fn Tab( .with(|selected_value| value.with_value(|value| value == selected_value)) }); + Effect::new(move |_| { + let selected = selected.get(); + if selected { + tab_list.registered_tabs.with_untracked(|registered_tabs| { + if let Some(previous_selected_tab) = tab_list + .previous_selected_value + .with_value(|selected_value| registered_tabs.get(selected_value)) + { + let tab_el = tab_ref.get_untracked().unwrap(); + let selected_tab_rect = tab_el.get_bounding_client_rect(); + let previous_selected_tab_rect = previous_selected_tab + .tab_ref + .get_untracked() + .unwrap() + .get_bounding_client_rect(); + + let offset = previous_selected_tab_rect.x() - selected_tab_rect.x(); + let scale = previous_selected_tab_rect.width() / selected_tab_rect.width(); + + let style = tab_el.deref().style(); + let _ = style + .set_property("--thaw-tab__indicator--offset", &format!("{offset:.0}px")); + let _ = + style.set_property("--thaw-tab__indicator--scale", &format!("{scale:.2}")); + + // let _ = style.get_property_value("offsetWidth"); + + // let _ = style.set_property("--thaw-tab__indicator--offset", "0px"); + // let _ = style.set_property("--thaw-tab__indicator--scale", "1"); + } + }) + } + + selected + }); + view! {