diff --git a/thaw/src/combobox/combobox.css b/thaw/src/combobox/combobox.css
index fbea8bf..196cad7 100644
--- a/thaw/src/combobox/combobox.css
+++ b/thaw/src/combobox/combobox.css
@@ -115,21 +115,6 @@
cursor: not-allowed;
}
-.thaw-combobox__listbox {
- row-gap: var(--spacingHorizontalXXS);
- display: flex;
- flex-direction: column;
- min-width: 160px;
- max-height: 80vh;
- background-color: var(--colorNeutralBackground1);
- padding: var(--spacingHorizontalXS);
- outline: 1px solid var(--colorTransparentStroke);
- border-radius: var(--borderRadiusMedium);
- box-shadow: var(--shadow16);
- box-sizing: border-box;
- overflow-y: auto;
-}
-
.thaw-combobox-option {
column-gap: var(--spacingHorizontalXS);
position: relative;
diff --git a/thaw/src/combobox/combobox_option_group.rs b/thaw/src/combobox/combobox_option_group.rs
index b1bf8cb..9dd2052 100644
--- a/thaw/src/combobox/combobox_option_group.rs
+++ b/thaw/src/combobox/combobox_option_group.rs
@@ -1,5 +1,5 @@
+use super::option_group::OptionGroup;
use leptos::prelude::*;
-use thaw_utils::{class_list, mount_style};
#[component]
pub fn ComboboxOptionGroup(
@@ -9,17 +9,5 @@ pub fn ComboboxOptionGroup(
label: String,
children: Children,
) -> impl IntoView {
- mount_style(
- "combobox-option-group",
- include_str!("./combobox-option-group.css"),
- );
-
- view! {
-
-
- {label}
-
- {children()}
-
- }
+ view! { }
}
diff --git a/thaw/src/combobox/listbox.css b/thaw/src/combobox/common/listbox.css
similarity index 61%
rename from thaw/src/combobox/listbox.css
rename to thaw/src/combobox/common/listbox.css
index eb432b5..11d836b 100644
--- a/thaw/src/combobox/listbox.css
+++ b/thaw/src/combobox/common/listbox.css
@@ -1,3 +1,18 @@
+.thaw-listbox {
+ row-gap: var(--spacingHorizontalXXS);
+ display: flex;
+ flex-direction: column;
+ min-width: 160px;
+ max-height: 80vh;
+ background-color: var(--colorNeutralBackground1);
+ padding: var(--spacingHorizontalXS);
+ outline: 1px solid var(--colorTransparentStroke);
+ border-radius: var(--borderRadiusMedium);
+ box-shadow: var(--shadow16);
+ box-sizing: border-box;
+ overflow-y: auto;
+}
+
.thaw-listbox.fade-in-scale-up-transition-leave-active {
transform-origin: inherit;
transition: opacity 0.2s cubic-bezier(0.4, 0, 1, 1),
@@ -20,4 +35,4 @@
.thaw-listbox.fade-in-scale-up-transition-enter-to {
opacity: 1;
transform: scale(1);
-}
\ No newline at end of file
+}
diff --git a/thaw/src/combobox/listbox.rs b/thaw/src/combobox/common/listbox.rs
similarity index 100%
rename from thaw/src/combobox/listbox.rs
rename to thaw/src/combobox/common/listbox.rs
diff --git a/thaw/src/combobox/common/mod.rs b/thaw/src/combobox/common/mod.rs
new file mode 100644
index 0000000..788010e
--- /dev/null
+++ b/thaw/src/combobox/common/mod.rs
@@ -0,0 +1,3 @@
+pub mod listbox;
+pub mod option_group;
+mod utils;
diff --git a/thaw/src/combobox/combobox-option-group.css b/thaw/src/combobox/common/option-group.css
similarity index 84%
rename from thaw/src/combobox/combobox-option-group.css
rename to thaw/src/combobox/common/option-group.css
index f03491e..d387dcf 100644
--- a/thaw/src/combobox/combobox-option-group.css
+++ b/thaw/src/combobox/common/option-group.css
@@ -1,10 +1,10 @@
-.thaw-combobox-option-group {
+.thaw-option-group {
display: flex;
row-gap: var(--spacingHorizontalXXS);
flex-direction: column;
}
-.thaw-combobox-option-group__label {
+.thaw-option-group__label {
display: block;
color: var(--colorNeutralForeground3);
font-weight: var(--fontWeightSemibold);
@@ -14,7 +14,7 @@
border-radius: var(--borderRadiusMedium);
}
-.thaw-combobox-option-group:not(:last-child)::after {
+.thaw-option-group:not(:last-child)::after {
content: "";
display: block;
margin: 0 calc(var(--spacingHorizontalXS) * -1) var(--spacingVerticalXS);
diff --git a/thaw/src/combobox/common/option_group.rs b/thaw/src/combobox/common/option_group.rs
new file mode 100644
index 0000000..3717e3c
--- /dev/null
+++ b/thaw/src/combobox/common/option_group.rs
@@ -0,0 +1,25 @@
+use leptos::prelude::*;
+use thaw_utils::{class_list, mount_style};
+
+#[component]
+pub fn OptionGroup(
+ class_prefix: &'static str,
+ class: MaybeProp,
+ /// Label of the group.
+ label: String,
+ children: Children,
+) -> impl IntoView {
+ mount_style("option-group", include_str!("./option-group.css"));
+
+ view! {
+
+
+ {label}
+
+ {children()}
+
+ }
+}
diff --git a/thaw/src/combobox/utils.rs b/thaw/src/combobox/common/utils.rs
similarity index 100%
rename from thaw/src/combobox/utils.rs
rename to thaw/src/combobox/common/utils.rs
diff --git a/thaw/src/combobox/mod.rs b/thaw/src/combobox/mod.rs
index 993d458..0a18528 100644
--- a/thaw/src/combobox/mod.rs
+++ b/thaw/src/combobox/mod.rs
@@ -1,9 +1,9 @@
mod combobox;
mod combobox_option;
mod combobox_option_group;
-pub(crate) mod listbox;
-mod utils;
+mod common;
pub use combobox::*;
pub use combobox_option::*;
pub use combobox_option_group::*;
+pub(crate) use common::*;
diff --git a/thaw/src/tag_picker/docs/mod.md b/thaw/src/tag_picker/docs/mod.md
index 503025a..d4e9207 100644
--- a/thaw/src/tag_picker/docs/mod.md
+++ b/thaw/src/tag_picker/docs/mod.md
@@ -37,6 +37,76 @@ view! {
}
```
+### Grouped
+
+```rust demo
+use leptos::either::Either;
+let selected_options = RwSignal::new(vec![]);
+let land = vec!["Cat", "Dog", "Ferret", "Hamster"];
+let water = vec!["Fish", "Jellyfish", "Octopus", "Seal"];
+
+view! {
+
+
+
+ {move || {
+ selected_options.get().into_iter().map(|option| view!{
+
+ {option}
+
+ }).collect_view()
+ }}
+
+
+
+ {move || {
+ selected_options.with(|selected_options| {
+ let land_view = land.iter().filter_map(|option| {
+ if selected_options.iter().any(|o| o == option) {
+ return None
+ } else {
+ Some(view! {
+
+ })
+ }
+ }).collect_view();
+ if land_view.is_empty() {
+ Either::Left(())
+ } else {
+ Either::Right(view! {
+
+ {land_view}
+
+ })
+ }
+ })
+ }}
+ {move || {
+ selected_options.with(|selected_options| {
+ let water_view = water.iter().filter_map(|option| {
+ if selected_options.iter().any(|o| o == option) {
+ return None
+ } else {
+ Some(view! {
+
+ })
+ }
+ }).collect_view();
+ if water_view.is_empty() {
+ Either::Left(())
+ } else {
+ Either::Right(view! {
+
+ {water_view}
+
+ })
+ }
+ })
+ }}
+
+}
+```
+
### TagPicker Props
| Name | Type | Default | Description |
@@ -68,3 +138,11 @@ view! {
| value | `String` | | Defines a unique identifier for the option. |
| text | `String` | | An optional override the string value of the Option's display text, defaulting to the Option's child content. |
| children | `Option` | `None` | |
+
+### TagPickerOptionGroup Props
+
+| Name | Type | Default | Desciption |
+| -------- | ------------------- | -------------------- | ------------------- |
+| class | `MaybeProp` | `Default::default()` | |
+| label | `String` | | Label of the group. |
+| children | `Children` | | |
diff --git a/thaw/src/tag_picker/mod.rs b/thaw/src/tag_picker/mod.rs
index 0556e7d..593909c 100644
--- a/thaw/src/tag_picker/mod.rs
+++ b/thaw/src/tag_picker/mod.rs
@@ -2,8 +2,10 @@ mod tag_picker;
mod tag_picker_group;
mod tag_picker_input;
mod tag_picker_option;
+mod tag_picker_option_group;
pub use tag_picker::*;
pub use tag_picker_group::*;
pub use tag_picker_input::*;
pub use tag_picker_option::*;
+pub use tag_picker_option_group::*;
diff --git a/thaw/src/tag_picker/tag-picker.css b/thaw/src/tag_picker/tag-picker.css
index 397faee..2deb6e3 100644
--- a/thaw/src/tag_picker/tag-picker.css
+++ b/thaw/src/tag_picker/tag-picker.css
@@ -82,21 +82,6 @@
outline-style: none;
}
-.thaw-tag-picker__listbox {
- display: flex;
- flex-direction: column;
- row-gap: var(--spacingHorizontalXXS);
- overflow-y: auto;
- min-width: 160px;
- max-height: 80vh;
- background-color: var(--colorNeutralBackground1);
- padding: var(--spacingHorizontalXS);
- outline: 1px solid var(--colorTransparentStroke);
- border-radius: var(--borderRadiusMedium);
- box-shadow: var(--shadow16);
- box-sizing: border-box;
-}
-
.thaw-tag-picker-option {
grid-template-columns: auto 1fr;
column-gap: var(--spacingHorizontalXS);
diff --git a/thaw/src/tag_picker/tag_picker.rs b/thaw/src/tag_picker/tag_picker.rs
index 67a262f..3aa0f3c 100644
--- a/thaw/src/tag_picker/tag_picker.rs
+++ b/thaw/src/tag_picker/tag_picker.rs
@@ -6,7 +6,7 @@ use crate::{
use leptos::{context::Provider, ev, html, prelude::*};
use std::collections::HashMap;
use thaw_components::{Binder, Follower, FollowerPlacement, FollowerWidth};
-use thaw_utils::{call_on_click_outside, class_list, mount_style, BoxCallback, Model};
+use thaw_utils::{call_on_click_outside_with_list, class_list, mount_style, BoxCallback, Model};
#[component]
pub fn TagPicker(
@@ -55,8 +55,8 @@ pub fn TagPicker(
}
is_show_listbox.update(|show| *show = !*show);
};
- call_on_click_outside(
- trigger_ref,
+ call_on_click_outside_with_list(
+ vec![trigger_ref, listbox_ref],
{
move || {
is_show_listbox.set(false);
diff --git a/thaw/src/tag_picker/tag_picker_option_group.rs b/thaw/src/tag_picker/tag_picker_option_group.rs
new file mode 100644
index 0000000..4f227c7
--- /dev/null
+++ b/thaw/src/tag_picker/tag_picker_option_group.rs
@@ -0,0 +1,13 @@
+use crate::option_group::OptionGroup;
+use leptos::prelude::*;
+
+#[component]
+pub fn TagPickerOptionGroup(
+ #[prop(optional, into)] class: MaybeProp,
+ /// Label of the group.
+ #[prop(into)]
+ label: String,
+ children: Children,
+) -> impl IntoView {
+ view! { }
+}
diff --git a/thaw_utils/src/on_click_outside.rs b/thaw_utils/src/on_click_outside.rs
index 98db865..c3fe30f 100644
--- a/thaw_utils/src/on_click_outside.rs
+++ b/thaw_utils/src/on_click_outside.rs
@@ -21,3 +21,28 @@ pub fn call_on_click_outside(element: NodeRef, on_click: BoxCallback) {
let _ = on_click;
}
}
+
+pub fn call_on_click_outside_with_list(refs: Vec>, on_click: BoxCallback) {
+ #[cfg(any(feature = "csr", feature = "hydrate"))]
+ {
+ let handle = window_event_listener(::leptos::ev::click, move |ev| {
+ let composed_path = ev.composed_path();
+ if refs.iter().any(|r| {
+ if let Some(el) = r.get_untracked() {
+ composed_path.includes(&el, 0)
+ } else {
+ false
+ }
+ }) {
+ return;
+ }
+ on_click();
+ });
+ on_cleanup(move || handle.remove());
+ }
+ #[cfg(not(any(feature = "csr", feature = "hydrate")))]
+ {
+ let _ = refs;
+ let _ = on_click;
+ }
+}