feat: custom tab label (#91)

This commit is contained in:
luoxiaozero 2024-01-25 22:18:33 +08:00 committed by GitHub
parent a78ef1a8ac
commit a2da6b4a59
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 125 additions and 28 deletions

View file

@ -15,6 +15,33 @@ view! {
}
```
### Custom tab label
```rust demo
use leptos_meta::Style;
let value = create_rw_signal(String::from("apple"));
view! {
<Style id="demo-tab-label">
".p-0 { padding: 0 }"
</Style>
<Tabs value>
<Tab key="apple">
<TabLabel slot class="p-0">
"🍎 Apple"
</TabLabel>
"apple"
</Tab>
<Tab key="pear">
<TabLabel slot>
"🍐 Pear"
</TabLabel>
"pear"
</Tab>
</Tabs>
}
```
### Tabs Props
| Name | Type | Default | Description |
@ -29,5 +56,11 @@ view! {
| -------- | --------------------- | -------------------- | -------------------------------------- |
| class | `MaybeSignal<String>` | `Default::default()` | Addtional classes for the tab element. |
| key | `String` | | The indentifier of the tab. |
| label | `String` | | The label of the tab. |
| label | `String` | `Default::default()` | The label of the tab. |
| children | `Children` | | Tabs content. |
### Tab Slots
| Name | Default | Description |
| -------- | ------- | -------------- |
| TabLabel | `None` | label content. |

View file

@ -62,13 +62,13 @@ fn TabsInner(
view! {
<div class=class_list!["thaw-tabs", move || class.get()] style=move || css_vars.get()>
<div class="thaw-tabs__label-list" ref=label_list_ref>
<div class="thaw-tabs__label-list" ref=label_list_ref role="tablist">
<For
each=move || tab_options_vec.get()
key=move |v| v.key.clone()
children=move |option| {
let label_ref = create_node_ref::<html::Span>();
let TabOption { key, label } = option;
let TabOption { key, label, label_view } = option;
create_effect({
let key = key.clone();
move |_| {
@ -93,26 +93,55 @@ fn TabsInner(
}
}
});
view! {
<span
class="thaw-tabs__label"
class=(
"thaw-tabs__label--active",
{
let is_active = create_memo({
let key = key.clone();
move |_| key == value.get()
});
if let Some(label_view) = label_view {
let TabLabelView { class, children } = label_view;
view! {
<span
class=class_list![
"thaw-tabs__label", ("thaw-tabs__label--active", move ||
is_active.get()), move || class.get()
]
on:click={
let key = key.clone();
move || key == value.get()
},
)
move |_| value.set(key.clone())
}
on:click={
let key = key.clone();
move |_| value.set(key.clone())
}
ref=label_ref
role="tab"
aria-selected=move || {
if is_active.get() { "true" } else { "false" }
}
>
ref=label_ref
>
{label}
</span>
{children}
</span>
}
} else {
view! {
<span
class="thaw-tabs__label"
class=("thaw-tabs__label--active", move || is_active.get())
on:click={
let key = key.clone();
move |_| value.set(key.clone())
}
ref=label_ref
role="tab"
aria-selected=move || {
if is_active.get() { "true" } else { "false" }
}
>
{if label.is_empty() { key } else { label }}
</span>
}
}
}
/>

View file

@ -6,12 +6,37 @@ use leptos::*;
pub(crate) struct TabOption {
pub key: String,
pub label: String,
pub label_view: Option<TabLabelView>,
}
#[derive(Clone)]
pub(crate) struct TabLabelView {
pub class: MaybeSignal<String>,
pub children: Fragment,
}
impl From<TabLabel> for TabLabelView {
fn from(tab_label: TabLabel) -> Self {
let TabLabel { class, children } = tab_label;
Self {
class,
children: children(),
}
}
}
#[slot]
pub struct TabLabel {
#[prop(optional, into)]
class: MaybeSignal<String>,
children: Children,
}
#[component]
pub fn Tab(
#[prop(into)] key: String,
#[prop(into)] label: String,
#[prop(optional, into)] label: String,
#[prop(optional)] tab_label: Option<TabLabel>,
#[prop(optional, into)] class: MaybeSignal<String>,
children: Children,
) -> impl IntoView {
@ -20,19 +45,29 @@ pub fn Tab(
tabs.push_tab_options(TabOption {
key: key.clone(),
label,
label_view: tab_label.map(|label| label.into()),
});
on_cleanup({
let is_active = create_memo({
let key = key.clone();
let tabs = tabs.clone();
move || {
tabs.remove_tab_options(&key);
}
move |_| key == tabs.get_key()
});
on_cleanup(move || {
tabs.remove_tab_options(&key);
});
view! {
<div class=class_list![
"thaw-tab", ("thaw-tab--hidden", move || key != tabs.get_key()), move || class.get()
]>{children()}</div>
<div
class=class_list![
"thaw-tab", ("thaw-tab--hidden", move || ! is_active.get()), move || class.get()
]
role="tabpanel"
aria-hidden=move || if is_active.get() { "false" } else { "true" }
>
{children()}
</div>
}
}