formidable 0.1.0

Easily derive forms from structs for Leptos.
Documentation
#![allow(unused_imports)]

mod accept;
#[cfg(feature = "bigdecimal")]
mod bigdecimal;
#[cfg(feature = "color")]
mod color;
mod email;
#[cfg(feature = "file")]
mod file;
mod non_empty_string;
mod optional;
mod std_types;
mod tel;
#[cfg(feature = "time")]
mod time;
#[cfg(feature = "url")]
mod url;

pub use accept::*;
#[cfg(feature = "bigdecimal")]
pub use bigdecimal::*;
#[cfg(feature = "color")]
pub use color::*;
pub use email::*;
#[cfg(feature = "file")]
pub use file::*;
pub use non_empty_string::*;
pub use optional::*;
pub use tel::*;
#[cfg(feature = "time")]
pub use time::*;
#[cfg(feature = "url")]
pub use url::*;

use crate::{
    components::{Input, InputType},
    FieldError, Form, FormError, Name,
};
use leptos::prelude::*;
use std::fmt::Display;
use std::str::FromStr;

impl<T> Form for T
where
    T: FormType,
    <T as FromStr>::Err: Clone + Display + Send + Sync + 'static,
{
    fn view(
        field: crate::FieldConfiguration,
        name: Name,
        value: Option<Self>,
        callback: Option<Callback<Result<Self, FormError>>>,
    ) -> impl IntoView {
        view! {
            <Input<T>
                label=field.label.expect("No label provided")
                description=field.description
                name=name
                value=value
                callback={callback.map(|callback| Callback::new(move |v: Result<Self, FieldError>| {
                    callback.run(v.map_err(FormError::from));
                }))}
                input_type=T::INPUT_TYPE
                placeholder=T::PLACEHOLDER
                required=T::REQUIRED
                minlength=T::MIN_LENGTH
                maxlength=T::MAX_LENGTH
                min=T::MIN
                max=T::MAX
                step=T::STEP
            />
        }
    }
}

pub trait FormType: Clone + Display + FromStr + Send + Sync + 'static {
    const INPUT_TYPE: InputType;
    const PLACEHOLDER: Option<Self> = None;
    const REQUIRED: Option<bool> = None;
    const MIN_LENGTH: Option<usize> = None;
    const MAX_LENGTH: Option<usize> = None;
    const MIN: Option<Self> = None;
    const MAX: Option<Self> = None;
    const STEP: Option<Self> = None;
}