accordion_rs/dioxus.rs
1use crate::common::{Align, Size};
2use dioxus::prelude::*;
3
4/// Properties for the Accordion component.
5#[derive(Props, PartialEq, Clone)]
6pub struct AccordionProps {
7 /// A signal that manages the expansion state of the accordion.
8 ///
9 /// This property determines whether the accordion is expanded (`true`) or collapsed (`false`).
10 /// It is required and is used to toggle the accordion's state.
11 pub expand: Signal<bool>,
12
13 /// The content to display when the accordion is expanded.
14 ///
15 /// This content will be visible only when the accordion is in an expanded state.
16 pub expanded: Element,
17
18 /// The content to display when the accordion is collapsed.
19 ///
20 /// This content will be visible only when the accordion is in a collapsed state.
21 pub collapsed: Element,
22
23 /// The child elements to display within the accordion container.
24 ///
25 /// Any additional content provided as children will be rendered inside the accordion body.
26 pub children: Element,
27
28 /// Size of the accordion.
29 ///
30 /// Defines the size of the accordion component. Typically used for layout adjustments.
31 /// Defaults to an `XXLarge` if not specified.
32 #[props(default)]
33 pub size: Size,
34
35 /// ARIA controls attribute for accessibility.
36 ///
37 /// Links the accordion container to another element, improving accessibility for screen readers.
38 /// Defaults to an empty string.
39 #[props(default = "")]
40 pub aria_controls: &'static str,
41
42 /// Custom inline styles for the accordion container.
43 ///
44 /// Specifies additional CSS styling for the accordion's container. Defaults to an empty string.
45 #[props(default = "")]
46 pub style: &'static str,
47
48 /// Custom inline styles for the expanded state.
49 ///
50 /// Defines additional styling for the accordion when it is expanded. Defaults to an empty string.
51 #[props(default = "")]
52 pub expanded_style: &'static str,
53
54 /// Custom inline styles for the collapsed state.
55 ///
56 /// Defines additional styling for the accordion when it is collapsed. Defaults to an empty string.
57 #[props(default = "")]
58 pub collapsed_style: &'static str,
59
60 /// Custom inline styles for the content section.
61 ///
62 /// Specifies additional styling for the content within the accordion. Defaults to an empty string.
63 #[props(default = "")]
64 pub content_style: &'static str,
65
66 /// Custom CSS class for the accordion container.
67 ///
68 /// Applies a custom class to the container element for styling purposes. Defaults to an empty string.
69 #[props(default = "")]
70 pub class: &'static str,
71
72 /// Custom CSS class for the expanded state.
73 ///
74 /// Specifies a class that is applied to the accordion when it is in an expanded state. Defaults to an empty string.
75 #[props(default = "")]
76 pub expanded_class: &'static str,
77
78 /// Custom CSS class for the collapsed state.
79 ///
80 /// Specifies a class that is applied to the accordion when it is in a collapsed state. Defaults to an empty string.
81 #[props(default = "")]
82 pub collapsed_class: &'static str,
83
84 /// Custom CSS class for the content container.
85 ///
86 /// Applies a class to the accordion's content container for styling purposes. Defaults to an empty string.
87 #[props(default = "")]
88 pub content_class: &'static str,
89
90 /// Indicates whether ARIA attributes should be included.
91 ///
92 /// If `true`, ARIA attributes such as `aria-expanded` and `aria-controls` will be added for accessibility.
93 /// Defaults to `true`.
94 #[props(default = true)]
95 pub aria_enabled: bool,
96
97 /// Duration of the expand/collapse animation in milliseconds.
98 ///
99 /// Specifies how long the transition animation should take. Defaults to `600` milliseconds.
100 #[props(default = 600)]
101 pub duration: u64,
102
103 /// Callback executed before the accordion expands.
104 ///
105 /// This callback is triggered just before the accordion transitions to an expanded state.
106 /// Defaults to a no-op.
107 #[props(default)]
108 pub will_open: Callback<()>,
109
110 /// Callback executed after the accordion has expanded.
111 ///
112 /// This callback is triggered once the accordion has completed its transition to an expanded state.
113 /// Defaults to a no-op.
114 #[props(default)]
115 pub did_open: Callback<()>,
116
117 /// Callback executed before the accordion collapses.
118 ///
119 /// This callback is triggered just before the accordion transitions to a collapsed state.
120 /// Defaults to a no-op.
121 #[props(default)]
122 pub will_close: Callback<()>,
123
124 /// Callback executed after the accordion has collapsed.
125 ///
126 /// This callback is triggered once the accordion has completed its transition to a collapsed state.
127 /// Defaults to a no-op.
128 #[props(default)]
129 pub did_close: Callback<()>,
130}
131
132/// Accordion Component
133///
134/// A Dioxus component for creating collapsible accordion sections. This component allows you
135/// to toggle between expanded and collapsed views with smooth animations, and supports customization
136/// through various properties like size, style, and callbacks.
137///
138/// # Properties
139/// The component uses the `AccordionProps` struct for configuration. Key properties include:
140///
141/// - **expand**: A `Signal<bool>` that controls the expansion state of the accordion. It is required to toggle between expanded and collapsed states.
142/// - **expanded**: The content that is displayed when the accordion is expanded (`Element`). Default: `""`.
143/// - **collapsed**: The content that is displayed when the accordion is collapsed (`Element`). Default: `""`.
144/// - **children**: The child elements to display inside the accordion when expanded (`Element`). Default: `""`.
145/// - **size**: Defines the size of the accordion (`Size`). Default: `Size::XXLarge`.
146/// - **aria_controls**: The ARIA controls attribute for accessibility (`&'static str`). Default: `""`.
147/// - **style**: Inline styles for the accordion container (`&'static str`). Default: `""`.
148/// - **expanded_style**: Inline styles for the expanded content (`&'static str`). Default: `""`.
149/// - **collapsed_style**: Inline styles for the collapsed content (`&'static str`). Default: `""`.
150/// - **content_style**: Inline styles for the content section (`&'static str`). Default: `""`.
151/// - **class**: Custom CSS class for the accordion container (`&'static str`). Default: `""`.
152/// - **expanded_class**: Custom CSS class for the expanded content (`&'static str`). Default: `""`.
153/// - **collapsed_class**: Custom CSS class for the collapsed content (`&'static str`). Default: `""`.
154/// - **content_class**: Custom CSS class for the content section (`&'static str`). Default: `""`.
155/// - **aria_enabled**: If `true`, ARIA attributes will be added to the HTML structure for better accessibility (`bool`). Default: `true`.
156/// - **duration**: Duration of the expand/collapse animation in milliseconds (`u64`). Default: `600`.
157/// - **will_open**: Callback invoked before the accordion expands (`Callback<()>`). Default: no-op.
158/// - **did_open**: Callback invoked after the accordion has expanded (`Callback<()>`). Default: no-op.
159/// - **will_close**: Callback invoked before the accordion collapses (`Callback<()>`). Default: no-op.
160/// - **did_close**: Callback invoked after the accordion has collapsed (`Callback<()>`). Default: no-op.
161///
162/// # Features
163/// - Smooth transitions between expanded and collapsed states with configurable duration.
164/// - Supports ARIA attributes for accessibility.
165/// - Customizable styles and classes for each section of the accordion.
166/// - Optional callbacks for pre- and post-expansion and collapse events.
167///
168/// # Examples
169///
170/// ## Basic Accordion
171/// ```rust
172/// use dioxus::prelude::*;
173/// use accordion_rs::dioxus::Accordion;
174/// use accordion_rs::Size;
175///
176/// fn App() -> Element {
177/// let expand_signal = use_signal(|| false);
178///
179/// rsx! {
180/// Accordion {
181/// expand: expand_signal.clone(),
182/// expanded: rsx! {p { "This is the expanded content" }},
183/// collapsed: rsx! {p { "This is the collapsed content" }},
184/// size: Size::Medium,
185/// }
186/// }
187/// }
188/// ```
189///
190/// ## Accordion with Custom Styles
191/// ```rust
192/// use dioxus::prelude::*;
193/// use accordion_rs::dioxus::Accordion;
194///
195/// fn App() -> Element {
196/// let expand_signal = use_signal(|| false);
197///
198/// rsx! {
199/// Accordion {
200/// expand: expand_signal.clone(),
201/// expanded: rsx! { p{ "Expanded content goes here" }},
202/// collapsed: rsx! { p{ "Collapsed content here" }},
203/// expanded_style: "background-color: lightblue;",
204/// collapsed_style: "background-color: lightgray;",
205/// }
206/// }
207/// }
208/// ```
209///
210/// ## Accordion with Callbacks
211/// ```rust
212/// use dioxus::prelude::*;
213/// use accordion_rs::dioxus::Accordion;
214///
215/// fn App() -> Element {
216/// let expand_signal = use_signal(|| false);
217///
218/// rsx! {
219/// Accordion {
220/// expand: expand_signal.clone(),
221/// expanded: rsx! { p{ "Expanded content" }},
222/// collapsed: rsx! { p{ "Collapsed content" }},
223/// will_open: |_| println!("Accordion will open!"),
224/// did_open: |_| println!("Accordion opened!"),
225/// will_close: |_| println!("Accordion will close!"),
226/// did_close: |_| println!("Accordion closed!"),
227/// }
228/// }
229/// }
230/// ```
231#[component]
232pub fn Accordion(mut props: AccordionProps) -> Element {
233 let toggle_expansion = {
234 move |_| {
235 if (props.expand)() {
236 props.will_close.call(());
237 props.expand.set(false);
238 props.did_close.call(());
239 } else {
240 props.will_open.call(());
241 props.expand.set(true);
242 props.did_open.call(());
243 }
244 }
245 };
246
247 rsx! {
248 div {
249 class: "{props.class}",
250 style: "{props.size.to_style()} {props.style}",
251 div {
252 class: {if (props.expand)() {
253 props.expanded_class
254 } else {
255 props.collapsed_class
256 }},
257 style: {format!(
258 "cursor: pointer; transition: all {}ms; {}",
259 props.duration,
260 if (props.expand)() {
261 props.expanded_style
262 } else {
263 props.collapsed_style
264 }
265 )},
266 aria_expanded: if props.aria_enabled { Some((props.expand)().to_string()) } else { None },
267 aria_controls: if props.aria_enabled { Some(props.aria_controls) } else { None },
268 onclick: toggle_expansion,
269 if (props.expand)() {
270 {props.expanded}
271 } else {
272 {props.collapsed}
273 }
274 },
275 if (props.expand)() {
276 div {
277 id: "{props.aria_controls}",
278 class: "{props.content_class}",
279 style: "overflow: hidden; transition: all {props.duration}ms; {props.content_style}",
280 {props.children}
281 }
282 }
283 }
284 }
285}
286
287#[derive(Props, PartialEq, Clone)]
288pub struct ItemProps {
289 /// The child elements of the item.
290 ///
291 /// These elements will be rendered inside the item container.
292 pub children: Element,
293
294 /// The inline style for the item container.
295 ///
296 /// Defaults to an empty string.
297 #[props(default = "")]
298 pub style: &'static str,
299
300 /// The CSS class for the item container.
301 ///
302 /// Defaults to an empty string.
303 #[props(default = "")]
304 pub class: &'static str,
305
306 /// The alignment of the item content.
307 ///
308 /// Specifies how the content of the item should be aligned (e.g., `Align::Left`, `Align::Center`, etc.).
309 /// Defaults to `Align::Left`.
310 #[props(default)]
311 pub align: Align,
312
313 /// The title text for the item.
314 ///
315 /// This text typically appears as a header or label for the item.
316 /// Defaults to an empty string.
317 #[props(default = "")]
318 pub title: &'static str,
319
320 /// The icon associated with the item.
321 ///
322 /// This can be a URL to an image or an icon class name.
323 /// Defaults to an empty string.
324 #[props(default = "")]
325 pub icon: &'static str,
326}
327
328#[component]
329pub fn Item(props: ItemProps) -> Element {
330 rsx! {
331 li {
332 class: "{props.class}",
333 style: "{props.align.to_style()} {props.style}",
334 if !props.icon.is_empty() {
335 span { class: "mr-2", "{props.icon}" }
336 }
337 if !props.title.is_empty() {
338 strong { "{props.title}" }
339 }
340 {props.children}
341 }
342 }
343}
344
345#[derive(Props, PartialEq, Clone)]
346pub struct ButtonProps {
347 /// The child elements or text content of the button.
348 ///
349 /// This defines the content that will appear inside the button, such as text or other elements.
350 pub children: Element,
351
352 /// The inline style for the button.
353 ///
354 /// This allows for custom styling directly applied to the button element.
355 /// Defaults to an empty string.
356 #[props(default = "")]
357 pub style: &'static str,
358
359 /// The CSS class for the button.
360 ///
361 /// This applies a custom CSS class to the button for styling.
362 /// Defaults to an empty string.
363 #[props(default = "")]
364 pub class: &'static str,
365}
366
367#[component]
368pub fn Button(props: ButtonProps) -> Element {
369 rsx! {
370 button {
371 class: "{props.class}",
372 style: "{props.style}",
373 {props.children}
374 }
375 }
376}
377
378#[derive(Props, PartialEq, Clone)]
379pub struct ListProps {
380 /// The child elements of the list.
381 ///
382 /// These elements represent the individual list items or nested components inside the list container.
383 pub children: Element,
384
385 /// The inline style for the list container.
386 ///
387 /// You can provide custom CSS styles directly to the list container using this property.
388 /// Defaults to an empty string.
389 #[props(default = "")]
390 pub style: &'static str,
391
392 /// The CSS class for the list container.
393 ///
394 /// This class is used to apply custom styling to the list container via external CSS.
395 /// Defaults to an empty string.
396 #[props(default = "")]
397 pub class: &'static str,
398}
399
400#[component]
401pub fn List(props: ListProps) -> Element {
402 rsx! {
403 ul {
404 class: "{props.class}",
405 style: "{props.style}",
406 {props.children}
407 }
408 }
409}