use freya_core::prelude::*;
use torin::{
gaps::Gaps,
size::Size,
};
use crate::{
activable_context::use_is_active,
define_theme,
get_theme,
};
define_theme! {
%[component]
pub SideBarItem {
%[fields]
color: Color,
background: Color,
hover_background: Color,
active_background: Color,
focus_border_fill: Color,
corner_radius: CornerRadius,
margin: Gaps,
padding: Gaps,
}
}
#[derive(Debug, Default, PartialEq, Clone, Copy)]
pub enum SideBarItemStatus {
#[default]
Idle,
Hovering,
}
#[derive(Clone, PartialEq)]
pub struct SideBarItem {
pub(crate) theme: Option<SideBarItemThemePartial>,
children: Vec<Element>,
on_press: Option<EventHandler<Event<PressEventData>>>,
overflow: Overflow,
key: DiffKey,
}
impl KeyExt for SideBarItem {
fn write_key(&mut self) -> &mut DiffKey {
&mut self.key
}
}
impl Default for SideBarItem {
fn default() -> Self {
Self::new()
}
}
impl ChildrenExt for SideBarItem {
fn get_children(&mut self) -> &mut Vec<Element> {
&mut self.children
}
}
impl SideBarItem {
pub fn new() -> Self {
Self {
theme: None,
children: Vec::new(),
on_press: None,
overflow: Overflow::Clip,
key: DiffKey::None,
}
}
pub fn on_press(mut self, on_press: impl Into<EventHandler<Event<PressEventData>>>) -> Self {
self.on_press = Some(on_press.into());
self
}
pub fn overflow(mut self, overflow: impl Into<Overflow>) -> Self {
self.overflow = overflow.into();
self
}
pub fn get_theme(&self) -> Option<&SideBarItemThemePartial> {
self.theme.as_ref()
}
pub fn theme(mut self, theme: SideBarItemThemePartial) -> Self {
self.theme = Some(theme);
self
}
}
impl Component for SideBarItem {
fn render(&self) -> impl IntoElement {
let SideBarItemTheme {
margin,
hover_background,
active_background,
background,
focus_border_fill,
corner_radius,
padding,
color,
} = get_theme!(&self.theme, SideBarItemThemePreference, "sidebar_item");
let mut status = use_state(SideBarItemStatus::default);
let is_active = use_is_active();
let a11y_id = use_a11y();
let focus = use_focus(a11y_id);
let on_pointer_enter = move |_| {
status.set(SideBarItemStatus::Hovering);
};
let on_pointer_leave = move |_| {
status.set(SideBarItemStatus::default());
};
let background = match *status.read() {
_ if is_active => active_background,
SideBarItemStatus::Hovering => hover_background,
SideBarItemStatus::Idle => background,
};
let border = (focus() == Focus::Keyboard).then(|| {
Border::new()
.fill(focus_border_fill)
.width(2.)
.alignment(BorderAlignment::Inner)
});
let on_press = self.on_press.clone();
rect()
.a11y_id(a11y_id)
.a11y_focusable(true)
.a11y_role(AccessibilityRole::Link)
.on_press(move |e: Event<PressEventData>| {
if let Some(handler) = &on_press {
handler.call(e);
}
})
.on_pointer_enter(on_pointer_enter)
.on_pointer_leave(on_pointer_leave)
.overflow(self.overflow)
.width(Size::fill())
.margin(margin)
.padding(padding)
.color(color)
.background(background)
.corner_radius(corner_radius)
.map(border, |rect, border| rect.border(border))
.children(self.children.clone())
}
fn render_key(&self) -> DiffKey {
self.key.clone().or(self.default_key())
}
}