From 7231e0cac1a6a3eecbec1bb01f0b42196d5af9b7 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Wed, 15 May 2024 23:03:35 +0800 Subject: [PATCH] feat: accordion --- demo/src/app.rs | 2 +- demo/src/pages/components.rs | 8 +-- demo_markdown/docs/accordion/mod.md | 21 +++++++ demo_markdown/docs/collapse/mod.md | 56 ------------------- demo_markdown/src/lib.rs | 2 +- thaw/src/accordion/accordion-item.css | 60 ++++++++++++++++++++ thaw/src/accordion/accordion_item.rs | 79 +++++++++++++++++++++++++++ thaw/src/accordion/mod.rs | 43 +++++++++++++++ thaw/src/collapse/collapse.css | 55 ------------------- thaw/src/collapse/collapse_item.rs | 63 --------------------- thaw/src/collapse/mod.rs | 48 ---------------- thaw/src/collapse/theme.rs | 20 ------- thaw/src/lib.rs | 4 +- thaw/src/theme/mod.rs | 9 +-- 14 files changed, 214 insertions(+), 256 deletions(-) create mode 100644 demo_markdown/docs/accordion/mod.md delete mode 100644 demo_markdown/docs/collapse/mod.md create mode 100644 thaw/src/accordion/accordion-item.css create mode 100644 thaw/src/accordion/accordion_item.rs create mode 100644 thaw/src/accordion/mod.rs delete mode 100644 thaw/src/collapse/collapse.css delete mode 100644 thaw/src/collapse/collapse_item.rs delete mode 100644 thaw/src/collapse/mod.rs delete mode 100644 thaw/src/collapse/theme.rs diff --git a/demo/src/app.rs b/demo/src/app.rs index 35c4974..053d00c 100644 --- a/demo/src/app.rs +++ b/demo/src/app.rs @@ -46,6 +46,7 @@ fn TheRouter(is_routing: RwSignal) -> impl IntoView { + @@ -57,7 +58,6 @@ fn TheRouter(is_routing: RwSignal) -> impl IntoView { - diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index e60d002..7bff405 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -109,6 +109,10 @@ pub(crate) fn gen_menu_data() -> Vec { MenuGroupOption { label: "Common Components".into(), children: vec![ + MenuItemOption { + value: "accordion".into(), + label: "Accordion".into(), + }, MenuItemOption { value: "avatar".into(), label: "Avatar".into(), @@ -121,10 +125,6 @@ pub(crate) fn gen_menu_data() -> Vec { value: "card".into(), label: "Card".into(), }, - MenuItemOption { - value: "collapse".into(), - label: "Collapse".into(), - }, MenuItemOption { value: "divider".into(), label: "Divider".into(), diff --git a/demo_markdown/docs/accordion/mod.md b/demo_markdown/docs/accordion/mod.md new file mode 100644 index 0000000..79a89ba --- /dev/null +++ b/demo_markdown/docs/accordion/mod.md @@ -0,0 +1,21 @@ +# Accordion + +```rust demo + +view! { + + + + "Leptos" + + "Build fast web applications with Rust." + + + + "Thaw" + + "An easy to use leptos component library" + + +} +``` \ No newline at end of file diff --git a/demo_markdown/docs/collapse/mod.md b/demo_markdown/docs/collapse/mod.md deleted file mode 100644 index 2891b44..0000000 --- a/demo_markdown/docs/collapse/mod.md +++ /dev/null @@ -1,56 +0,0 @@ -# Collapse - -```rust demo -use std::collections::HashSet; - -let value = create_rw_signal(HashSet::from(["thaw".to_string()])); - -view! { - - - "Build fast web applications with Rust." - - - "An easy to use leptos component library" - - -} -``` - -### Accordion - -Like an accordion. - -```rust demo -view! { - - - "Build fast web applications with Rust." - - - "An easy to use leptos component library." - - - "A Vue 3 Component Library. Fairly Complete. Theme Customizable. Uses TypeScript. Fast." - - -} -``` - -### Collapse Props - -| Name | Type | Default | Description | -| --------- | ----------------------------------- | -------------------- | ------------------------------------------- | -| class | `OptionalProp>` | `Default::default()` | Addtional classes for the collapse element. | -| value | `Model>` | `Default::default()` | Currently active panel. | -| accordion | `bool` | `false` | Only allow one panel open at a time. | -| children | `Children` | | Collapse's content. | - -### CollapseItem Props - -| Name | Type | Default | Description | -| --- | --- | --- | --- | -| class | `OptionalProp>` | `Default::default()` | Addtional classes for the collapse item element. | -| title | `MaybeSignal` | | The title of the CollapseItem. | -| key | `MaybeSignal` | | The indentifier of CollapseItem. | -| chilren | `Children` | | CollapseItem's content. | diff --git a/demo_markdown/src/lib.rs b/demo_markdown/src/lib.rs index 30e7bd7..63fb01d 100644 --- a/demo_markdown/src/lib.rs +++ b/demo_markdown/src/lib.rs @@ -28,6 +28,7 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt "NavBarMdPage" => "../docs/_mobile/nav_bar/mod.md", "TabbarMdPage" => "../docs/_mobile/tabbar/mod.md", "ToastMdPage" => "../docs/_mobile/toast/mod.md", + "AccordionMdPage" => "../docs/accordion/mod.md", "AlertMdPage" => "../docs/alert/mod.md", "AnchorMdPage" => "../docs/anchor/mod.md", "AutoCompleteMdPage" => "../docs/auto_complete/mod.md", @@ -39,7 +40,6 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt "CalendarMdPage" => "../docs/calendar/mod.md", "CardMdPage" => "../docs/card/mod.md", "CheckboxMdPage" => "../docs/checkbox/mod.md", - "CollapseMdPage" => "../docs/collapse/mod.md", "ColorPickerMdPage" => "../docs/color_picker/mod.md", "DatePickerMdPage" => "../docs/date_picker/mod.md", "DividerMdPage" => "../docs/divider/mod.md", diff --git a/thaw/src/accordion/accordion-item.css b/thaw/src/accordion/accordion-item.css new file mode 100644 index 0000000..e9c7b69 --- /dev/null +++ b/thaw/src/accordion/accordion-item.css @@ -0,0 +1,60 @@ +.thaw-accordion-header { + margin: 0; + background-color: var(--colorTransparentBackground); + color: var(--colorNeutralForeground1); + border-radius: var(--borderRadiusMedium); +} + +.thaw-accordion-header__button { + display: flex; + align-items: center; + position: relative; + padding-left: var(--spacingHorizontalMNudge); + padding-right: var(--spacingHorizontalM); + padding-top: 0px; + padding-bottom: 0px; + width: 100%; + min-height: 44px; + text-align: unset; + line-height: var(--lineHeightBase300); + font-family: var(--fontFamilyBase); + font-size: var(--fontSizeBase300); + font-weight: var(--fontWeightRegular); + background-color: inherit; + color: inherit; + border-width: 0px; + appearance: button; + overflow: visible; + box-sizing: border-box; + cursor: pointer; +} + +.thaw-accordion-panel { + margin: 0 var(--spacingHorizontalM); +} + + +.thaw-accordion-panel-enter-from, +.thaw-accordion-panel-enter-to { + opacity: 1; +} + +.thaw-accordion-panel-leave-to, +.thaw-accordion-panel-enter-from { + opacity: 0; + max-height: 0; +} + +.thaw-accordion-panel-leave-active { + overflow: hidden; + transition: max-height 0.15s cubic-bezier(0.4, 0, 0.2, 1) 0s, + opacity 0.15s cubic-bezier(0, 0, 0.2, 1) 0s, + padding-top 0.15s cubic-bezier(0.4, 0, 0.2, 1) 0s; +} + +.thaw-accordion-panel-enter-active { + overflow: hidden; + transition: max-height 0.15s cubic-bezier(0.4, 0, 0.2, 1), + opacity 0.15s cubic-bezier(0.4, 0, 1, 1), + padding-top 0.15s cubic-bezier(0.4, 0, 0.2, 1); +} \ No newline at end of file diff --git a/thaw/src/accordion/accordion_item.rs b/thaw/src/accordion/accordion_item.rs new file mode 100644 index 0000000..58ac2ce --- /dev/null +++ b/thaw/src/accordion/accordion_item.rs @@ -0,0 +1,79 @@ +use crate::AccordionInjection; +use leptos::*; +use thaw_components::CSSTransition; +use thaw_utils::{mount_style, StoredMaybeSignal}; + +#[component] +pub fn AccordionItem( + #[prop(into)] value: MaybeSignal, + accordion_header: AccordionHeader, + children: Children, +) -> impl IntoView { + mount_style("accordion-item", include_str!("./accordion-item.css")); + let AccordionInjection { + open_items, + multiple, + collapsible, + } = AccordionInjection::use_(); + let panel_ref = NodeRef::::new(); + let value: StoredMaybeSignal<_> = value.into(); + + let is_show_panel = Memo::new(move |_| with!(|open_items, value| open_items.contains(value))); + + let on_click = move |_| { + let is_show_panel = is_show_panel.get_untracked(); + update!(move |open_items| { + if is_show_panel { + if collapsible { + with!(|value| open_items.remove(value)); + } else if multiple { + with!(|value| open_items.remove(value)); + } + } else { + if !multiple { + open_items.clear(); + } + open_items.insert(value.get_untracked()); + } + }); + }; + + view! { +
+
+ +
+ +
+ {children()} +
+
+
+ } +} + +#[slot] +pub struct AccordionHeader { + children: Children, +} + +#[slot] +pub struct AccordionPanel { + children: Children, +} diff --git a/thaw/src/accordion/mod.rs b/thaw/src/accordion/mod.rs new file mode 100644 index 0000000..da0e7e9 --- /dev/null +++ b/thaw/src/accordion/mod.rs @@ -0,0 +1,43 @@ +mod accordion_item; + +pub use accordion_item::*; + +use leptos::*; +use std::collections::HashSet; +use thaw_utils::Model; + +#[component] +pub fn Accordion( + /// Controls the state of the panel. + #[prop(optional, into)] open_items: Model>, + /// Indicates if Accordion support multiple Panels opened at the same time. + #[prop(optional)] multiple: bool, + /// Indicates if Accordion support multiple Panels closed at the same time. + #[prop(optional)] collapsible: bool, + children: Children, +) -> impl IntoView { + view! { + +
+ {children()} +
+
+ } +} + +#[derive(Clone)] +pub(crate) struct AccordionInjection { + pub open_items: Model>, + pub multiple: bool, + pub collapsible: bool, +} + +impl AccordionInjection { + pub fn use_() -> AccordionInjection { + expect_context() + } +} diff --git a/thaw/src/collapse/collapse.css b/thaw/src/collapse/collapse.css deleted file mode 100644 index 7dca169..0000000 --- a/thaw/src/collapse/collapse.css +++ /dev/null @@ -1,55 +0,0 @@ -.thaw-collapse .thaw-collapse-item:not(:first-child) { - margin-top: 16px; - border-top: 1px solid var(--thaw-border-color); -} - -.thaw-collapse-item__header { - display: flex; - align-items: center; - cursor: pointer; -} - -.thaw-collapse - .thaw-collapse-item:not(:first-child) - .thaw-collapse-item__header { - padding-top: 16px; -} - -.thaw-collapse-item-arrow { - margin-right: 4px; - transition: transform 0.15s cubic-bezier(0.4, 0, 0.2, 1); -} - -.thaw-collapse-item--active .thaw-collapse-item-arrow { - transform: rotate(90deg); -} - -.thaw-collapse-item__content { - padding-top: 16px; -} - -.thaw-collapse-item-enter-from, -.thaw-collapse-item-enter-to { - opacity: 1; -} - -.thaw-collapse-item-leave-to, -.thaw-collapse-item-enter-from { - opacity: 0; - padding-top: 0; - max-height: 0; -} - -.thaw-collapse-item-leave-active { - overflow: hidden; - transition: max-height 0.15s cubic-bezier(0.4, 0, 0.2, 1) 0s, - opacity 0.15s cubic-bezier(0, 0, 0.2, 1) 0s, - padding-top 0.15s cubic-bezier(0.4, 0, 0.2, 1) 0s; -} - -.thaw-collapse-item-enter-active { - overflow: hidden; - transition: max-height 0.15s cubic-bezier(0.4, 0, 0.2, 1), - opacity 0.15s cubic-bezier(0.4, 0, 1, 1), - padding-top 0.15s cubic-bezier(0.4, 0, 0.2, 1); -} diff --git a/thaw/src/collapse/collapse_item.rs b/thaw/src/collapse/collapse_item.rs deleted file mode 100644 index 18f8ca8..0000000 --- a/thaw/src/collapse/collapse_item.rs +++ /dev/null @@ -1,63 +0,0 @@ -use super::use_collapse; -use crate::Icon; -use leptos::*; -use thaw_components::CSSTransition; -use thaw_utils::{class_list, OptionalProp, StoredMaybeSignal}; - -#[component] -pub fn CollapseItem( - #[prop(optional, into)] class: OptionalProp>, - #[prop(into)] title: MaybeSignal, - #[prop(into)] key: MaybeSignal, - children: Children, -) -> impl IntoView { - let collapse = use_collapse(); - let key: StoredMaybeSignal<_> = key.into(); - let content_ref = create_node_ref::(); - - let is_show_content = create_memo(move |_| { - collapse - .value - .with(|keys| key.with(|key| keys.contains(key))) - }); - - let on_click = move |_| { - collapse.value.update(|keys| { - if collapse.accordion { - keys.clear(); - } - let key = key.get_untracked(); - if is_show_content.get_untracked() { - keys.remove(&key); - } else { - keys.insert(key); - } - }); - }; - - view! { -
-
- - {move || title.get()} -
- -
- {children()} -
-
-
- } -} diff --git a/thaw/src/collapse/mod.rs b/thaw/src/collapse/mod.rs deleted file mode 100644 index a99d1ff..0000000 --- a/thaw/src/collapse/mod.rs +++ /dev/null @@ -1,48 +0,0 @@ -mod collapse_item; -mod theme; - -pub use collapse_item::CollapseItem; -pub use theme::CollapseTheme; - -use crate::{use_theme, Theme}; -use leptos::*; -use std::collections::HashSet; -use thaw_utils::{class_list, mount_style, Model, OptionalProp}; - -#[component] -pub fn Collapse( - #[prop(optional, into)] class: OptionalProp>, - #[prop(optional, into)] value: Model>, - #[prop(optional)] accordion: bool, - children: Children, -) -> impl IntoView { - mount_style("collapser", include_str!("./collapse.css")); - let theme = use_theme(Theme::light); - let css_vars = create_memo(move |_| { - theme.with(|theme| format!("--thaw-border-color: {};", theme.collapse.border_color)) - }); - - view! { - -
- {children()} -
-
- } -} - -#[derive(Clone)] -pub(crate) struct CollapseInjection { - pub value: Model>, - pub accordion: bool, -} - -pub(crate) fn use_collapse() -> CollapseInjection { - expect_context() -} diff --git a/thaw/src/collapse/theme.rs b/thaw/src/collapse/theme.rs deleted file mode 100644 index 386bc22..0000000 --- a/thaw/src/collapse/theme.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::theme::ThemeMethod; - -#[derive(Clone)] -pub struct CollapseTheme { - pub border_color: String, -} - -impl ThemeMethod for CollapseTheme { - fn light() -> Self { - Self { - border_color: "#efeff5".into(), - } - } - - fn dark() -> Self { - Self { - border_color: "#ffffff17".into(), - } - } -} diff --git a/thaw/src/lib.rs b/thaw/src/lib.rs index ef84b85..1ea8c51 100644 --- a/thaw/src/lib.rs +++ b/thaw/src/lib.rs @@ -1,3 +1,4 @@ +mod accordion; mod alert; mod anchor; mod auto_complete; @@ -10,7 +11,6 @@ mod calendar; mod card; mod checkbox; mod code; -mod collapse; mod color_picker; mod config_provider; mod date_picker; @@ -46,6 +46,7 @@ mod theme; mod time_picker; mod upload; +pub use accordion::*; pub use alert::*; pub use anchor::*; pub use auto_complete::*; @@ -58,7 +59,6 @@ pub use calendar::*; pub use card::*; pub use checkbox::*; pub use code::*; -pub use collapse::*; pub use color_picker::*; pub use config_provider::*; pub use date_picker::*; diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index f983366..51650c8 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -5,9 +5,9 @@ use self::common::CommonTheme; use crate::{ mobile::{NavBarTheme, TabbarTheme}, AlertTheme, AnchorTheme, AutoCompleteTheme, BackTopTheme, BreadcrumbTheme, CalendarTheme, - CollapseTheme, ColorPickerTheme, DatePickerTheme, InputTheme, MenuTheme, MessageTheme, - PopoverTheme, ProgressTheme, ScrollbarTheme, SelectTheme, SkeletionTheme, SliderTheme, - SpinnerTheme, SwitchTheme, TableTheme, TagTheme, TimePickerTheme, UploadTheme, + ColorPickerTheme, DatePickerTheme, InputTheme, MenuTheme, MessageTheme, PopoverTheme, + ProgressTheme, ScrollbarTheme, SelectTheme, SkeletionTheme, SliderTheme, SpinnerTheme, + SwitchTheme, TableTheme, TagTheme, TimePickerTheme, UploadTheme, }; pub use color::ColorTheme; use leptos::*; @@ -44,7 +44,6 @@ pub struct Theme { pub time_picker: TimePickerTheme, pub date_picker: DatePickerTheme, pub popover: PopoverTheme, - pub collapse: CollapseTheme, pub scrollbar: ScrollbarTheme, pub back_top: BackTopTheme, pub anchor: AnchorTheme, @@ -78,7 +77,6 @@ impl Theme { time_picker: TimePickerTheme::light(), date_picker: DatePickerTheme::light(), popover: PopoverTheme::light(), - collapse: CollapseTheme::light(), scrollbar: ScrollbarTheme::light(), back_top: BackTopTheme::light(), anchor: AnchorTheme::light(), @@ -111,7 +109,6 @@ impl Theme { time_picker: TimePickerTheme::dark(), date_picker: DatePickerTheme::dark(), popover: PopoverTheme::dark(), - collapse: CollapseTheme::dark(), scrollbar: ScrollbarTheme::dark(), back_top: BackTopTheme::dark(), anchor: AnchorTheme::dark(),