Skip to main content

impulse_thaw/accordion/
accordion_item.rs

1use crate::AccordionInjection;
2use leptos::prelude::*;
3use thaw_components::CSSTransition;
4use thaw_utils::{class_list, mount_style, update, with};
5
6#[component]
7pub fn AccordionItem(
8    #[prop(optional, into)] class: MaybeProp<String>,
9    /// Required value that identifies this item inside an Accordion component.
10    #[prop(into)]
11    value: Signal<String>,
12    accordion_header: AccordionHeader,
13    children: Children,
14) -> impl IntoView {
15    mount_style("accordion-item", include_str!("./accordion-item.css"));
16    let AccordionInjection {
17        open_items,
18        multiple,
19        collapsible,
20    } = AccordionInjection::expect_context();
21    let is_show_panel = Memo::new(move |_| with!(|open_items, value| open_items.contains(value)));
22
23    let on_click = move |_| {
24        let is_show_panel = is_show_panel.get_untracked();
25        update!(move |open_items| {
26            if is_show_panel {
27                if collapsible {
28                    with!(|value| open_items.remove(value));
29                } else if multiple {
30                    with!(|value| open_items.remove(value));
31                }
32            } else {
33                if !multiple {
34                    open_items.clear();
35                }
36                open_items.insert(value.get_untracked());
37            }
38        });
39    };
40
41    view! {
42        <div class=class_list!["thaw-accordion-item", class]>
43            <div class="thaw-accordion-header">
44                <button
45                    class="thaw-accordion-header__button"
46                    aria-expanded=move || is_show_panel.get().to_string()
47                    type="button"
48                    on:click=on_click
49                >
50                    <span class="thaw-accordion-header__expand-icon" aria-hidden="true">
51                        <svg
52                            fill="currentColor"
53                            aria-hidden="true"
54                            width="1em"
55                            height="1em"
56                            viewBox="0 0 20 20"
57                            style=move || {
58                                if is_show_panel.get() {
59                                    "transform: rotate(90deg)"
60                                } else {
61                                    "transform: rotate(0deg)"
62                                }
63                            }
64                        >
65                            <path
66                                d="M7.65 4.15c.2-.2.5-.2.7 0l5.49 5.46c.21.22.21.57 0 .78l-5.49 5.46a.5.5 0 0 1-.7-.7L12.8 10 7.65 4.85a.5.5 0 0 1 0-.7Z"
67                                fill="currentColor"
68                            ></path>
69                        </svg>
70                    </span>
71                    {(accordion_header.children)()}
72                </button>
73            </div>
74            <CSSTransition show=is_show_panel name="thaw-accordion-panel">
75                <div class="thaw-accordion-panel">
76                    {children()}
77                </div>
78            </CSSTransition>
79        </div>
80    }
81}
82
83#[slot]
84pub struct AccordionHeader {
85    children: Children,
86}
87
88// #[slot]
89// pub struct AccordionPanel {
90//     children: Children,
91// }