use std::marker::PhantomData;
use crate::{field::FieldHandlers, traits::*, validators::*};
use dioxus::{core::SpawnIfAsync, prelude::*};
type AppForm = fn(AppFormInput) -> AppFormOutput;
struct AppFormInput {}
struct AppFormOutput {}
#[derive(PartialEq, Clone, Debug, Store)]
pub struct FormState {
pub(crate) can_submit: bool,
pub(crate) is_submiting: bool,
pub(crate) is_validating: bool,
}
impl Default for FormState {
fn default() -> Self {
Self {
can_submit: true,
is_submiting: false,
is_validating: false,
}
}
}
#[inline(always)]
pub fn use_init_form_state() -> Store<FormState> {
use_store(Default::default)
}
pub fn use_form_provider<TForm>()
where
TForm: InitForm + GetFieldRegistry + FormSubmitInput + GetFormState + CalculateCanSubmit,
{
let mut form = TForm::use_form();
let mut form_state = form.get_form_state();
use_context_provider(|| form);
}
#[component]
pub fn Form<TForm>(
#[props(extends=GlobalAttributes)]
#[props(extends=form)]
attributes: Vec<Attribute>,
children: Element,
on_submit: EventHandler<TForm::SubmitInput>,
#[props(optional, default=PhantomData)] _phantom_form: PhantomData<TForm>,
) -> Element
where
TForm: GetFormState + FormSubmitInput + Clone + ValidateOnSubmit + CalculateCanSubmit + 'static,
{
let mut form = use_context::<TForm>();
let mut form_state = form.get_form_state();
rsx! {
form {
onsubmit: move |ev| {
ev.prevent_default();
let mut form = form.clone();
async move {
form.validate_on_submit().await;
let can_submit = form.calculate_can_submit();
if can_submit && let Some(output) = form.build_submit_input() {
tracing::info!("submitting now...");
form_state.can_submit().set(false);
form_state.is_submiting().set(true);
on_submit.call(output);
form_state.can_submit().set(true);
form_state.is_submiting().set(false);
}
}
},
..attributes,
{children}
}
}
}
pub fn use_form<TForm>() -> TForm
where
TForm: GetFieldRegistry + GetFormState,
{
try_use_context::<TForm>().expect("You may have forgotten to use `use_form_provider` with the required form struct in the parent component.")
}