freya_components/
sidebar.rs1use freya_core::prelude::*;
2use torin::{
3 gaps::Gaps,
4 size::Size,
5};
6
7use crate::{
8 activable_route_context::use_activable_route,
9 define_theme,
10 get_theme,
11};
12
13define_theme! {
14 %[component]
15 pub SideBarItem {
16 %[fields]
17 color: Color,
18 background: Color,
19 hover_background: Color,
20 active_background: Color,
21 corner_radius: CornerRadius,
22 margin: Gaps,
23 padding: Gaps,
24 }
25}
26
27#[derive(Debug, Default, PartialEq, Clone, Copy)]
28pub enum SideBarItemStatus {
29 #[default]
31 Idle,
32 Hovering,
34}
35
36#[derive(Clone, PartialEq)]
71pub struct SideBarItem {
72 pub(crate) theme: Option<SideBarItemThemePartial>,
74 children: Vec<Element>,
76 on_press: Option<EventHandler<Event<PressEventData>>>,
78 overflow: Overflow,
80 key: DiffKey,
81}
82
83impl KeyExt for SideBarItem {
84 fn write_key(&mut self) -> &mut DiffKey {
85 &mut self.key
86 }
87}
88
89impl Default for SideBarItem {
90 fn default() -> Self {
91 Self::new()
92 }
93}
94
95impl ChildrenExt for SideBarItem {
96 fn get_children(&mut self) -> &mut Vec<Element> {
97 &mut self.children
98 }
99}
100
101impl SideBarItem {
102 pub fn new() -> Self {
103 Self {
104 theme: None,
105 children: Vec::new(),
106 on_press: None,
107 overflow: Overflow::Clip,
108 key: DiffKey::None,
109 }
110 }
111
112 pub fn on_press(mut self, on_press: impl Into<EventHandler<Event<PressEventData>>>) -> Self {
113 self.on_press = Some(on_press.into());
114 self
115 }
116
117 pub fn overflow(mut self, overflow: impl Into<Overflow>) -> Self {
118 self.overflow = overflow.into();
119 self
120 }
121
122 pub fn get_theme(&self) -> Option<&SideBarItemThemePartial> {
124 self.theme.as_ref()
125 }
126
127 pub fn theme(mut self, theme: SideBarItemThemePartial) -> Self {
129 self.theme = Some(theme);
130 self
131 }
132}
133
134impl Component for SideBarItem {
135 fn render(&self) -> impl IntoElement {
136 let SideBarItemTheme {
137 margin,
138 hover_background,
139 active_background,
140 background,
141 corner_radius,
142 padding,
143 color,
144 } = get_theme!(&self.theme, SideBarItemThemePreference, "sidebar_item");
145 let mut status = use_state(SideBarItemStatus::default);
146 let is_active = use_activable_route();
147
148 let on_pointer_enter = move |_| {
149 status.set(SideBarItemStatus::Hovering);
150 };
151
152 let on_pointer_leave = move |_| {
153 status.set(SideBarItemStatus::default());
154 };
155
156 let background = match *status.read() {
157 _ if is_active => active_background,
158 SideBarItemStatus::Hovering => hover_background,
159 SideBarItemStatus::Idle => background,
160 };
161
162 rect()
163 .a11y_focusable(true)
164 .a11y_role(AccessibilityRole::Link)
165 .map(self.on_press.clone(), |rect, on_press| {
166 rect.on_press(on_press)
167 })
168 .on_pointer_enter(on_pointer_enter)
169 .on_pointer_leave(on_pointer_leave)
170 .overflow(self.overflow)
171 .width(Size::fill())
172 .margin(margin)
173 .padding(padding)
174 .color(color)
175 .background(background)
176 .corner_radius(corner_radius)
177 .children(self.children.clone())
178 }
179
180 fn render_key(&self) -> DiffKey {
181 self.key.clone().or(self.default_key())
182 }
183}