From b992a3eda7efdac513433a3dd01ff214a651a1ae Mon Sep 17 00:00:00 2001 From: luoxiao Date: Thu, 27 Jun 2024 20:28:55 +0800 Subject: [PATCH] refactor: remove Select --- demo/src/app.rs | 2 +- demo/src/pages/components.rs | 8 +- demo_markdown/src/lib.rs | 2 +- thaw/src/select/mod.rs | 95 ----------------- thaw/src/select/multi.rs | 199 ----------------------------------- thaw/src/select/raw.rs | 158 --------------------------- thaw/src/select/select.css | 99 ----------------- thaw/src/select/theme.rs | 32 ------ thaw/src/theme/mod.rs | 5 +- 9 files changed, 7 insertions(+), 593 deletions(-) delete mode 100644 thaw/src/select/mod.rs delete mode 100644 thaw/src/select/multi.rs delete mode 100644 thaw/src/select/raw.rs delete mode 100644 thaw/src/select/select.css delete mode 100644 thaw/src/select/theme.rs diff --git a/demo/src/app.rs b/demo/src/app.rs index 9eb5d89..d9bcb0b 100644 --- a/demo/src/app.rs +++ b/demo/src/app.rs @@ -76,7 +76,7 @@ fn TheRouter(is_routing: RwSignal) -> impl IntoView { - + // diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index ed7c29d..d32c3ce 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -255,10 +255,10 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/scrollbar".into(), label: "Scrollbar".into(), }, - MenuItemOption { - value: "/components/select".into(), - label: "Select".into(), - }, + // MenuItemOption { + // value: "/components/select".into(), + // label: "Select".into(), + // }, MenuItemOption { value: "/components/skeleton".into(), label: "Skeleton".into(), diff --git a/demo_markdown/src/lib.rs b/demo_markdown/src/lib.rs index 5fb6821..d1e7060 100644 --- a/demo_markdown/src/lib.rs +++ b/demo_markdown/src/lib.rs @@ -58,7 +58,7 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt "ProgressMdPage" => "../docs/progress/mod.md", "RadioMdPage" => "../docs/radio/mod.md", "ScrollbarMdPage" => "../docs/scrollbar/mod.md", - "SelectMdPage" => "../docs/select/mod.md", + // "SelectMdPage" => "../docs/select/mod.md", "SkeletonMdPage" => "../docs/skeleton/mod.md", "SliderMdPage" => "../docs/slider/mod.md", "SpaceMdPage" => "../docs/space/mod.md", diff --git a/thaw/src/select/mod.rs b/thaw/src/select/mod.rs deleted file mode 100644 index 12fa91b..0000000 --- a/thaw/src/select/mod.rs +++ /dev/null @@ -1,95 +0,0 @@ -mod multi; -mod raw; -mod theme; - -pub use multi::*; -pub use theme::SelectTheme; - -use leptos::*; -use std::{hash::Hash, rc::Rc}; -use thaw_utils::{Model, OptionalProp}; - -use crate::{ - select::raw::{RawSelect, SelectIcon}, - Icon, -}; - -#[slot] -pub struct SelectLabel { - children: Children, -} - -#[derive(Clone, Default, PartialEq, Eq, Hash)] -pub struct SelectOption { - pub label: String, - pub value: T, -} - -impl SelectOption { - pub fn new(label: impl Into, value: T) -> SelectOption { - SelectOption { - label: label.into(), - value, - } - } -} - -#[component] -pub fn Select( - #[prop(optional, into)] value: Model>, - #[prop(optional, into)] options: MaybeSignal>>, - #[prop(optional, into)] class: OptionalProp>, - #[prop(optional)] select_label: Option, -) -> impl IntoView -where - T: Eq + Hash + Clone + 'static, -{ - let is_menu_visible = create_rw_signal(false); - let show_menu = move |_| is_menu_visible.set(true); - let hide_menu = move |_| is_menu_visible.set(false); - let is_selected = move |v: &T| with!(|value| value.as_ref() == Some(v)); - let on_select: Callback<(ev::MouseEvent, SelectOption)> = - Callback::new(move |(_, option): (ev::MouseEvent, SelectOption)| { - let item_value = option.value; - value.set(Some(item_value)); - hide_menu(()); - }); - let select_label = select_label.unwrap_or_else(|| { - let options = options.clone(); - let value_label = Signal::derive(move || { - with!(|value, options| { - match value { - Some(value) => options - .iter() - .find(|opt| &opt.value == value) - .map_or(String::new(), |v| v.label.clone()), - None => String::new(), - } - }) - }); - SelectLabel { - children: Box::new(move || Fragment::new(vec![value_label.into_view()])), - } - }); - let select_icon = SelectIcon { - children: Rc::new(move || { - Fragment::new(vec![ - view! { }.into_view() - ]) - }), - }; - - view! { - - } -} diff --git a/thaw/src/select/multi.rs b/thaw/src/select/multi.rs deleted file mode 100644 index 715ab51..0000000 --- a/thaw/src/select/multi.rs +++ /dev/null @@ -1,199 +0,0 @@ -use leptos::*; -use std::{hash::Hash, rc::Rc, time::Duration}; -use thaw_utils::{Model, OptionalProp}; - -use crate::{ - select::raw::{RawSelect, SelectIcon}, - Icon, SelectLabel, SelectOption, Tag, TagVariant, -}; - -#[derive(Clone, Default, PartialEq, Eq, Hash)] -pub struct MultiSelectOption { - pub label: String, - pub value: T, - pub variant: TagVariant, -} - -impl MultiSelectOption { - pub fn new(label: impl Into, value: T) -> MultiSelectOption { - MultiSelectOption { - label: label.into(), - value, - variant: TagVariant::Default, - } - } - - pub fn with_variant(mut self, variant: TagVariant) -> MultiSelectOption { - self.variant = variant; - self - } -} - -impl From> for SelectOption { - fn from(opt: MultiSelectOption) -> Self { - SelectOption { - label: opt.label, - value: opt.value, - } - } -} - -#[component] -pub fn MultiSelect( - #[prop(optional, into)] value: Model>, - #[prop(optional, into)] options: MaybeSignal>>, - #[prop(optional, into)] class: OptionalProp>, - #[prop(optional, into)] clearable: MaybeSignal, - #[prop(optional)] select_label: Option, -) -> impl IntoView -where - T: Eq + Hash + Clone + 'static, -{ - let select_options: Signal> = Signal::derive({ - let options = options.clone(); - move || options.get().into_iter().map(SelectOption::from).collect() - }); - let class: OptionalProp<_> = match class.into_option() { - Some(MaybeSignal::Dynamic(class)) => { - Some(MaybeSignal::Dynamic(Signal::derive(move || { - with!(|class| format!("thaw-select--multiple {class}")) - }))) - .into() - } - Some(MaybeSignal::Static(class)) => Some(MaybeSignal::Static(format!( - "thaw-select--multiple {class}" - ))) - .into(), - None => Some(MaybeSignal::Static("thaw-select--multiple".to_string())).into(), - }; - let is_menu_visible = create_rw_signal(false); - let show_menu = move |_| is_menu_visible.set(true); - let hide_menu = move |_| is_menu_visible.set(false); - let is_selected = move |v: &T| with!(|value| value.contains(v)); - let on_select: Callback<(ev::MouseEvent, SelectOption)> = - Callback::new(move |(_, option): (ev::MouseEvent, SelectOption)| { - let item_value = option.value; - update!(|value| { - let index = value - .iter() - .enumerate() - .find_map(|(i, v)| (v == &item_value).then_some(i)); - match index { - Some(i) => { - value.remove(i); - } - None => { - value.push(item_value); - } - } - }); - }); - let select_label = select_label.unwrap_or_else(|| { - let options = options.clone(); - let signal_value = value; - let value_label = Signal::derive(move || { - with!(|value, options| { - value - .iter() - .map(|value| { - let (label, variant) = options - .iter() - .find(move |v| &v.value == value) - .map_or((String::new(), TagVariant::Default), |v| { - (v.label.clone(), v.variant) - }); - let value = value.clone(); - let on_close = Callback::new(move |ev: ev::MouseEvent| { - ev.stop_propagation(); - let value = value.clone(); - // We remove the item on the next tick to ensure the menu on click handler works correctly - set_timeout( - move || { - update!(|signal_value| { - let index = signal_value - .iter() - .enumerate() - .find_map(|(i, v)| (v == &value).then_some(i)); - if let Some(i) = index { - signal_value.remove(i); - } - }); - }, - Duration::ZERO, - ) - }); - view! { - - {label} - - } - }) - .collect_view() - }) - }); - SelectLabel { - children: Box::new(move || Fragment::new(vec![value_label.into_view()])), - } - }); - let is_hovered = RwSignal::new(false); - let show_clear_icon = Signal::derive(move || { - clearable.get() - && ((is_hovered.get() || is_menu_visible.get()) && with!(|value| !value.is_empty())) - }); - let on_hover_enter = Callback::new(move |_| is_hovered.set(true)); - let on_hover_exit = Callback::new(move |_| is_hovered.set(false)); - let select_icon = SelectIcon { - children: Rc::new(move || { - Fragment::new(vec![view! { - {move || if show_clear_icon.get() { - view! { - - } - } else { - view! { - - } - }} - } - .into_view()]) - }), - }; - - // Trigger the following menu to resync when the value is updated - let _ = watch( - move || value.track(), - move |_, _, _| { - is_menu_visible.update(|_| {}); - }, - false, - ); - - view! { - - } -} diff --git a/thaw/src/select/raw.rs b/thaw/src/select/raw.rs deleted file mode 100644 index 7099f57..0000000 --- a/thaw/src/select/raw.rs +++ /dev/null @@ -1,158 +0,0 @@ -use std::{hash::Hash, time::Duration}; - -use leptos::*; -use thaw_components::{Binder, CSSTransition, Follower, FollowerPlacement, FollowerWidth}; -use thaw_utils::{class_list, mount_style, OptionalProp}; - -use crate::{theme::use_theme, SelectLabel, SelectOption, Theme}; - -#[slot] -pub(crate) struct SelectIcon { - children: ChildrenFn, -} - -#[component] -pub(super) fn RawSelect( - #[prop(optional, into)] options: MaybeSignal>>, - #[prop(optional, into)] class: OptionalProp>, - select_label: SelectLabel, - select_icon: SelectIcon, - #[prop(optional, into)] is_menu_visible: Signal, - #[prop(into)] on_select: Callback<(ev::MouseEvent, SelectOption)>, - #[prop(into)] show_menu: Callback<()>, - #[prop(into)] hide_menu: Callback<()>, - #[prop(optional, into)] on_hover_enter: Option>, - #[prop(optional, into)] on_hover_exit: Option>, - is_selected: F, -) -> impl IntoView -where - T: Eq + Hash + Clone + 'static, - F: Fn(&T) -> bool + Copy + 'static, -{ - mount_style("select", include_str!("./select.css")); - - let trigger_ref = create_node_ref::(); - let menu_ref = create_node_ref::(); - - #[cfg(any(feature = "csr", feature = "hydrate"))] - { - use leptos::wasm_bindgen::__rt::IntoJsResult; - let listener = window_event_listener(ev::click, move |ev| { - let el = ev.target(); - let el: Option = el.into_js_result().map_or(None, |el| Some(el.into())); - let is_descendent_of_select = trigger_ref.get().unwrap().contains(el.as_ref()); - let is_descendent_of_menu = menu_ref.get().unwrap().contains(el.as_ref()); - if (!is_descendent_of_select && !is_descendent_of_menu) - || (is_menu_visible.get() && el.unwrap() == ****trigger_ref.get().unwrap()) - { - hide_menu.call(()); - } - }); - on_cleanup(move || listener.remove()); - } - - let theme = use_theme(Theme::light); - let css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - theme.with(|theme| { - let border_color_hover = theme.common.color_primary.clone(); - css_vars.push_str(&format!("--thaw-border-color-hover: {border_color_hover};")); - css_vars.push_str(&format!( - "--thaw-background-color: {};", - theme.select.background_color - )); - css_vars.push_str(&format!("--thaw-font-color: {};", theme.select.font_color)); - css_vars.push_str(&format!( - "--thaw-border-color: {};", - theme.select.border_color - )); - }); - - css_vars - }); - - let menu_css_vars = create_memo(move |_| { - let mut css_vars = String::new(); - theme.with(|theme| { - css_vars.push_str(&format!( - "--thaw-background-color: {};", - theme.select.menu_background_color - )); - css_vars.push_str(&format!( - "--thaw-background-color-hover: {};", - theme.select.menu_background_color_hover - )); - css_vars.push_str(&format!("--thaw-font-color: {};", theme.select.font_color)); - css_vars.push_str(&format!( - "--thaw-font-color-selected: {};", - theme.common.color_primary - )); - }); - css_vars - }); - - view! { - -
- {(select_label.children)()} - {select_icon.children} -
- - -
- - {item.get_value().label} -
- } - } - /> - -
-
-
- } -} diff --git a/thaw/src/select/select.css b/thaw/src/select/select.css deleted file mode 100644 index 3dc6dbf..0000000 --- a/thaw/src/select/select.css +++ /dev/null @@ -1,99 +0,0 @@ -.thaw-select { - position: relative; - display: flex; - align-items: center; - flex-wrap: wrap; - padding: 0 30px 0 10px; - min-height: 34px; - background-color: var(--thaw-background-color); - font-size: 14px; - color: var(--thaw-font-color); - border: 1px solid var(--thaw-border-color); - border-radius: 3px; - transition: all 0.3s; - cursor: pointer; - box-sizing: border-box; -} - -.thaw-select.thaw-select--multiple { - padding: 3px 30px 0 3px; -} - -.thaw-select-dropdown-icon { - position: absolute; - right: 10px; - top: 50%; - transform: translateY(-50%); - font-size: 12px; - opacity: 40%; - pointer-events: none; -} - -.thaw-select-dropdown-icon--clear { - pointer-events: auto; -} - -.thaw-select.thaw-select--multiple .thaw-tag { - height: 24px; - margin: 0 3px 3px 0; -} - -.thaw-select:hover { - border-color: var(--thaw-border-color-hover); -} - -.thaw-select-menu { - font-size: 14px; - color: var(--thaw-font-color); - background-color: var(--thaw-background-color); - box-sizing: border-box; - padding: 5px; - width: 100%; - max-height: 200px; - border-radius: 3px; - box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12), - 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05); - overflow: auto; -} - -.thaw-select-menu__item { - padding: 6px 5px; - border-radius: 2px; - cursor: pointer; -} - -.thaw-select-menu__item:hover { - background-color: var(--thaw-background-color-hover); -} - -.thaw-select-menu__item-selected { - color: var(--thaw-font-color-selected); -} - -.thaw-select-menu.fade-in-scale-up-transition-leave-active { - transform-origin: inherit; - transition: opacity 0.2s cubic-bezier(0.4, 0, 1, 1), - transform 0.2s cubic-bezier(0.4, 0, 1, 1), - background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1), - box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1); -} - -.thaw-select-menu.fade-in-scale-up-transition-enter-active { - transform-origin: inherit; - transition: opacity 0.2s cubic-bezier(0, 0, 0.2, 1), - transform 0.2s cubic-bezier(0, 0, 0.2, 1), - background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1), - box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1); -} - -.thaw-select-menu.fade-in-scale-up-transition-enter-from, -.thaw-select-menu.fade-in-scale-up-transition-leave-to { - opacity: 0; - transform: scale(0.9); -} - -.thaw-select-menu.fade-in-scale-up-transition-leave-from, -.thaw-select-menu.fade-in-scale-up-transition-enter-to { - opacity: 1; - transform: scale(1); -} diff --git a/thaw/src/select/theme.rs b/thaw/src/select/theme.rs deleted file mode 100644 index 3e46f19..0000000 --- a/thaw/src/select/theme.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::theme::ThemeMethod; - -#[derive(Clone)] -pub struct SelectTheme { - pub font_color: String, - pub border_color: String, - pub background_color: String, - pub menu_background_color: String, - pub menu_background_color_hover: String, -} - -impl ThemeMethod for SelectTheme { - fn light() -> Self { - Self { - font_color: "#333639".into(), - border_color: "#e0e0e6".into(), - background_color: "#fff".into(), - menu_background_color: "#fff".into(), - menu_background_color_hover: "#f3f5f6".into(), - } - } - - fn dark() -> Self { - Self { - font_color: "#ffffffd1".into(), - border_color: "#0000".into(), - background_color: "#ffffff1a".into(), - menu_background_color: "#48484e".into(), - menu_background_color_hover: "#ffffff17".into(), - } - } -} diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index 2e75a14..5270a75 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -2,7 +2,7 @@ mod color; mod common; use self::common::CommonTheme; -use crate::{AlertTheme, AnchorTheme, MessageTheme, ProgressTheme, SelectTheme}; +use crate::{AlertTheme, AnchorTheme, MessageTheme, ProgressTheme}; pub use color::ColorTheme; use leptos::*; @@ -18,7 +18,6 @@ pub struct Theme { pub color: ColorTheme, pub alert: AlertTheme, pub message: MessageTheme, - pub select: SelectTheme, pub progress: ProgressTheme, pub anchor: AnchorTheme, } @@ -31,7 +30,6 @@ impl Theme { color: ColorTheme::light(), alert: AlertTheme::light(), message: MessageTheme::light(), - select: SelectTheme::light(), progress: ProgressTheme::light(), anchor: AnchorTheme::light(), } @@ -43,7 +41,6 @@ impl Theme { color: ColorTheme::dark(), alert: AlertTheme::dark(), message: MessageTheme::dark(), - select: SelectTheme::dark(), progress: ProgressTheme::dark(), anchor: AnchorTheme::dark(), }