nova_forms/components/
radio.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 Radio<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 ..
31 } = FieldWiring::<T>::wire(bind, value, change, error, label.clone());
32
33 view! {
34 <div
35 class="field radio"
36 class:error=move || error.get().is_some()
37 class:ok=move || error.get().is_none()
38 >
39 { move || {
40 if render_mode.get() {
41 if let Ok(value) = value.get() {
42 view!{
43 <span class="label">{label.clone()}</span>
44 <span class="value">{use_translation(value)}</span>
45 }.into_view()
46 } else {
47 view!{
48 <span class="label">{label.clone()}</span>
49 <span class="value"></span>
50 }.into_view()
51 }
52 } else {
53 view! {
54 <fieldset>
55 <legend>{label.clone()}</legend>
56 <For
57 each={move || T::iter()}
58 key={|item| *item}
59 children={move |item| {
60 let input_elem = html::input()
61 .attr("type", "radio")
62 .attr("id", format!("{}({})", qs.to_string(), item.into()))
63 .attr("name", qs.to_string())
64 .attr("checked", move || value.get() == Ok(item))
65 .attr("value", move || item.into())
66 .on(ev::input, move |ev| {
67 set_raw_value.call(event_target_value(&ev));
68 });
69
70 view! {
71 <label for=format!("{}({})", qs.to_string(), item.into())>
72 {input_elem}
73 <span class="custom-radio"></span>
74 <span class="custom-radio-label">{use_translation(item)}</span>
75 </label>
76 }
77 }}
78 />
79 {move || {
80 if let Some(error) = error.get() {
81 view! { <span class="error-message">{error}</span> }
82 .into_view()
83 } else {
84 View::default()
85 }
86 }}
87 </fieldset>
88 }.into_view()
89 }
90 }}
91 </div>
92 }
93}