1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use std::{fmt::Display, hash::Hash, str::FromStr};
use crate::{use_translation, QueryStringPart, FieldWiring};
use leptos::*;
use strum::{IntoEnumIterator, ParseError};
/// A component that renders radio buttons from an enum.
#[component]
pub fn Radio<T>(
/// The label of the input field.
#[prop(into)] label: TextProp,
/// The query string that binds the input field to the form data.
#[prop(into)] bind: QueryStringPart,
/// The initial value of the input field.
#[prop(optional, into)] value: MaybeProp<T>,
/// A write signal that is updated with the parsed value of the input field.
#[prop(optional, into)] change: Option<Callback<Result<T, T::Err>, ()>>,
/// Set a custom error message for the input field.
#[prop(optional, into)] error: MaybeProp<TextProp>,
) -> impl IntoView
where
T: IntoEnumIterator + FromStr<Err = ParseError> + Into<&'static str> + Clone + Copy + Default + Eq + Hash + Display + 'static
{
let FieldWiring {
qs,
value,
error,
set_raw_value,
render_mode,
..
} = FieldWiring::<T>::wire(bind, value, change, error, label.clone());
view! {
<div
class="field radio"
class:error=move || error.get().is_some()
class:ok=move || error.get().is_none()
>
{ move || {
if render_mode.get() {
if let Ok(value) = value.get() {
view!{
<span class="label">{label.clone()}</span>
<span class="value">{use_translation(value)}</span>
}.into_view()
} else {
view!{
<span class="label">{label.clone()}</span>
<span class="value"></span>
}.into_view()
}
} else {
view! {
<fieldset>
<legend>{label.clone()}</legend>
<For
each={move || T::iter()}
key={|item| *item}
children={move |item| {
let input_elem = html::input()
.attr("type", "radio")
.attr("id", format!("{}({})", qs.to_string(), item.into()))
.attr("name", qs.to_string())
.attr("checked", move || value.get() == Ok(item))
.attr("value", move || item.into())
.on(ev::input, move |ev| {
set_raw_value.call(event_target_value(&ev));
});
view! {
<label for=format!("{}({})", qs.to_string(), item.into())>
{input_elem}
<span class="custom-radio"></span>
<span class="custom-radio-label">{use_translation(item)}</span>
</label>
}
}}
/>
{move || {
if let Some(error) = error.get() {
view! { <span class="error-message">{error}</span> }
.into_view()
} else {
View::default()
}
}}
</fieldset>
}.into_view()
}
}}
</div>
}
}