yew_accordion/lib.rs
1#![doc(
2 html_logo_url = "https://github.com/next-rs/yew-accordion/assets/62179149/48fa7fe4-90a1-4314-801b-49389cebf33e",
3 html_favicon_url = "https://github.com/next-rs/yew-accordion/assets/62179149/05482d9e-3bb3-49c2-9d3e-26aa9c12d936"
4)]
5
6//! # Yew Accordion - Documentation
7//!
8//! Welcome to the official Yew Accordion documentation. This library
9//! provides a customizable accordion component for your Yew applications.
10//!
11//! ## Usage
12//!
13//! To use the Yew Accordion library, add the following dependency to your `Cargo.toml` file:
14//!
15//! ```sh
16//! cargo add yew-accordion
17//! ```
18//!
19//! To integrate the library into your Yew application, you can use the `Accordion`, `AccordionItem`,
20//! and `AccordionButton` components. Here's a simple example of how to use them:
21//!
22//! ```rust
23//! use yew::prelude::*;
24//! use yew_accordion::{Accordion, AccordionItem, AccordionButton};
25//!
26//! // Your Yew component structure here...
27//!
28//! #[function_component]
29//! pub fn MyAccordionComponent() -> Html {
30//! // Your component logic here...
31//!
32//! html! {
33//! <Accordion
34//! expanded_element={html! {<AccordionButton class={"bg-blue-500 text-white p-2 rounded"}>{ "Hide -" }</AccordionButton>}}
35//! collapsed_element={html! {<AccordionButton class={"bg-green-500 text-white p-2 rounded"}>{ "Show +" }</AccordionButton>}}
36//! size="sm"
37//! aria_controls="example-accordion"
38//! container_class="my-custom-class bg-gray-800 p-4 rounded border border-gray-700"
39//! expanded_element_class="my-expanded-class bg-gradient-to-r from-blue-700 to-blue-500 text-white p-2 rounded"
40//! collapsed_element_class="my-collapsed-class bg-gradient-to-r from-green-700 to-green-500 text-white p-2 rounded"
41//! content_container_class="my-content-class bg-gray-900 p-4 rounded border-t border-gray-700"
42//! >
43//! <ul>
44//! <AccordionItem
45//! item_class="my-list-item-class border-b p-2 hover:bg-gray-700 transition duration-300 ease-in-out"
46//! >{ "Item 1" }</AccordionItem>
47//! <AccordionItem
48//! item_class="my-list-item-class border-b p-2 hover:bg-gray-700 transition duration-300 ease-in-out"
49//! >{ "Item 2" }</AccordionItem>
50//! <AccordionItem
51//! item_class="my-list-item-class p-2 hover:bg-gray-700 transition duration-300 ease-in-out"
52//! >{ "Item 3" }</AccordionItem>
53//! </ul>
54//! </Accordion>
55//! }
56//! }
57//! ```
58//!
59//! For more detailed information, check the [examples] provided in the library.
60//!
61//! [examples]: https://github.com/next-rs/yew-accordion/tree/main/examples
62//!
63//! ## Configuration
64//!
65//! Yew Accordion allows you to customize various aspects of the accordion component through the
66//! `AccordionProps`, `AccordionItemProps`, and `AccordionButtonProps` structures. You can adjust
67//! properties such as size, ARIA controls, and custom classes. Refer to the respective documentation
68//! for detailed configuration options.
69//!
70//! ## Contribution
71//!
72//! If you encounter any issues or have suggestions for improvements, feel free to contribute
73//! to the [GitHub repository](https://github.com/next-rs/yew-accordion). We appreciate your feedback
74//! and involvement in making Yew Accordion better!
75//!
76//! ## Acknowledgments
77//!
78//! Special thanks to the Yew community and contributors for such an amazing framework.
79//!
80
81use yew::prelude::*;
82
83/// Properties for the Accordion component.
84#[derive(Properties, Clone, PartialEq)]
85pub struct AccordionProps {
86 #[prop_or_default]
87 /// The content to be displayed when the accordion is expanded.
88 pub expanded_element: Html,
89
90 #[prop_or_default]
91 /// The content to be displayed when the accordion is collapsed.
92 pub collapsed_element: Html,
93
94 #[prop_or_default]
95 /// The child elements within the accordion.
96 pub children: Html,
97
98 #[prop_or_default]
99 /// Size of the accordion. Possible values: "sm", "md", "lg".
100 pub size: &'static str,
101
102 #[prop_or_default]
103 /// ARIA controls attribute for accessibility.
104 pub aria_controls: &'static str,
105
106 #[prop_or_default]
107 /// Class for the container element.
108 pub container_class: &'static str,
109
110 #[prop_or_default]
111 /// Class for the expanded element.
112 pub expanded_element_class: &'static str,
113
114 #[prop_or_default]
115 /// Class for the collapsed element.
116 pub collapsed_element_class: &'static str,
117
118 #[prop_or_default]
119 /// Class for the content container.
120 pub content_container_class: &'static str,
121}
122
123/// Accordion component.
124#[function_component]
125pub fn Accordion(props: &AccordionProps) -> Html {
126 // State to track whether the accordion is expanded or collapsed.
127 let is_expanded = use_state(|| false);
128 let props = props.clone();
129 let is_expanded_value = *is_expanded;
130
131 // Callback function to handle accordion click events.
132 let onclick = move |e: MouseEvent| {
133 e.prevent_default();
134 is_expanded.set(!is_expanded_value);
135 };
136
137 html! {
138 <div class={get_accordion_container_style(&props.size, &props.container_class)}>
139 <div
140 aria-expanded={is_expanded_value.to_string()}
141 aria-controls={props.aria_controls}
142 onclick={onclick}
143 class={get_toggle_element_style(&is_expanded_value, &props.expanded_element_class, &props.collapsed_element_class)}
144 >
145 { if is_expanded_value {props.expanded_element.clone()} else {props.collapsed_element.clone()} }
146 </div>
147 { if is_expanded_value {
148 html! { <div id={props.aria_controls} class={props.content_container_class}>{props.children.clone()}</div> }
149 } else {
150 html! {}
151 } }
152 </div>
153 }
154}
155
156/// Get the CSS class for the accordion container based on size and custom class.
157fn get_accordion_container_style(size: &str, custom_class: &str) -> String {
158 let base_class = match size {
159 "sm" => "w-28",
160 "md" => "w-40",
161 "lg" => "w-80",
162 _ => "",
163 };
164 format!("{} {}", base_class, custom_class)
165}
166
167/// Get the CSS class for the toggle element based on its expanded state.
168fn get_toggle_element_style(
169 is_expanded: &bool,
170 expanded_class: &'static str,
171 collapsed_class: &'static str,
172) -> &'static str {
173 if *is_expanded {
174 expanded_class
175 } else {
176 collapsed_class
177 }
178}
179
180/// Properties for the AccordionItem component.
181#[derive(Clone, PartialEq, Properties)]
182pub struct AccordionItemProps {
183 #[prop_or_default]
184 /// The content of the AccordionItem.
185 pub children: Html,
186
187 #[prop_or_default]
188 /// Additional class for the AccordionItem.
189 pub item_class: &'static str,
190}
191
192/// AccordionItem component.
193#[function_component]
194pub fn AccordionItem(props: &AccordionItemProps) -> Html {
195 html! { <li class={props.item_class}>{ props.children.clone() }</li> }
196}
197
198/// Properties for the AccordionButton component.
199#[derive(Clone, PartialEq, Properties)]
200pub struct AccordionButtonProps {
201 #[prop_or_default]
202 /// The content of the AccordionButton.
203 pub children: Html,
204
205 #[prop_or_default]
206 /// Additional class for the AccordionButton.
207 pub class: &'static str,
208}
209
210/// AccordionButton component.
211#[function_component]
212pub fn AccordionButton(props: &AccordionButtonProps) -> Html {
213 html! { <button class={props.class}>{ props.children.clone() }</button> }
214}