From f6d534220ecbefb084690c4468e62c520653bf36 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Thu, 27 Jun 2024 17:31:52 +0800 Subject: [PATCH] feat: Combobox adds clearable prop --- demo_markdown/docs/combobox/mod.md | 17 ++++++ thaw/src/combobox/combobox.css | 4 +- thaw/src/combobox/combobox.rs | 88 +++++++++++++++++++++++++++--- 3 files changed, 101 insertions(+), 8 deletions(-) diff --git a/demo_markdown/docs/combobox/mod.md b/demo_markdown/docs/combobox/mod.md index cef4145..1578530 100644 --- a/demo_markdown/docs/combobox/mod.md +++ b/demo_markdown/docs/combobox/mod.md @@ -15,6 +15,23 @@ view! { } ``` +### Clearable + +```rust demo +let value = RwSignal::new(vec![]); + +view! { + + + "Cat" + + + "Dog" + + +} +``` + ### Multiselect ```rust demo diff --git a/thaw/src/combobox/combobox.css b/thaw/src/combobox/combobox.css index 5801cfe..3fd11e9 100644 --- a/thaw/src/combobox/combobox.css +++ b/thaw/src/combobox/combobox.css @@ -78,6 +78,7 @@ outline-style: none; } +.thaw-combobox__clear-icon, .thaw-combobox__expand-icon { display: block; margin-left: var(--spacingHorizontalXXS); @@ -152,7 +153,6 @@ .thaw-combobox-option__check-icon { visibility: hidden; - margin-left: calc(var(--spacingHorizontalXXS) * -1); margin-right: var(--spacingHorizontalXXS); font-size: var(--fontSizeBase400); @@ -162,6 +162,8 @@ visibility: visible; } +.thaw-combobox__clear-icon > svg, +.thaw-combobox__expand-icon > svg, .thaw-combobox-option__check-icon--multiselect > svg, .thaw-combobox-option__check-icon > svg { display: block; diff --git a/thaw/src/combobox/combobox.rs b/thaw/src/combobox/combobox.rs index e8fc16b..75151e3 100644 --- a/thaw/src/combobox/combobox.rs +++ b/thaw/src/combobox/combobox.rs @@ -1,12 +1,13 @@ use crate::ConfigInjection; use leptos::*; use thaw_components::{Binder, CSSTransition, Follower, FollowerPlacement, FollowerWidth}; -use thaw_utils::{mount_style, Model}; +use thaw_utils::{add_event_listener, mount_style, Model}; #[component] pub fn Combobox( #[prop(optional, into)] value: Model>, #[prop(optional)] multiselect: bool, + #[prop(optional)] clearable: bool, children: Children, ) -> impl IntoView { mount_style("combobox", include_str!("./combobox.css")); @@ -15,13 +16,63 @@ pub fn Combobox( let listbox_ref = NodeRef::::new(); let is_show_listbox = RwSignal::new(false); + let clear_icon_ref = NodeRef::::new(); + let is_show_clear_icon = Memo::new(move |_| { + if clearable { + value.with(|value| !value.is_empty()) + } else { + false + } + }); + if clearable { + clear_icon_ref.on_load(move |clear_icon_el| { + let handler = add_event_listener(clear_icon_el.into_any(), ev::click, move |e| { + e.stop_propagation(); + value.set(vec![]); + }); + on_cleanup(move || handler.remove()); + }); + } + + #[cfg(any(feature = "csr", feature = "hydrate"))] + { + let handle = window_event_listener(ev::click, move |ev| { + use leptos::wasm_bindgen::__rt::IntoJsResult; + if !is_show_listbox.get_untracked() { + return; + } + let el = ev.target(); + let mut el: Option = + el.into_js_result().map_or(None, |el| Some(el.into())); + let body = document().body().unwrap(); + if let Some(listbox_el) = listbox_ref.get_untracked() { + if let Some(trigger_el) = trigger_ref.get_untracked() { + while let Some(current_el) = el { + if current_el == *body { + break; + }; + if current_el == ***listbox_el { + return; + } + if current_el == ***trigger_el { + return; + } + el = current_el.parent_element(); + } + } + } + is_show_listbox.set(false); + }); + on_cleanup(move || handle.remove()); + } + view! {
+ { + if clearable { + view! { + + }.into() + } else { + None + } + }