fix: NavDrawer selected category value error (#252)

This commit is contained in:
luoxiaozero 2024-09-08 23:07:14 +08:00 committed by GitHub
parent 583b03100e
commit f9d39f740c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 46 additions and 63 deletions

View file

@ -53,7 +53,7 @@ view! {
| --- | --- | --- | --- | | --- | --- | --- | --- |
| class | `MaybeProp<String>,` | `Default::default()` | | | class | `MaybeProp<String>,` | `Default::default()` | |
| selected_value | `OptionModel<String>` | `Default::default()` | The value of the currently selected navItem. | | selected_value | `OptionModel<String>` | `Default::default()` | The value of the currently selected navItem. |
| selected_category_value | `VecModel<String>` | `vec![]` | Indicates a category that has a selected child Will show the category as selected if it is closed. | | selected_category_value | `OptionModel<String>` | `None` | Indicates a category that has a selected child Will show the category as selected if it is closed. |
| nav_drawer_header | slot `Option<NavDrawerHeader>` | `None` | | | nav_drawer_header | slot `Option<NavDrawerHeader>` | `None` | |
| nav_drawer_footer | slot `Option<NavDrawerFooter>` | `None` | | | nav_drawer_footer | slot `Option<NavDrawerFooter>` | `None` | |
| children | `Children` | | | | children | `Children` | | |

View file

@ -69,7 +69,8 @@
background-color: var(--colorNeutralBackground4Pressed); background-color: var(--colorNeutralBackground4Pressed);
} }
.thaw-nav-item--selected::after { .thaw-nav-item--selected::after,
.thaw-nav-category-item--selected[aria-expanded="false"]::after {
content: ""; content: "";
position: absolute; position: absolute;
width: 4px; width: 4px;

View file

@ -1,8 +1,8 @@
use super::NavDrawerInjection; use super::NavDrawerInjection;
use crate::Icon; use crate::Icon;
use leptos::{either::Either, html, prelude::*}; use leptos::{context::Provider, either::Either, html, prelude::*};
use thaw_components::CSSTransition; use thaw_components::CSSTransition;
use thaw_utils::{class_list, StoredMaybeSignal, VecModelWithValue}; use thaw_utils::{class_list, StoredMaybeSignal};
#[component] #[component]
pub fn NavCategory( pub fn NavCategory(
@ -13,56 +13,9 @@ pub fn NavCategory(
let nav_drawer = NavDrawerInjection::expect_context(); let nav_drawer = NavDrawerInjection::expect_context();
let value: StoredMaybeSignal<_> = value.into(); let value: StoredMaybeSignal<_> = value.into();
let group_ref = NodeRef::<html::Div>::new(); let group_ref = NodeRef::<html::Div>::new();
let is_show_group = Memo::new(move |_| { let is_show_group = RwSignal::new(false);
nav_drawer let is_selected_category =
.selected_category_value Memo::new(move |_| value.with(|value| nav_drawer.is_selected_category(value)));
.with(|selected_category_value| {
value.with(|value| match selected_category_value {
VecModelWithValue::T(v) => v == value,
VecModelWithValue::Option(v) => v.as_ref() == Some(value),
VecModelWithValue::Vec(v) => v.contains(value),
})
})
});
let on_click = move |_| {
let value = value.get_untracked();
let is_show_group = is_show_group.get_untracked();
nav_drawer
.selected_category_value
.update(|selected_category_value| {
match selected_category_value {
(None, None, Some(v)) => {
if is_show_group {
if let Some(index) = v.iter().position(|item| item == &value) {
v.remove(index);
}
} else {
v.push(value);
}
}
(None, Some(v), None) => {
if is_show_group {
*v = None;
} else {
*v = Some(value);
}
}
(Some(v), None, None) => {
if is_show_group {
v.clear();
} else {
*v = value;
}
}
_ => unreachable!(),
}
if is_show_group {
} else {
}
});
};
let NavCategoryItem { let NavCategoryItem {
class: item_class, class: item_class,
@ -72,9 +25,13 @@ pub fn NavCategory(
view! { view! {
<button <button
class=class_list!["thaw-nav-category-item", item_class] class=class_list![
on:click=on_click "thaw-nav-category-item",
aria-expanded=move || is_show_group.get() ("thaw-nav-category-item--selected", move || is_selected_category.get()),
item_class
]
on:click=move |_| { is_show_group.update(|show| *show = !*show); }
aria-expanded=move || if is_show_group.get() { "true" } else { "false" }
> >
{move || { {move || {
if let Some(icon) = item_icon.get() { if let Some(icon) = item_icon.get() {
@ -117,7 +74,9 @@ pub fn NavCategory(
node_ref=group_ref node_ref=group_ref
style=move || display.get().unwrap_or_default() style=move || display.get().unwrap_or_default()
> >
<Provider value=NavCategoryInjection { value }>
{children()} {children()}
</Provider>
</div> </div>
</CSSTransition> </CSSTransition>
} }
@ -131,3 +90,14 @@ pub struct NavCategoryItem {
icon: MaybeProp<icondata_core::Icon>, icon: MaybeProp<icondata_core::Icon>,
children: Children, children: Children,
} }
#[derive(Clone, Copy)]
pub(crate) struct NavCategoryInjection {
pub value: StoredMaybeSignal<String>,
}
impl NavCategoryInjection {
pub fn use_context() -> Option<Self> {
use_context()
}
}

View file

@ -1,7 +1,7 @@
use crate::Scrollbar; use crate::Scrollbar;
use leptos::{context::Provider, prelude::*}; use leptos::{context::Provider, prelude::*};
use thaw_components::OptionComp; use thaw_components::OptionComp;
use thaw_utils::{class_list, mount_style, OptionModel, VecModel}; use thaw_utils::{class_list, mount_style, OptionModel, OptionModelWithValue};
#[component] #[component]
pub fn NavDrawer( pub fn NavDrawer(
@ -10,8 +10,8 @@ pub fn NavDrawer(
#[prop(optional, into)] #[prop(optional, into)]
selected_value: OptionModel<String>, selected_value: OptionModel<String>,
/// Indicates a category that has a selected child Will show the category as selected if it is closed. /// Indicates a category that has a selected child Will show the category as selected if it is closed.
#[prop(default = vec![].into(), into)] #[prop(optional, into)]
selected_category_value: VecModel<String>, selected_category_value: OptionModel<String>,
children: Children, children: Children,
#[prop(optional)] nav_drawer_header: Option<NavDrawerHeader>, #[prop(optional)] nav_drawer_header: Option<NavDrawerHeader>,
#[prop(optional)] nav_drawer_footer: Option<NavDrawerFooter>, #[prop(optional)] nav_drawer_footer: Option<NavDrawerFooter>,
@ -51,11 +51,19 @@ pub struct NavDrawerFooter {
#[derive(Clone)] #[derive(Clone)]
pub(crate) struct NavDrawerInjection { pub(crate) struct NavDrawerInjection {
pub selected_value: OptionModel<String>, pub selected_value: OptionModel<String>,
pub selected_category_value: VecModel<String>, pub selected_category_value: OptionModel<String>,
} }
impl NavDrawerInjection { impl NavDrawerInjection {
pub fn expect_context() -> Self { pub fn expect_context() -> Self {
expect_context() expect_context()
} }
pub fn is_selected_category(&self, value: &String) -> bool {
self.selected_category_value
.with(|selected_category_value| match selected_category_value {
OptionModelWithValue::T(v) => v == value,
OptionModelWithValue::Option(v) => v.as_ref() == Some(value),
})
}
} }

View file

@ -1,4 +1,4 @@
use super::NavDrawerInjection; use super::{NavCategoryInjection, NavDrawerInjection};
use crate::Icon; use crate::Icon;
use leptos::{either::Either, prelude::*}; use leptos::{either::Either, prelude::*};
use thaw_utils::{class_list, OptionModelWithValue, StoredMaybeSignal}; use thaw_utils::{class_list, OptionModelWithValue, StoredMaybeSignal};
@ -12,6 +12,7 @@ pub fn NavItem(
children: Children, children: Children,
) -> impl IntoView { ) -> impl IntoView {
let nav_drawer = NavDrawerInjection::expect_context(); let nav_drawer = NavDrawerInjection::expect_context();
let nav_category = NavCategoryInjection::use_context();
let value: StoredMaybeSignal<_> = value.into(); let value: StoredMaybeSignal<_> = value.into();
let on_click = move |_| { let on_click = move |_| {
let value = value.get_untracked(); let value = value.get_untracked();
@ -23,6 +24,9 @@ pub fn NavItem(
}) })
{ {
nav_drawer.selected_value.set(Some(value)); nav_drawer.selected_value.set(Some(value));
nav_drawer
.selected_category_value
.set(nav_category.map(|c| c.value.get_untracked()));
} }
}; };