mirror of
https://github.com/adoyle0/thaw.git
synced 2025-02-02 08:34:15 -05:00
feat: custom tab label (#91)
This commit is contained in:
parent
a78ef1a8ac
commit
a2da6b4a59
3 changed files with 125 additions and 28 deletions
|
@ -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. |
|
||||
|
|
|
@ -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,16 +93,18 @@ fn TabsInner(
|
|||
}
|
||||
}
|
||||
});
|
||||
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="thaw-tabs__label"
|
||||
class=(
|
||||
"thaw-tabs__label--active",
|
||||
{
|
||||
let key = key.clone();
|
||||
move || key == value.get()
|
||||
},
|
||||
)
|
||||
class=class_list![
|
||||
"thaw-tabs__label", ("thaw-tabs__label--active", move ||
|
||||
is_active.get()), move || class.get()
|
||||
]
|
||||
|
||||
on:click={
|
||||
let key = key.clone();
|
||||
|
@ -110,10 +112,37 @@ fn TabsInner(
|
|||
}
|
||||
|
||||
ref=label_ref
|
||||
role="tab"
|
||||
aria-selected=move || {
|
||||
if is_active.get() { "true" } else { "false" }
|
||||
}
|
||||
>
|
||||
{label}
|
||||
|
||||
{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>
|
||||
}
|
||||
}
|
||||
}
|
||||
/>
|
||||
|
||||
|
|
|
@ -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 || {
|
||||
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>
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue