Skip to main content

leptos_form_tool/controls/
mod.rs

1//! This module contains all the possible controls that you
2//! can use to build a form.
3
4use crate::{form::FormToolData, styles::FormStyle};
5use leptos::{
6    prelude::{AnyView, RwSignal, Signal},
7    reactive::wrappers::write::SignalSetter,
8};
9use std::{
10    fmt::Display,
11    marker::{Send, Sync},
12    str::FromStr,
13    sync::Arc,
14};
15
16pub mod button;
17pub mod checkbox;
18pub mod custom;
19pub mod group;
20pub mod heading;
21pub mod hidden;
22pub mod output;
23pub mod radio_buttons;
24pub mod select;
25pub mod slider;
26pub mod spacer;
27pub mod stepper;
28pub mod submit;
29pub mod text_area;
30pub mod text_input;
31
32pub trait BuilderFn<B>: Fn(B) -> B {}
33pub trait BuilderCxFn<B, CX>: Fn(B, Arc<CX>) -> B {}
34pub trait ValidationFn<FDT: ?Sized>:
35    Fn(&FDT) -> Result<(), String> + Send + Sync + 'static
36{
37}
38pub trait ValidationCb: Fn() -> bool + 'static {}
39pub trait ParseFn<CR, FDT>: Fn(CR) -> Result<FDT, String> + Send + Sync + 'static {}
40pub trait UnparseFn<CR, FDT>: Fn(FDT) -> CR + 'static {}
41pub trait FieldGetter<FD, FDT>: Fn(&FD) -> FDT + Send + Sync + 'static {}
42pub trait FieldSetter<FD, FDT>: Fn(&mut FD, FDT) + Send + Sync + 'static {}
43pub trait ShowWhenFn<FD: Send + Sync + 'static, CX: Send + Sync>:
44    Fn(Signal<FD>, Arc<CX>) -> bool + Send + Sync
45{
46}
47pub trait RenderFn<FS, FD: 'static>:
48    FnOnce(Arc<FS>, RwSignal<FD>) -> (AnyView, Option<Box<dyn ValidationCb>>) + 'static
49{
50}
51
52// implement the traits for all valid types
53impl<B, T> BuilderFn<B> for T where T: Fn(B) -> B {}
54impl<B, CX, T> BuilderCxFn<B, CX> for T where T: Fn(B, Arc<CX>) -> B {}
55impl<FDT, T> ValidationFn<FDT> for T where T: Fn(&FDT) -> Result<(), String> + Send + Sync + 'static {}
56impl<T> ValidationCb for T where T: Fn() -> bool + 'static {}
57impl<CR, FDT, F> ParseFn<CR, FDT> for F where
58    F: Fn(CR) -> Result<FDT, String> + Send + Sync + 'static
59{
60}
61impl<CR, FDT, F> UnparseFn<CR, FDT> for F where F: Fn(FDT) -> CR + 'static {}
62impl<FD, FDT, F> FieldGetter<FD, FDT> for F where F: Fn(&FD) -> FDT + Send + Sync + 'static {}
63impl<FD, FDT, F> FieldSetter<FD, FDT> for F where F: Fn(&mut FD, FDT) + Send + Sync + 'static {}
64impl<FD: Send + Sync + 'static, CX: Send + Sync, F> ShowWhenFn<FD, CX> for F where
65    F: Fn(Signal<FD>, Arc<CX>) -> bool + Send + Sync
66{
67}
68impl<FS, FD: 'static, F> RenderFn<FS, FD> for F where
69    F: FnOnce(Arc<FS>, RwSignal<FD>) -> (AnyView, Option<Box<dyn ValidationCb>>) + 'static
70{
71}
72
73/// The possible states for a validated control
74#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
75pub enum ValidationState {
76    /// Parsing and validation passed. No errors
77    #[default]
78    Passed,
79    /// Error when parsing the field.
80    ParseError(String),
81    /// Error when validating the field.
82    ValidationError(String),
83}
84impl ValidationState {
85    /// Gets the error message if there is a parse or validation error.
86    pub fn msg(&self) -> Option<&String> {
87        match self {
88            ValidationState::Passed => None,
89            ValidationState::ParseError(e) => Some(e),
90            ValidationState::ValidationError(e) => Some(e),
91        }
92    }
93    /// Takes the error message if there is a parse or validation error.
94    pub fn take_msg(self) -> Option<String> {
95        match self {
96            ValidationState::Passed => None,
97            ValidationState::ParseError(e) => Some(e),
98            ValidationState::ValidationError(e) => Some(e),
99        }
100    }
101
102    /// Returns true if self is `Passed`.
103    pub fn is_passed(&self) -> bool {
104        matches!(self, ValidationState::Passed)
105    }
106    /// Returns true if self is either `ParseError` or `ValidationError`.
107    pub fn is_err(&self) -> bool {
108        !self.is_passed()
109    }
110
111    /// Returns true if self is `ParseError`.
112    pub fn is_parse_err(&self) -> bool {
113        matches!(self, ValidationState::ParseError(_))
114    }
115
116    /// Returns true if self is `ValidationError`.
117    pub fn is_validation_err(&self) -> bool {
118        matches!(self, ValidationState::ValidationError(_))
119    }
120}
121
122/// The possibilities for when a control updates the form data.
123#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
124pub enum UpdateEvent {
125    OnFocusout,
126    OnInput,
127    #[default]
128    OnChange,
129}
130
131/// A trait for the data needed to render an read-only control.
132pub trait VanityControlData<FD: FormToolData>: Clone + Send + Sync + 'static {
133    /// Builds the control, returning the [`AnyView`] that was built.
134    fn render_control<FS: FormStyle>(
135        fs: &FS,
136        fd: RwSignal<FD>,
137        control: ControlRenderData<FS, Self>,
138        value_getter: Option<Signal<String>>,
139    ) -> AnyView;
140}
141pub trait GetterVanityControlData<FD: FormToolData>: VanityControlData<FD> {}
142
143/// A trait for the data needed to render an interactive control.
144pub trait ControlData<FD: FormToolData>: Clone + Send + Sync + 'static {
145    /// This is the data type returned by this control. Usually a [`String`].
146    type ReturnType: Clone + Send + Sync;
147
148    /// Builds the control, returning the [`AnyView`] that was built.
149    fn render_control<FS: FormStyle>(
150        fs: &FS,
151        fd: RwSignal<FD>,
152        control: ControlRenderData<FS, Self>,
153        value_getter: Signal<Self::ReturnType>,
154        value_setter: SignalSetter<Self::ReturnType>,
155        validation_state: Signal<ValidationState>,
156    ) -> AnyView;
157}
158pub trait ValidatedControlData<FD: FormToolData>: ControlData<FD> {}
159
160/// The data needed to render a interactive control of type `C`.
161pub struct ControlRenderData<FS: FormStyle + ?Sized, C: ?Sized> {
162    pub styles: Vec<FS::StylingAttributes>,
163    pub data: C,
164}
165impl<FS, C> Clone for ControlRenderData<FS, C>
166where
167    FS: FormStyle + ?Sized,
168    C: Clone,
169{
170    fn clone(&self) -> Self {
171        ControlRenderData {
172            styles: self.styles.clone(),
173            data: self.data.clone(),
174        }
175    }
176}
177
178/// The data needed to render a read-only control of type `C`.
179pub struct VanityControlBuilder<FD: FormToolData, C: VanityControlData<FD>> {
180    pub(crate) style_attributes: Vec<<FD::Style as FormStyle>::StylingAttributes>,
181    pub data: C,
182    pub(crate) getter: Option<Arc<dyn FieldGetter<FD, String>>>,
183    pub(crate) show_when: Option<Arc<dyn ShowWhenFn<FD, FD::Context>>>,
184}
185
186pub(crate) struct BuiltVanityControlData<FD: FormToolData, C: VanityControlData<FD>> {
187    pub(crate) render_data: ControlRenderData<FD::Style, C>,
188    pub(crate) getter: Option<Arc<dyn FieldGetter<FD, String>>>,
189    pub(crate) show_when: Option<Arc<dyn ShowWhenFn<FD, FD::Context>>>,
190}
191
192impl<FD: FormToolData, C: VanityControlData<FD>> VanityControlBuilder<FD, C> {
193    /// Creates a new [`VanityControlBuilder`] with the given [`VanityControlData`].
194    pub(crate) fn new(data: C) -> Self {
195        VanityControlBuilder {
196            data,
197            style_attributes: Vec::new(),
198            getter: None,
199            show_when: None,
200        }
201    }
202
203    /// Builds the builder into the data needed to render the control.
204    pub(crate) fn build(self) -> BuiltVanityControlData<FD, C> {
205        BuiltVanityControlData {
206            render_data: ControlRenderData {
207                data: self.data,
208                styles: self.style_attributes,
209            },
210            getter: self.getter,
211            show_when: self.show_when,
212        }
213    }
214
215    /// Sets the function to decide when to render the control.
216    ///
217    /// Validations for components that are not shown DO NOT run.
218    pub fn show_when(
219        mut self,
220        when: impl Fn(Signal<FD>, Arc<FD::Context>) -> bool + Send + Sync + 'static,
221    ) -> Self {
222        self.show_when = Some(Arc::new(when));
223        self
224    }
225
226    /// Adds a styling attribute to this control.
227    pub fn style(mut self, attribute: <FD::Style as FormStyle>::StylingAttributes) -> Self {
228        self.style_attributes.push(attribute);
229        self
230    }
231}
232
233impl<FD: FormToolData, C: GetterVanityControlData<FD>> VanityControlBuilder<FD, C> {
234    /// Sets the getter function.
235    ///
236    /// This function can get a string from the form data to be displayed
237    ///
238    /// Setting this getter field is NOT required for vanity controls like this one.
239    pub fn getter(mut self, getter: impl FieldGetter<FD, String>) -> Self {
240        self.getter = Some(Arc::new(getter));
241        self
242    }
243}
244
245/// The possibilities for errors when building a control.
246#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
247pub enum ControlBuildError {
248    /// The getter field was not specified.
249    MissingGetter,
250    /// The setter field was not specified.
251    MissingSetter,
252    /// The parse function was not specified.
253    MissingParseFn,
254    /// The unparse function was not specified.
255    MissingUnParseFn,
256}
257impl Display for ControlBuildError {
258    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
259        let message = match self {
260            ControlBuildError::MissingGetter => "missing getter function",
261            ControlBuildError::MissingSetter => "missing setter function",
262            ControlBuildError::MissingParseFn => "missing parse function",
263            ControlBuildError::MissingUnParseFn => "missing unparse function",
264        };
265        write!(f, "{}", message)
266    }
267}
268
269/// The data returned from a control's build function.
270pub(crate) struct BuiltControlData<FD: FormToolData, C: ControlData<FD>, FDT> {
271    pub(crate) render_data: ControlRenderData<FD::Style, C>,
272    pub(crate) getter: Arc<dyn FieldGetter<FD, FDT>>,
273    pub(crate) setter: Arc<dyn FieldSetter<FD, FDT>>,
274    pub(crate) parse_fn: Box<dyn ParseFn<C::ReturnType, FDT>>,
275    pub(crate) unparse_fn: Box<dyn UnparseFn<C::ReturnType, FDT>>,
276    pub(crate) validation_fn: Option<Arc<dyn ValidationFn<FD>>>,
277    pub(crate) show_when: Option<Arc<dyn ShowWhenFn<FD, FD::Context>>>,
278}
279
280/// A builder for a interactive control.
281pub struct ControlBuilder<FD: FormToolData, C: ControlData<FD>, FDT> {
282    pub(crate) getter: Option<Arc<dyn FieldGetter<FD, FDT>>>,
283    pub(crate) setter: Option<Arc<dyn FieldSetter<FD, FDT>>>,
284    pub(crate) parse_fn: Option<Box<dyn ParseFn<C::ReturnType, FDT>>>,
285    pub(crate) unparse_fn: Option<Box<dyn UnparseFn<C::ReturnType, FDT>>>,
286    pub(crate) validation_fn: Option<Arc<dyn ValidationFn<FD>>>,
287    pub(crate) style_attributes: Vec<<FD::Style as FormStyle>::StylingAttributes>,
288    pub(crate) show_when: Option<Arc<dyn ShowWhenFn<FD, FD::Context>>>,
289    pub data: C,
290}
291
292impl<FD: FormToolData, C: ControlData<FD>, FDT> ControlBuilder<FD, C, FDT> {
293    /// Creates a new [`ControlBuilder`] with the given [`ControlData`].
294    pub(crate) fn new(data: C) -> Self {
295        ControlBuilder {
296            data,
297            getter: None,
298            setter: None,
299            parse_fn: None,
300            unparse_fn: None,
301            validation_fn: None,
302            style_attributes: Vec::new(),
303            show_when: None,
304        }
305    }
306
307    /// Builds the builder into the data needed to render the control.
308    ///
309    /// This fails if a required field was not specified.
310    pub(crate) fn build(self) -> Result<BuiltControlData<FD, C, FDT>, ControlBuildError> {
311        let getter = match self.getter {
312            Some(getter) => getter,
313            None => return Err(ControlBuildError::MissingGetter),
314        };
315        let setter = match self.setter {
316            Some(setter) => setter,
317            None => return Err(ControlBuildError::MissingSetter),
318        };
319        let parse_fn = match self.parse_fn {
320            Some(parse_fn) => parse_fn,
321            None => return Err(ControlBuildError::MissingParseFn),
322        };
323        let unparse_fn = match self.unparse_fn {
324            Some(unparse_fn) => unparse_fn,
325            None => return Err(ControlBuildError::MissingUnParseFn),
326        };
327
328        Ok(BuiltControlData {
329            render_data: ControlRenderData {
330                data: self.data,
331                styles: self.style_attributes,
332            },
333            getter,
334            setter,
335            parse_fn,
336            unparse_fn,
337            validation_fn: self.validation_fn,
338            show_when: self.show_when,
339        })
340    }
341
342    /// Sets the function to decide when to render the control.
343    ///
344    /// Validations for components that are not shown DO NOT run.
345    pub fn show_when(
346        mut self,
347        when: impl Fn(Signal<FD>, Arc<FD::Context>) -> bool + Send + Sync + 'static,
348    ) -> Self {
349        self.show_when = Some(Arc::new(when));
350        self
351    }
352
353    /// Sets the getter function.
354    ///
355    /// This function should get the field from the form data
356    /// for use in the form field.
357    ///
358    /// Setting this getter field is required.
359    pub fn getter(mut self, getter: impl FieldGetter<FD, FDT>) -> Self {
360        self.getter = Some(Arc::new(getter));
361        self
362    }
363
364    /// Sets the setter function.
365    ///
366    /// This function should get the field from the form data
367    /// for use in the form field.
368    ///
369    /// Setting this setter field is required.
370    pub fn setter(mut self, setter: impl FieldSetter<FD, FDT>) -> Self {
371        self.setter = Some(Arc::new(setter));
372        self
373    }
374
375    /// Sets the parse functions to the ones given.
376    ///
377    /// The parse and unparse functions define how to turn what the user
378    /// types in the form into what is stored in the form data struct and
379    /// vice versa.
380    pub fn parse_custom(
381        mut self,
382        parse_fn: impl ParseFn<C::ReturnType, FDT>,
383        unparse_fn: impl UnparseFn<C::ReturnType, FDT>,
384    ) -> Self {
385        self.parse_fn = Some(Box::new(parse_fn));
386        self.unparse_fn = Some(Box::new(unparse_fn));
387        self
388    }
389
390    /// Adds a styling attribute to this control.
391    pub fn style(mut self, attribute: <FD::Style as FormStyle>::StylingAttributes) -> Self {
392        self.style_attributes.push(attribute);
393        self
394    }
395}
396
397impl<FD, C, FDT> ControlBuilder<FD, C, FDT>
398where
399    FD: FormToolData,
400    C: ControlData<FD>,
401    FDT: TryFrom<<C as ControlData<FD>>::ReturnType>,
402    <FDT as TryFrom<<C as ControlData<FD>>::ReturnType>>::Error: ToString,
403    <C as ControlData<FD>>::ReturnType: From<FDT>,
404{
405    /// Sets the parse functions to use the [`TryFrom`] and [`From`] traits
406    /// for parsing and unparsing respectively.
407    ///
408    /// The parse and unparse functions define how to turn what the user
409    /// types in the form into what is stored in the form data struct and
410    /// vice versa.
411    pub fn parse_from(mut self) -> Self {
412        self.parse_fn = Some(Box::new(|control_return_value| {
413            FDT::try_from(control_return_value).map_err(|e| e.to_string())
414        }));
415        self.unparse_fn = Some(Box::new(|field| {
416            <C as ControlData<FD>>::ReturnType::from(field)
417        }));
418        self
419    }
420}
421
422impl<FD, C, FDT> ControlBuilder<FD, C, FDT>
423where
424    FD: FormToolData,
425    C: ControlData<FD>,
426    FDT: TryFrom<<C as ControlData<FD>>::ReturnType>,
427    <C as ControlData<FD>>::ReturnType: From<FDT>,
428{
429    /// Sets the parse functions to use the [`TryFrom`] and [`From`] traits
430    /// for parsing and unparsing respectively, with a custom error message.
431    ///
432    /// The parse and unparse functions define how to turn what the user
433    /// types in the form into what is stored in the form data struct and
434    /// vice versa.
435    pub fn parse_from_msg(mut self, msg: impl ToString + Send + Sync + 'static) -> Self {
436        self.parse_fn = Some(Box::new(move |control_return_value| {
437            FDT::try_from(control_return_value).map_err(|_| msg.to_string())
438        }));
439        self.unparse_fn = Some(Box::new(|field| {
440            <C as ControlData<FD>>::ReturnType::from(field)
441        }));
442        self
443    }
444}
445
446impl<FD, C, FDT> ControlBuilder<FD, C, FDT>
447where
448    FD: FormToolData,
449    C: ControlData<FD, ReturnType = String>,
450    FDT: FromStr + ToString,
451    <FDT as FromStr>::Err: ToString,
452{
453    /// Sets the parse functions to use the [`FromStr`] [`ToString`] and traits
454    /// for parsing and unparsing respectively. To trim the string before
455    /// parsing, see [`parse_trimmed`](Self::parse_trimmed)().
456    ///
457    /// The parse and unparse functions define how to turn what the user
458    /// types in the form into what is stored in the form data struct and
459    /// vice versa.
460    pub fn parse_string(mut self) -> Self {
461        self.parse_fn = Some(Box::new(|control_return_value| {
462            control_return_value
463                .parse::<FDT>()
464                .map_err(|e| e.to_string())
465        }));
466        self.unparse_fn = Some(Box::new(|field| field.to_string()));
467        self
468    }
469
470    /// Sets the parse functions to use the [`FromStr`] [`ToString`] and traits
471    /// for parsing and unparsing respectively, similar to
472    /// [`parse_string`](Self::parse_string)().
473    /// However, this method trims the string before parsing.
474    ///
475    /// The parse and unparse functions define how to turn what the user
476    /// types in the form into what is stored in the form data struct and
477    /// vice versa.
478    pub fn parse_trimmed(mut self) -> Self {
479        self.parse_fn = Some(Box::new(|control_return_value| {
480            control_return_value
481                .trim()
482                .parse::<FDT>()
483                .map_err(|e| e.to_string())
484        }));
485        self.unparse_fn = Some(Box::new(|field| field.to_string()));
486        self
487    }
488
489    /// Sets the parse functions to use the [`FromStr`] [`ToString`] and
490    /// traits. Similar to [`parse_string`](Self::parse_string).
491    ///
492    /// The message passed in is the error message.
493    ///
494    /// The parse and unparse functions define how to turn what the user
495    /// types in the form into what is stored in the form data struct and
496    /// vice versa.
497    pub fn parse_string_msg(mut self, msg: impl ToString + Send + Sync + 'static) -> Self {
498        self.parse_fn = Some(Box::new(move |control_return_value| {
499            control_return_value
500                .parse::<FDT>()
501                .map_err(|_| msg.to_string())
502        }));
503        self.unparse_fn = Some(Box::new(|field| field.to_string()));
504        self
505    }
506
507    /// Sets the parse functions to use the [`FromStr`] [`ToString`] and
508    /// traits, trimming beforehand. Similar to
509    /// [`parse_trimmed`](Self::parse_trimmed).
510    ///
511    /// The message passed in is the error message.
512    ///
513    /// The parse and unparse functions define how to turn what the user
514    /// types in the form into what is stored in the form data struct and
515    /// vice versa.
516    pub fn parse_trimmed_msg(mut self, msg: impl ToString + Send + Sync + 'static) -> Self {
517        self.parse_fn = Some(Box::new(move |control_return_value| {
518            control_return_value
519                .trim()
520                .parse::<FDT>()
521                .map_err(|_| msg.to_string())
522        }));
523        self.unparse_fn = Some(Box::new(|field| field.to_string()));
524        self
525    }
526}
527
528impl<FD, C, FDT> ControlBuilder<FD, C, Option<FDT>>
529where
530    FD: FormToolData,
531    C: ControlData<FD, ReturnType = String>,
532    FDT: FromStr + ToString,
533{
534    /// Sets the parse functions to use the [`FromStr`] [`ToString`] and traits
535    /// on on optional value for parsing and unparsing respectively.
536    /// If parsing fails, the `None` varient will be passed, otherwise, if
537    /// parsing succeeds, `Some(value)` will be passed.
538    ///
539    /// To trim the string before parsing, see
540    /// [`parse_optional_trimmed`](Self::parse_optional_trimmed)().
541    ///
542    /// The parse and unparse functions define how to turn what the user
543    /// types in the form into what is stored in the form data struct and
544    /// vice versa.
545    pub fn parse_optional(mut self) -> Self {
546        self.parse_fn = Some(Box::new(|control_return_value| {
547            Ok(control_return_value.parse::<FDT>().ok())
548        }));
549        self.unparse_fn = Some(Box::new(|field| {
550            field.map(|v| v.to_string()).unwrap_or_default()
551        }));
552        self
553    }
554
555    /// Sets the parse functions to use the [`FromStr`] [`ToString`] and traits
556    /// on on optional value for parsing and unparsing respectively, similar
557    /// to [`parse_optional`](Self::parse_optional)().
558    /// However, this method trims the string before parsing.
559    ///
560    /// The parse and unparse functions define how to turn what the user
561    /// types in the form into what is stored in the form data struct and
562    /// vice versa.
563    pub fn parse_optional_trimmed(mut self) -> Self {
564        self.parse_fn = Some(Box::new(|control_return_value| {
565            Ok(control_return_value.trim().parse::<FDT>().ok())
566        }));
567        self.unparse_fn = Some(Box::new(|field| {
568            field.map(|v| v.to_string()).unwrap_or_default()
569        }));
570        self
571    }
572}
573
574impl<FD, C, FDT> ControlBuilder<FD, C, FDT>
575where
576    FD: FormToolData,
577    C: ControlData<FD, ReturnType = String>,
578    FDT: FromStr + ToString + Default,
579{
580    /// Sets the parse functions to use the [`FromStr`] [`ToString`] and traits
581    /// for parsing and unparsing respectively.
582    /// If parsing fails, the default value will be used.
583    ///
584    /// To trim the string before parsing, see
585    /// [`parse_trimmed_or_default`](Self::parse_trimmed_or_default)().
586    ///
587    /// The parse and unparse functions define how to turn what the user
588    /// types in the form into what is stored in the form data struct and
589    /// vice versa.
590    pub fn parse_or_default(mut self) -> Self {
591        self.parse_fn = Some(Box::new(|control_return_value| {
592            Ok(control_return_value.parse::<FDT>().unwrap_or_default())
593        }));
594        self.unparse_fn = Some(Box::new(|field| field.to_string()));
595        self
596    }
597
598    /// Sets the parse functions to use the [`FromStr`] [`ToString`] and traits
599    /// on on optional value for parsing and unparsing respectively, similar
600    /// to [`parse_or_default`](Self::parse_or_default)().
601    /// However, this method trims the string before parsing.
602    ///
603    /// The parse and unparse functions define how to turn what the user
604    /// types in the form into what is stored in the form data struct and
605    /// vice versa.
606    pub fn parse_trimmed_or_default(mut self) -> Self {
607        self.parse_fn = Some(Box::new(|control_return_value| {
608            Ok(control_return_value
609                .trim()
610                .parse::<FDT>()
611                .unwrap_or_default())
612        }));
613        self.unparse_fn = Some(Box::new(|field| field.to_string()));
614        self
615    }
616}
617
618impl<FD: FormToolData, C: ValidatedControlData<FD>, FDT> ControlBuilder<FD, C, FDT> {
619    /// Sets the validation function for this control.
620    ///
621    /// This allows you to check if the parsed value is a valid value.
622    ///
623    /// You are given the entire [`FormToolData`] struct, but you should only
624    /// validate the field you are creating. You can use the other fields in
625    /// the struct as context.
626    ///
627    /// Ex. You have a month and a day field in a form. You use the month
628    /// field to help ensure that the day is a valid day of that month.
629    pub fn validation_fn(
630        mut self,
631        validation_fn: impl Fn(&FD) -> Result<(), String> + Send + Sync + 'static,
632    ) -> Self {
633        self.validation_fn = Some(Arc::new(validation_fn));
634        self
635    }
636}