nova_forms/components/
select.rs1use std::{fmt::Display, hash::Hash, str::FromStr};
2
3use crate::{use_translation, QueryStringPart, FieldWiring};
4use leptos::*;
5use strum::{IntoEnumIterator, ParseError};
6
7#[component]
9pub fn Select<T>(
10 #[prop(into)] label: TextProp,
12 #[prop(into)] bind: QueryStringPart,
14 #[prop(optional, into)] value: MaybeProp<T>,
16 #[prop(optional, into)] change: Option<Callback<Result<T, T::Err>, ()>>,
18 #[prop(optional, into)] error: MaybeProp<TextProp>,
20) -> impl IntoView
21where
22 T: IntoEnumIterator + FromStr<Err = ParseError> + Into<&'static str> + Clone + Copy + Default + Eq + Hash + Display + 'static
23{
24 let FieldWiring {
25 qs,
26 value,
27 error,
28 set_raw_value,
29 render_mode,
30 raw_value,
31 ..
32 } = FieldWiring::<T>::wire(bind, value, change, error, label.clone());
33
34 let select_elem = view! {
35 <select
36 id=qs.to_string()
37 name=qs.to_string()
38 autocomplete=false
39 prop:value=move || raw_value.get()
40 on:input=move |ev| { set_raw_value.call(event_target_value(&ev));}
41 >
42 <For
43 each={move || T::iter()}
44 key={|item| *item}
45 children={move |item| {
46 let option_elem = html::option()
47 .attr("id", format!("{}({})", qs.to_string(), item.into()))
48 .attr("selected", move || value.get() == Ok(item))
49 .attr("value", move || item.into())
50 .child(use_translation(item));
51
52 view! {
53 {option_elem}
54 }
55 }}
56 />
57 </select>
58 };
59
60 view! {
61 <div
62 class="field select"
63 class:error=move || error.get().is_some()
64 class:ok=move || error.get().is_none()
65 >
66 {move || {
67 if render_mode.get() {
68 if let Ok(value) = value.get() {
69 view!{
70 <span class="label">{label.clone()}</span>
71 <span class="value">{use_translation(value)}</span>
72 }.into_view()
73 } else {
74 view!{
75 <span class="label">{label.clone()}</span>
76 <span class="value"></span>
77 }.into_view()
78 }
79 } else {
80 view! {
81 <label for=qs.to_string()>{label.clone()}</label>
82 {select_elem.clone()}
83 {move || {
84 if let Some(error) = error.get() {
85 view! { <span class="error-message">{error}</span> }
86 .into_view()
87 } else {
88 View::default()
89 }
90 }}
91 }.into_view()
92 }
93 }}
94 </div>
95 }
96}