diff --git a/grid_form.scss b/grid_form.scss index bea0787..04e99f9 100644 --- a/grid_form.scss +++ b/grid_form.scss @@ -90,24 +90,24 @@ // column widths -.w-full { +.col-span-full { grid-column: 1 / -1; } -.w-12 { +.col-span-12 { grid-column: span 12 / span 12; } -.w-6 { +.col-span-6 { grid-column: span 6 / span 6; } -.w-4 { +.col-span-4 { grid-column: span 4 / span 4; } -.w-3 { +.col-span-3 { grid-column: span 3 / span 3; } -.w-2 { +.col-span-2 { grid-column: span 2 / span 2; } -.w-1 { +.col-span-1 { grid-column: span 1 / span 1; } diff --git a/src/controls/text_input.rs b/src/controls/text_input.rs index b8a87ae..4c76632 100644 --- a/src/controls/text_input.rs +++ b/src/controls/text_input.rs @@ -53,6 +53,11 @@ impl FormBuilder { } impl ControlBuilder { + pub fn named(mut self, control_name: impl ToString) -> Self { + self.data.name = control_name.to_string(); + self + } + pub fn placeholder(mut self, placeholder: impl ToString) -> Self { self.data.placeholder = Some(placeholder.to_string()); self diff --git a/src/form.rs b/src/form.rs index 64308e1..82183db 100644 --- a/src/form.rs +++ b/src/form.rs @@ -7,10 +7,8 @@ use crate::{ }, styles::FormStyle, }; -use leptos::{ - create_rw_signal, create_signal, IntoSignal, IntoView, RwSignal, SignalGet, SignalSet, - SignalUpdate, View, -}; +use leptos::*; +use leptos_router::Form; pub struct Validator { validations: Vec>>, @@ -102,20 +100,8 @@ pub struct FormBuilder { } impl FormBuilder { - // TODO: remove the Default trait bound and bind it to this function only - fn new_full_builder(form_style: FS) -> FormBuilder { - let fd = create_rw_signal(FD::default()); - FormBuilder { - inner: FormBuilderInner::FullBuilder(FullFormBuilder { - fd, - fs: form_style, - validations: Vec::new(), - views: Vec::new(), - }), - } - } - - fn new_full_builder_with(starting_data: FD, form_style: FS) -> FormBuilder { + // TODO: remove the Default trait bound + fn new_full_builder(starting_data: FD, form_style: FS) -> FormBuilder { let fd = create_rw_signal(starting_data); FormBuilder { inner: FormBuilderInner::FullBuilder(FullFormBuilder { @@ -267,12 +253,38 @@ impl FormBuilder { ) } - fn build(self) -> Option> { + fn build( + self, + action_location: String, + action: Option>>, + ) -> Option> { let builder = match self.inner { FormBuilderInner::FullBuilder(fb) => fb, FormBuilderInner::ValidationBuilder { validations: _ } => return None, }; - let view = builder.fs.form_frame(builder.views.into_view()); + let validations = builder.validations.clone(); + let validate_form = move || { + let fd = builder.fd.get(); + validations.iter().all(|v| v(&fd).is_ok()) + }; + + let elements = builder.fs.form_frame(builder.views.into_view()); + + let view = view! { +
+ {elements} +
+ } + .into_view(); Some(Form { fd: builder.fd, @@ -281,10 +293,10 @@ impl FormBuilder { }) } - fn validator(self) -> Validator { - let validations = match self.inner { - FormBuilderInner::FullBuilder(fb) => fb.validations, - FormBuilderInner::ValidationBuilder { validations } => validations, + fn validator(&self) -> Validator { + let validations = match &self.inner { + FormBuilderInner::FullBuilder(fb) => fb.validations.clone(), + FormBuilderInner::ValidationBuilder { validations } => validations.clone(), }; Validator { validations } } @@ -309,16 +321,24 @@ pub trait FormData: Default + Clone + 'static { /// Constructs a [`Form`] for this FormData type. /// /// The [`Form`] provides the way to render the form. - fn get_form(style: Self::Style) -> Form { - let builder = FormBuilder::new_full_builder(style); + fn get_form(self, action: impl ToString, style: Self::Style) -> Form { + let builder = FormBuilder::new_full_builder(self, style); let builder = Self::build_form(builder); - builder.build().expect("builder should be full builder") + builder + .build(action.to_string(), None) + .expect("builder should be full builder") } - fn get_form_with_starting_data(self, style: Self::Style) -> Form { - let builder = FormBuilder::new_full_builder_with(self, style); + fn get_action_form( + self, + action: Action>, + style: Self::Style, + ) -> Form { + let builder = FormBuilder::new_full_builder(self, style); let builder = Self::build_form(builder); - builder.build().expect("builder should be full builder") + builder + .build(action.url().unwrap_or(String::new()), Some(action)) + .expect("builder should be full builder") } fn get_validator() -> Validator { diff --git a/src/styles/grid_form.rs b/src/styles/grid_form.rs index 59cef18..f097fd2 100644 --- a/src/styles/grid_form.rs +++ b/src/styles/grid_form.rs @@ -4,7 +4,6 @@ use crate::controls::{ text_input::TextInputData, ControlData, ControlRenderData, }; use leptos::*; -use leptos_router::Form; pub enum GridFormStylingAttributes { Width(u32), @@ -16,12 +15,11 @@ pub struct GridFormStyle; impl FormStyle for GridFormStyle { type StylingAttributes = GridFormStylingAttributes; - // TODO: something about an on-submit thing fn form_frame(&self, children: View) -> View { view! { -
+
{children} - +
} .into_view() } @@ -118,7 +116,7 @@ impl FormStyle for GridFormStyle { } .into_view() diff --git a/src/styles/mod.rs b/src/styles/mod.rs index 8fbeadb..2cc5937 100644 --- a/src/styles/mod.rs +++ b/src/styles/mod.rs @@ -10,6 +10,13 @@ use leptos::{Signal, View}; pub trait FormStyle: Default + 'static { type StylingAttributes; + /// Render any containing components for the form. + /// + /// This allows you to wrap all the form components + /// in another component if neccisary. + /// + /// Do NOT wrap it in an actual `form` element; any + /// wrapping should be done with `div` or similar elements. fn form_frame(&self, children: View) -> View; fn heading(&self, control: ControlRenderData) -> View; fn text_input(