thaw/src/tabs/mod.rs

135 lines
4.6 KiB
Rust
Raw Normal View History

2023-06-15 18:02:21 +08:00
mod tab;
2023-10-11 21:25:11 +08:00
use std::ops::Deref;
use crate::{
theme::use_theme,
utils::{maybe_rw_signal::MaybeRwSignal, mount_style::mount_style},
Theme,
};
2023-06-15 18:02:21 +08:00
use leptos::*;
2023-10-07 21:41:03 +08:00
2023-06-15 18:02:21 +08:00
pub use tab::*;
#[component]
2023-10-11 21:25:11 +08:00
pub fn Tabs(
2023-10-17 17:25:20 +08:00
#[prop(optional, into)] value: MaybeRwSignal<String>,
2023-10-11 21:25:11 +08:00
children: Children,
) -> impl IntoView {
2023-10-07 21:41:03 +08:00
mount_style("tabs", include_str!("./tabs.css"));
2023-08-29 09:11:22 +08:00
let tab_options_vec = create_rw_signal(vec![]);
provide_context(TabsInjectionKey {
2023-10-11 21:25:11 +08:00
active_key: value.deref().clone(),
2023-08-29 09:11:22 +08:00
tab_options_vec: tab_options_vec.clone(),
});
let theme = use_theme(Theme::light);
let css_vars = create_memo(move |_| {
2023-06-15 18:02:21 +08:00
let mut css_vars = String::new();
let theme = theme.get();
let color_primary = theme.common.color_primary.clone();
2023-06-18 22:13:32 +08:00
css_vars.push_str(&format!(
"--label-active-background-color: {color_primary};"
));
2023-06-15 18:02:21 +08:00
css_vars
});
2023-06-18 22:13:32 +08:00
2023-08-29 09:11:22 +08:00
let label_line = create_rw_signal::<Option<TabsLabelLine>>(None);
let label_line_style = create_memo(move |_| {
2023-06-18 22:13:32 +08:00
let mut style = String::new();
if let Some(line) = label_line.get() {
style.push_str(&format!("width: {}px; left: {}px", line.width, line.left))
}
style
});
2023-08-29 09:11:22 +08:00
let label_list_ref = create_node_ref::<html::Div>();
2023-06-18 22:13:32 +08:00
2023-10-07 21:41:03 +08:00
view! {
2023-06-15 18:02:21 +08:00
<div class="melt-tabs" style=move || css_vars.get()>
2023-06-18 22:13:32 +08:00
<div class="melt-tabs__label-list" ref=label_list_ref>
2023-10-08 09:28:13 +08:00
<For
each=move || tab_options_vec.get()
2023-10-17 17:25:20 +08:00
key=move |v| v.key.clone()
children=move |option| {
2023-10-08 09:28:13 +08:00
let label_ref = create_node_ref::<html::Span>();
2023-10-17 17:25:20 +08:00
let TabOption { key, label } = option;
create_effect({
let key = key.clone();
move |_| {
let Some(label) = label_ref.get() else {
return;
};
let Some(label_list) = label_list_ref.get() else {
return;
};
if key.clone() == value.get() {
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(),
}),
);
});
}
2023-10-08 09:28:13 +08:00
}
});
view! {
<span
class="melt-tabs__label"
class=(
"melt-tabs__label--active",
2023-10-17 17:25:20 +08:00
{
let key = key.clone();
move || key == value.get()
},
2023-10-08 09:28:13 +08:00
)
2023-10-17 17:25:20 +08:00
on:click={
let key = key.clone();
move |_| value.set(key.clone())
}
2023-10-08 09:28:13 +08:00
ref=label_ref
>
2023-10-17 17:25:20 +08:00
{label}
2023-10-08 09:28:13 +08:00
</span>
2023-06-18 22:13:32 +08:00
}
}
2023-10-08 09:28:13 +08:00
/>
2023-06-18 22:13:32 +08:00
<span class="melt-tabs-label__line" style=move || label_line_style.get()></span>
2023-06-15 18:02:21 +08:00
</div>
2023-10-08 09:28:13 +08:00
<div>{children()}</div>
2023-06-15 18:02:21 +08:00
</div>
}
}
2023-06-18 22:13:32 +08:00
#[derive(Clone)]
pub(crate) struct TabsLabelLine {
width: f64,
left: f64,
}
2023-06-15 18:02:21 +08:00
#[derive(Clone)]
pub struct TabsInjectionKey {
2023-10-17 17:25:20 +08:00
active_key: RwSignal<String>,
tab_options_vec: RwSignal<Vec<TabOption>>,
2023-06-15 18:02:21 +08:00
}
impl TabsInjectionKey {
2023-10-17 17:25:20 +08:00
pub fn get_key(&self) -> String {
2023-06-15 18:02:21 +08:00
self.active_key.get()
}
2023-10-17 17:25:20 +08:00
pub(crate) fn push_tab_options(&self, options: TabOption) {
2023-06-15 18:02:21 +08:00
self.tab_options_vec.update(|v| {
v.push(options);
});
}
}
2023-08-29 09:11:22 +08:00
pub fn use_tabs() -> TabsInjectionKey {
use_context::<TabsInjectionKey>().expect("TabsInjectionKey not exist")
2023-06-15 18:02:21 +08:00
}