From 3c2440db49f7107cdb9cbc3f40bf6f0d39ee3d1b Mon Sep 17 00:00:00 2001 From: luoxiao <luoxiaozero@163.com> Date: Sat, 24 Jun 2023 23:38:05 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20add=20select=20component?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib.rs | 1 + src/select/mod.rs | 72 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 src/select/mod.rs diff --git a/src/lib.rs b/src/lib.rs index 30c388b..09c7dc3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ mod menu; pub mod mobile; mod modal; mod progress; +mod select; mod slider; mod space; mod table; diff --git a/src/select/mod.rs b/src/select/mod.rs new file mode 100644 index 0000000..3431206 --- /dev/null +++ b/src/select/mod.rs @@ -0,0 +1,72 @@ +use crate::teleport::Teleport; +use leptos::*; +use std::hash::Hash; + +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct SelectOption<T> { + pub label: String, + pub value: T, +} + +#[component] +pub fn Select<T>( + cx: Scope, + #[prop(into)] value: RwSignal<Option<T>>, + #[prop(optional, into)] options: MaybeSignal<Vec<SelectOption<T>>>, +) -> impl IntoView +where + T: Eq + Hash + Clone + 'static, +{ + let is_show_popover = create_rw_signal(cx, false); + let trigger_ref = create_node_ref::<html::Div>(cx); + let popover_ref = create_node_ref::<html::Div>(cx); + let show_popover = move |_| { + let rect = trigger_ref.get().unwrap().get_bounding_client_rect(); + is_show_popover.set(true); + if let Some(popover_ref) = popover_ref.get() { + popover_ref + .style("width", format!("{}px", rect.width())) + .style( + "transform", + format!( + "translateX({}px) translateY({}px) translateX(-50%)", + rect.x() + rect.width() / 2.0, + rect.y() + rect.height() + ), + ); + } + }; + + let temp_options = options.clone(); + let select_option_label = create_memo(cx, move |_| match value.get() { + Some(value) => temp_options + .get() + .iter() + .find(move |v| v.value == value) + .map_or(String::new(), |v| v.label.clone()), + None => String::new(), + }); + view! { cx, + <div class="melt-select" ref=trigger_ref on:click=show_popover> + { + move || select_option_label.get() + } + </div> + <Teleport> + <div class="melt-select-menu" style=move || if is_show_popover.get() { "display: none" } else { "" } ref=popover_ref> + <For + each=move || options.get() + key=move |item| item.value.clone() + view=move |cx, item| { + view! { cx, + <div class="melt-select-menu__item"> + { item.label } + </div> + } + } + > + </For> + </div> + </Teleport> + } +}