1use std::{fmt::Display, str::FromStr};
2
3use crate::{use_translation, FormContext, InputContext, QueryString, QueryStringPart};
4use leptos::*;
5
6pub struct FieldWiring<T>
9where
10 T: FromStr + ToString + Clone + Default + 'static,
11 T::Err: Clone + Display,
12{
13 pub qs: QueryString,
14 pub value: Signal<Result<T, T::Err>>,
15 pub raw_value: Signal<String>,
16 pub set_value: Callback<T, ()>,
17 pub set_raw_value: Callback<String, ()>,
18 pub error: Signal<Option<Oco<'static, str>>>,
19 pub render_mode: Signal<bool>,
20 pub disabled: Signal<bool>,
21}
22
23impl<T> FieldWiring<T>
24where
25 T: FromStr + ToString + Clone + Default + 'static,
26 T::Err: Clone + Display
27{
28 pub fn wire(
29 bind: QueryStringPart,
30 external_value: MaybeProp<T>,
31 change: Option<Callback<Result<T, T::Err>, ()>>,
32 error: MaybeProp<TextProp>,
33 label: TextProp,
34 ) -> Self {
35 let input = InputContext::new(bind);
36 input.add_label(label);
37 let qs = input.qs();
38 let validate_signal = input.validate_signal();
39 let nova_form_context = expect_context::<FormContext>();
40 let form_value = input.value();
41 let raw_form_value = input.raw_value();
42 let (show_error, set_show_error) = create_signal(false);
43
44 if cfg!(debug_assertions) {
46 input.set_value(T::default());
47 }
48
49 if let Some(change) = change {
51 create_effect(move |_| {
52 logging::log!("call change callback");
53 change.call(form_value.get());
54 });
55 }
56
57 create_effect(move |_| {
59 if let Some(value) = external_value.get() {
60 logging::log!("update value from external");
61 input.set_value(value);
62 }
63 });
64
65 let set_raw_value = Callback::new(move |value: String| {
66 logging::log!("set_raw_value {}: {}", qs, value);
67 input.set_raw_value(value);
68 set_show_error.set(true);
69 });
70
71 let set_value = Callback::new(move |value: T| {
72 logging::log!("set_value {}: {}", qs, value.to_string());
73 input.set_value(value);
74 set_show_error.set(true);
75 });
76
77 create_effect(move |_| {
78 logging::log!("validate_signal {}", qs);
79 if validate_signal.get() {
80 set_show_error.set(true);
81 }
82 });
83
84 create_effect(move |_| {
85 match form_value.get() {
86 Ok(value) => {
87 logging::log!("form_value changed {}: {}", qs, value.to_string());
88 }
89 Err(err) => {
90 logging::log!("form_value changed {}: {}", qs, err);
91 }
92 }
93 });
94
95 let error_message = Memo::new(move |_| {
96 logging::log!("error_message {}", qs);
97 if let Some(error) = error.get() {
98 Some(error.get())
99 } else
100 if show_error.get() {
101 form_value.get().err().map(|err| use_translation(err).get())
102 } else {
103 None
104 }
105 }).into();
106
107 let disabled = input.disabled();
108
109 let render_mode = Signal::derive(move || nova_form_context.is_render_mode());
110
111 FieldWiring {
112 qs,
113 value: form_value,
114 raw_value: raw_form_value,
115 set_raw_value,
116 set_value,
117 error: error_message,
118 render_mode,
119 disabled,
120 }
121 }
122}