pub mod group;
pub use group::{SidebarMenu, SidebarMenuProps};
use dioxus::prelude::*;
use crate::badge::{Badge, BadgeVariant};
use crate::icon::{Icon, IconKind, RenderSvgIcon, SvgIcon};
#[derive(Props, Clone, PartialEq)]
pub struct NavLinkProps {
pub label: String,
#[props(default)]
pub description: Option<String>,
#[props(default)]
pub icon: Option<SvgIcon>,
#[props(default)]
pub active: bool,
#[props(default)]
pub href: Option<String>,
#[props(default)]
pub on_click: Option<EventHandler<MouseEvent>>,
#[props(default)]
pub badge: Option<String>,
#[props(default)]
pub badge_variant: Option<BadgeVariant>,
#[props(default)]
pub opened: Option<Signal<bool>>,
#[props(default)]
pub default_opened: bool,
#[props(default)]
pub disabled: bool,
#[props(default)]
pub class: String,
#[props(default)]
pub children: Option<Element>,
}
#[component]
pub fn NavLink(props: NavLinkProps) -> Element {
let mut local_opened = use_signal(|| props.default_opened);
let has_children = props.children.is_some();
let is_open = props.opened.map(|sig| sig()).unwrap_or(local_opened());
let opened_sig = props.opened;
let mut toggle_open = move || {
if let Some(mut sig) = opened_sig {
sig.set(!is_open);
} else {
local_opened.set(!is_open);
}
};
#[cfg(feature = "theme")]
let theme_val = crate::theme::use_theme()();
#[cfg(feature = "theme")]
let base_override = theme_val.resolve_component_base("nav_link").unwrap_or("");
#[cfg(feature = "theme")]
let class_modifiers = theme_val.resolve_class_modifiers("nav_link", &props.class);
#[cfg(not(feature = "theme"))]
let base_override = "";
#[cfg(not(feature = "theme"))]
let class_modifiers = String::new();
let active_class = if props.active { "sd-nav-link--active" } else { "" };
let disabled_class = if props.disabled { "sd-nav-link--disabled" } else { "" };
let open_class = if is_open { "sd-nav-link--open" } else { "" };
let icon_el = if let Some(ref ic) = props.icon {
rsx! {
span { class: "sd-nav-link__icon",
RenderSvgIcon { icon: ic.clone(), size: 16 }
}
}
} else {
rsx! {}
};
let badge_el = if let Some(ref b) = props.badge {
let variant = props.badge_variant.unwrap_or(BadgeVariant::Default);
rsx! {
span { class: "sd-nav-link__badge",
Badge {
label: b.clone(),
variant: variant,
pill: true,
}
}
}
} else {
rsx! {}
};
let chevron_el = if has_children {
rsx! {
span {
class: if is_open { "sd-nav-link__chevron sd-nav-link__chevron--open" } else { "sd-nav-link__chevron" },
Icon { kind: IconKind::ChevronRight, size: 14 }
}
}
} else {
rsx! {}
};
let actions_el = if props.badge.is_some() || has_children {
rsx! {
span { class: "sd-nav-link__actions",
{badge_el}
{chevron_el}
}
}
} else {
rsx! {}
};
let main_content = rsx! {
span { class: "sd-nav-link__indicator", "aria-hidden": "true" }
{icon_el}
span { class: "sd-nav-link__body",
span { class: "sd-nav-link__label", "{props.label}" }
if let Some(ref desc) = props.description {
span { class: "sd-nav-link__description", "{desc}" }
}
}
{actions_el}
};
let interactive_item = if let Some(ref href) = props.href {
rsx! {
a {
class: "sd-nav-link__item",
href: "{href}",
"aria-current": if props.active { "page" } else { "" },
onclick: move |evt| {
if has_children {
toggle_open();
}
if let Some(ref handler) = props.on_click {
handler.call(evt);
}
},
{main_content}
}
}
} else {
rsx! {
button {
r#type: "button",
class: "sd-nav-link__item sd-nav-link__item--button",
disabled: props.disabled,
"aria-current": if props.active { "page" } else { "" },
onclick: move |evt| {
if has_children {
toggle_open();
}
if let Some(ref handler) = props.on_click {
handler.call(evt);
}
},
{main_content}
}
}
};
rsx! {
div {
class: "sd-nav-link {active_class} {disabled_class} {open_class} {base_override} {class_modifiers} {props.class}",
{interactive_item}
if has_children && is_open {
div { class: "sd-nav-link__children",
{props.children}
}
}
}
}
}