Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/tag picker 240912 #260

Merged
merged 3 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 0 additions & 15 deletions thaw/src/combobox/combobox.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
16 changes: 2 additions & 14 deletions thaw/src/combobox/combobox_option_group.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::option_group::OptionGroup;
use leptos::prelude::*;
use thaw_utils::{class_list, mount_style};

#[component]
pub fn ComboboxOptionGroup(
Expand All @@ -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! {
<div role="group" class=class_list!["thaw-combobox-option-group", class]>
<span role="presentation" class="thaw-combobox-option-group__label">
{label}
</span>
{children()}
</div>
}
view! { <OptionGroup class_prefix="thaw-combobox-option-group" class label children /> }
}
Original file line number Diff line number Diff line change
@@ -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),
Expand All @@ -20,4 +35,4 @@
.thaw-listbox.fade-in-scale-up-transition-enter-to {
opacity: 1;
transform: scale(1);
}
}
File renamed without changes.
3 changes: 3 additions & 0 deletions thaw/src/combobox/common/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod listbox;
pub mod option_group;
mod utils;
Original file line number Diff line number Diff line change
@@ -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);
Expand All @@ -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);
Expand Down
25 changes: 25 additions & 0 deletions thaw/src/combobox/common/option_group.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use leptos::prelude::*;
use thaw_utils::{class_list, mount_style};

#[component]
pub fn OptionGroup(
class_prefix: &'static str,
class: MaybeProp<String>,
/// Label of the group.
label: String,
children: Children,
) -> impl IntoView {
mount_style("option-group", include_str!("./option-group.css"));

view! {
<div role="group" class=class_list!["thaw-option-group", class_prefix, class]>
<span
role="presentation"
class=format!("thaw-option-group__label {class_prefix}__label")
>
{label}
</span>
{children()}
</div>
}
}
File renamed without changes.
4 changes: 2 additions & 2 deletions thaw/src/combobox/mod.rs
Original file line number Diff line number Diff line change
@@ -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::*;
78 changes: 78 additions & 0 deletions thaw/src/tag_picker/docs/mod.md
Original file line number Diff line number Diff line change
Expand Up @@ -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! {
<TagPicker selected_options>
<TagPickerControl slot>
<TagPickerGroup>
{move || {
selected_options.get().into_iter().map(|option| view!{
<Tag value=option.clone()>
{option}
</Tag>
}).collect_view()
}}
</TagPickerGroup>
<TagPickerInput />
</TagPickerControl>
{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! {
<TagPickerOption value=option.clone() text=option.clone() />
})
}
}).collect_view();
if land_view.is_empty() {
Either::Left(())
} else {
Either::Right(view! {
<TagPickerOptionGroup label="Land">
{land_view}
</TagPickerOptionGroup>
})
}
})
}}
{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! {
<TagPickerOption value=option.clone() text=option.clone() />
})
}
}).collect_view();
if water_view.is_empty() {
Either::Left(())
} else {
Either::Right(view! {
<TagPickerOptionGroup label="Sea">
{water_view}
</TagPickerOptionGroup>
})
}
})
}}
</TagPicker>
}
```

### TagPicker Props

| Name | Type | Default | Description |
Expand Down Expand Up @@ -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<Children>` | `None` | |

### TagPickerOptionGroup Props

| Name | Type | Default | Desciption |
| -------- | ------------------- | -------------------- | ------------------- |
| class | `MaybeProp<String>` | `Default::default()` | |
| label | `String` | | Label of the group. |
| children | `Children` | | |
2 changes: 2 additions & 0 deletions thaw/src/tag_picker/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
15 changes: 0 additions & 15 deletions thaw/src/tag_picker/tag-picker.css
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions thaw/src/tag_picker/tag_picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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);
Expand Down
13 changes: 13 additions & 0 deletions thaw/src/tag_picker/tag_picker_option_group.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use crate::option_group::OptionGroup;
use leptos::prelude::*;

#[component]
pub fn TagPickerOptionGroup(
#[prop(optional, into)] class: MaybeProp<String>,
/// Label of the group.
#[prop(into)]
label: String,
children: Children,
) -> impl IntoView {
view! { <OptionGroup class_prefix="thaw-tag-picker-option-group" class label children /> }
}
25 changes: 25 additions & 0 deletions thaw_utils/src/on_click_outside.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,28 @@ pub fn call_on_click_outside(element: NodeRef<Div>, on_click: BoxCallback) {
let _ = on_click;
}
}

pub fn call_on_click_outside_with_list(refs: Vec<NodeRef<Div>>, 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;
}
}
Loading