Skip to content

Commit aa75ad8

Browse files
authored
feat: NavDrawer adds open_categories prop (#387)
1 parent f310028 commit aa75ad8

File tree

3 files changed

+101
-50
lines changed

3 files changed

+101
-50
lines changed

thaw/src/nav/docs/mod.md

+56-41
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,62 @@
11
# Nav
22

33
```rust demo
4+
let is_multiple = RwSignal::new(true);
5+
let is_multiple_label = Memo::new(move |_| {
6+
if is_multiple.get() {
7+
"Multiple".to_string()
8+
} else {
9+
"Single".to_string()
10+
}
11+
});
412

513
view! {
6-
<NavDrawer>
7-
<NavCategory value="area">
8-
<NavCategoryItem slot icon=icondata::AiAreaChartOutlined>
9-
"Area Chart"
10-
</NavCategoryItem>
11-
<NavSubItem value="target">
12-
"Target"
13-
</NavSubItem>
14-
<NavSubItem value="above">
15-
"Above"
16-
</NavSubItem>
17-
<NavSubItem value="below">
18-
"Below"
19-
</NavSubItem>
20-
</NavCategory>
21-
<NavCategory value="pie">
22-
<NavCategoryItem slot icon=icondata::AiPieChartOutlined>
23-
"Pie Chart"
24-
</NavCategoryItem>
25-
<NavSubItem value="pie-target">
26-
"Pie Target"
27-
</NavSubItem>
28-
<NavSubItem value="pin-above">
29-
"Pin Above"
30-
</NavSubItem>
31-
<NavSubItem value="pin-below">
32-
"Pin Below"
33-
</NavSubItem>
34-
</NavCategory>
35-
<NavItem
36-
icon=icondata::AiGithubOutlined
37-
value="github"
38-
href="https://github.com/thaw-ui/thaw"
39-
attr:target="_blank"
40-
>
41-
"Github"
42-
</NavItem>
43-
<NavItem icon=icondata::AiChromeOutlined value="chrome">
44-
"Chrome"
45-
</NavItem>
46-
</NavDrawer>
14+
<Flex>
15+
<NavDrawer multiple=is_multiple>
16+
<NavCategory value="area">
17+
<NavCategoryItem slot icon=icondata::AiAreaChartOutlined>
18+
"Area Chart"
19+
</NavCategoryItem>
20+
<NavSubItem value="target">
21+
"Target"
22+
</NavSubItem>
23+
<NavSubItem value="above">
24+
"Above"
25+
</NavSubItem>
26+
<NavSubItem value="below">
27+
"Below"
28+
</NavSubItem>
29+
</NavCategory>
30+
<NavCategory value="pie">
31+
<NavCategoryItem slot icon=icondata::AiPieChartOutlined>
32+
"Pie Chart"
33+
</NavCategoryItem>
34+
<NavSubItem value="pie-target">
35+
"Pie Target"
36+
</NavSubItem>
37+
<NavSubItem value="pin-above">
38+
"Pin Above"
39+
</NavSubItem>
40+
<NavSubItem value="pin-below">
41+
"Pin Below"
42+
</NavSubItem>
43+
</NavCategory>
44+
<NavItem
45+
icon=icondata::AiGithubOutlined
46+
value="github"
47+
href="https://github.com/thaw-ui/thaw"
48+
attr:target="_blank"
49+
>
50+
"Github"
51+
</NavItem>
52+
<NavItem icon=icondata::AiChromeOutlined value="chrome">
53+
"Chrome"
54+
</NavItem>
55+
</NavDrawer>
56+
<div>
57+
<Switch checked=is_multiple label=is_multiple_label/>
58+
</div>
59+
</Flex>
4760
}
4861
```
4962

@@ -54,6 +67,8 @@ view! {
5467
| class | `MaybeProp<String>,` | `Default::default()` | |
5568
| selected_value | `OptionModel<String>` | `Default::default()` | The value of the currently selected navItem. |
5669
| selected_category_value | `OptionModel<String>` | `None` | Indicates a category that has a selected child Will show the category as selected if it is closed. |
70+
| open_categories | `Model<Vec<String>>` | `vec![]` | Controls the open categories. |
71+
| multiple | `Signal<bool>` | `true` | Indicates if NavDrawer supports multiple open Categories at the same time. |
5772
| nav_drawer_header | slot `Option<NavDrawerHeader>` | `None` | |
5873
| nav_drawer_footer | slot `Option<NavDrawerFooter>` | `None` | |
5974
| children | `Children` | | |

thaw/src/nav/nav_category.rs

+15-7
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@ pub fn NavCategory(
1111
nav_category_item: NavCategoryItem,
1212
) -> impl IntoView {
1313
let nav_drawer = NavDrawerInjection::expect_context();
14-
let is_show_group = RwSignal::new(false);
14+
let open = Memo::new(move |_| {
15+
value.with(|value| {
16+
nav_drawer
17+
.open_categories
18+
.with(|open_categories| open_categories.contains(value))
19+
})
20+
});
1521
let is_selected_category =
1622
Memo::new(move |_| value.with(|value| nav_drawer.is_selected_category(value)));
1723

@@ -21,17 +27,19 @@ pub fn NavCategory(
2127
children: item_children,
2228
} = nav_category_item;
2329

30+
let on_nav_category_item_click = move |_| {
31+
nav_drawer.on_request_nav_category_item_toggle(value.get_untracked());
32+
};
33+
2434
view! {
2535
<button
2636
class=class_list![
2737
"thaw-nav-category-item",
2838
("thaw-nav-category-item--selected", move || is_selected_category.get()),
2939
item_class
3040
]
31-
on:click=move |_| {
32-
is_show_group.update(|show| *show = !*show);
33-
}
34-
aria-expanded=move || if is_show_group.get() { "true" } else { "false" }
41+
on:click=on_nav_category_item_click
42+
aria-expanded=move || if open.get() { "true" } else { "false" }
3543
>
3644
{move || {
3745
if let Some(icon) = item_icon.get() {
@@ -49,7 +57,7 @@ pub fn NavCategory(
4957
height="20"
5058
viewBox="0 0 20 20"
5159
style=move || {
52-
if is_show_group.get() {
60+
if open.get() {
5361
"transform: rotate(90deg)"
5462
} else {
5563
"transform: rotate(0deg)"
@@ -63,7 +71,7 @@ pub fn NavCategory(
6371
</svg>
6472
</span>
6573
</button>
66-
<CSSTransition show=is_show_group name="thaw-nav-sub-item-group">
74+
<CSSTransition show=open name="thaw-nav-sub-item-group">
6775
<div class="thaw-nav-sub-item-group">
6876
<Provider value=NavCategoryInjection { value }>{children()}</Provider>
6977
</div>

thaw/src/nav/nav_drawer.rs

+30-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::Scrollbar;
22
use leptos::{context::Provider, prelude::*};
33
use thaw_components::OptionComp;
4-
use thaw_utils::{class_list, mount_style, OptionModel, OptionModelWithValue};
4+
use thaw_utils::{class_list, mount_style, Model, OptionModel, OptionModelWithValue};
55

66
#[component]
77
pub fn NavDrawer(
@@ -12,6 +12,12 @@ pub fn NavDrawer(
1212
/// Indicates a category that has a selected child Will show the category as selected if it is closed.
1313
#[prop(optional, into)]
1414
selected_category_value: OptionModel<String>,
15+
/// Controls the open categories.
16+
#[prop(optional, into)]
17+
open_categories: Model<Vec<String>>,
18+
/// Indicates if NavDrawer supports multiple open Categories at the same time.
19+
#[prop(default = true.into(), into)]
20+
multiple: Signal<bool>,
1521
children: Children,
1622
#[prop(optional)] nav_drawer_header: Option<NavDrawerHeader>,
1723
#[prop(optional)] nav_drawer_footer: Option<NavDrawerFooter>,
@@ -22,6 +28,8 @@ pub fn NavDrawer(
2228
<Provider value=NavDrawerInjection {
2329
selected_value,
2430
selected_category_value,
31+
open_categories,
32+
multiple,
2533
}>
2634
<div class=class_list!["thaw-nav-drawer", class]>
2735
<OptionComp value=nav_drawer_header let:header>
@@ -48,10 +56,12 @@ pub struct NavDrawerFooter {
4856
children: Children,
4957
}
5058

51-
#[derive(Clone)]
59+
#[derive(Clone, Copy)]
5260
pub(crate) struct NavDrawerInjection {
5361
pub selected_value: OptionModel<String>,
5462
pub selected_category_value: OptionModel<String>,
63+
pub open_categories: Model<Vec<String>>,
64+
multiple: Signal<bool>,
5565
}
5666

5767
impl NavDrawerInjection {
@@ -66,4 +76,22 @@ impl NavDrawerInjection {
6676
OptionModelWithValue::Option(v) => v.as_ref() == Some(value),
6777
})
6878
}
79+
80+
pub fn on_request_nav_category_item_toggle(&self, category_value: String) {
81+
self.open_categories.update(move |open_categories| {
82+
if self.multiple.get_untracked() {
83+
if let Some(index) = open_categories.iter().position(|v| v == &category_value) {
84+
open_categories.remove(index);
85+
} else {
86+
open_categories.push(category_value);
87+
}
88+
} else {
89+
if open_categories.first() == Some(&category_value) {
90+
open_categories.clear();
91+
} else {
92+
*open_categories = vec![category_value];
93+
}
94+
}
95+
});
96+
}
6997
}

0 commit comments

Comments
 (0)