diff --git a/src/controls/button.rs b/src/controls/button.rs index a8cbf7d..ee03f53 100644 --- a/src/controls/button.rs +++ b/src/controls/button.rs @@ -1,12 +1,11 @@ -use super::ControlRenderData; +use super::{BuilderFn, ControlRenderData}; use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle}; use leptos::RwSignal; use std::rc::Rc; use web_sys::MouseEvent; -type ButtonAction = dyn Fn(MouseEvent, &mut FD); +type ButtonAction = dyn Fn(MouseEvent, RwSignal) + 'static; -#[derive(Clone)] pub struct ButtonData { pub(crate) text: String, pub(crate) action: Option>>, @@ -19,21 +18,26 @@ impl Default for ButtonData { } } } +impl Clone for ButtonData { + fn clone(&self) -> Self { + ButtonData { + text: self.text.clone(), + action: self.action.clone(), + } + } +} -impl FormBuilder { - pub fn button( - mut self, - builder: impl Fn(ButtonBuilder) -> ButtonBuilder, - ) -> Self { +impl FormBuilder { + pub fn button(mut self, builder: impl BuilderFn, FD::Context>) -> Self { let button_builder = ButtonBuilder::new(); - let control = builder(button_builder); + let control = builder(button_builder, &self.cx); let render_data = ControlRenderData { data: control.data, styles: control.styles, }; - let render_fn = move |fs: &FS, fd: RwSignal| { + let render_fn = move |fs: &FD::Style, fd: RwSignal| { let view = fs.button(render_data, fd); (view, None) }; @@ -43,13 +47,12 @@ impl FormBuilder { } } -#[derive(Clone)] -pub struct ButtonBuilder { - pub(crate) styles: Vec, +pub struct ButtonBuilder { + pub(crate) styles: Vec<::StylingAttributes>, pub(crate) data: ButtonData, } -impl ButtonBuilder { +impl ButtonBuilder { fn new() -> Self { ButtonBuilder { styles: Vec::default(), @@ -57,7 +60,7 @@ impl ButtonBuilder { } } - pub fn style(mut self, style: FS::StylingAttributes) -> Self { + pub fn style(mut self, style: ::StylingAttributes) -> Self { self.styles.push(style); self } @@ -67,7 +70,7 @@ impl ButtonBuilder { self } - pub fn action(mut self, action: impl Fn(MouseEvent, &mut FD) + 'static) -> Self { + pub fn action(mut self, action: impl Fn(MouseEvent, RwSignal) + 'static) -> Self { self.data.action = Some(Rc::new(action)); self } diff --git a/src/controls/checkbox.rs b/src/controls/checkbox.rs index 3a7e3fc..f74f714 100644 --- a/src/controls/checkbox.rs +++ b/src/controls/checkbox.rs @@ -22,16 +22,16 @@ impl ControlData for CheckboxData { } } -impl FormBuilder { +impl FormBuilder { pub fn checkbox( self, - builder: impl BuilderFn, CX>, + builder: impl BuilderFn, FD::Context>, ) -> Self { self.new_control(builder) } } -impl ControlBuilder { +impl ControlBuilder { pub fn named(mut self, control_name: impl ToString) -> Self { self.data.name = control_name.to_string(); self diff --git a/src/controls/custom.rs b/src/controls/custom.rs index f84e2d0..6555cba 100644 --- a/src/controls/custom.rs +++ b/src/controls/custom.rs @@ -1,11 +1,11 @@ use super::{BuilderFn, ControlBuilder, ControlData}; -use crate::{styles::FormStyle, FormBuilder, FormToolData}; +use crate::{FormBuilder, FormToolData}; -impl FormBuilder { +impl FormBuilder { pub fn custom( mut self, control_data: CC, - builder: impl Fn(ControlBuilder) -> ControlBuilder, + builder: impl Fn(ControlBuilder) -> ControlBuilder, ) -> Self { let control_builder = ControlBuilder::new(control_data); let control = builder(control_builder); @@ -15,7 +15,7 @@ impl FormBuilder { pub fn custom_default( self, - builder: impl BuilderFn, CX>, + builder: impl BuilderFn, FD::Context>, ) -> Self { self.new_control(builder) } diff --git a/src/controls/group.rs b/src/controls/group.rs index 8edfbd6..cced99c 100644 --- a/src/controls/group.rs +++ b/src/controls/group.rs @@ -1,13 +1,11 @@ use super::ValidationCb; -use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle}; +use crate::styles::FormStyle; +use crate::{form::FormToolData, form_builder::FormBuilder}; use leptos::{CollectView, RwSignal}; -impl FormBuilder { - pub fn group( - mut self, - builder: impl Fn(FormBuilder) -> FormBuilder, - ) -> Self { - let mut group_builder = FormBuilder::new(self.cx); +impl FormBuilder { + pub fn group(mut self, builder: impl Fn(FormBuilder) -> FormBuilder) -> Self { + let mut group_builder = FormBuilder::new_group(self.cx); group_builder = builder(group_builder); // Take context back @@ -17,7 +15,7 @@ impl FormBuilder { self.validations.push(validation); } - let render_fn = move |fs: &FS, fd: RwSignal| { + let render_fn = move |fs: &FD::Style, fd: RwSignal| { let (views, validation_cbs): (Vec<_>, Vec<_>) = group_builder .render_fns .into_iter() diff --git a/src/controls/heading.rs b/src/controls/heading.rs index 9d765e0..4e22d4b 100644 --- a/src/controls/heading.rs +++ b/src/controls/heading.rs @@ -17,16 +17,16 @@ impl VanityControlData for HeadingData { } } -impl FormBuilder { +impl FormBuilder { pub fn heading( self, - builder: impl BuilderFn, CX>, + builder: impl BuilderFn, FD::Context>, ) -> Self { self.new_vanity(builder) } } -impl VanityControlBuilder { +impl VanityControlBuilder { pub fn title(mut self, title: impl ToString) -> Self { self.data.title = title.to_string(); self diff --git a/src/controls/hidden.rs b/src/controls/hidden.rs index a9074e8..11ffcf9 100644 --- a/src/controls/hidden.rs +++ b/src/controls/hidden.rs @@ -19,10 +19,10 @@ impl ControlData for HiddenData { } } -impl FormBuilder { +impl FormBuilder { pub fn hidden( self, - builder: impl BuilderFn, CX>, + builder: impl BuilderFn, FD::Context>, ) -> Self { self.new_control(builder) } diff --git a/src/controls/mod.rs b/src/controls/mod.rs index e1cb9a6..59ecd9c 100644 --- a/src/controls/mod.rs +++ b/src/controls/mod.rs @@ -77,18 +77,18 @@ pub struct ControlRenderData { } /// The data needed to render a read-only control of type `C`. -pub struct VanityControlBuilder { - pub(crate) style_attributes: Vec, +pub struct VanityControlBuilder { + pub(crate) style_attributes: Vec<::StylingAttributes>, pub(crate) data: C, pub(crate) getter: Option>>, } -pub(crate) struct BuiltVanityControlData { - pub(crate) render_data: ControlRenderData, +pub(crate) struct BuiltVanityControlData { + pub(crate) render_data: ControlRenderData, pub(crate) getter: Option>>, } -impl VanityControlBuilder { +impl VanityControlBuilder { /// Creates a new [`VanityControlBuilder`] with the given [`VanityControlData`]. pub(crate) fn new(data: C) -> Self { VanityControlBuilder { @@ -99,7 +99,7 @@ impl VanityControlBuilder } /// Builds the builder into the data needed to render the control. - pub(crate) fn build(self) -> BuiltVanityControlData { + pub(crate) fn build(self) -> BuiltVanityControlData { BuiltVanityControlData { render_data: ControlRenderData { data: self.data, @@ -110,13 +110,13 @@ impl VanityControlBuilder } /// Adds a styling attribute to this control. - pub fn style(mut self, attribute: FS::StylingAttributes) -> Self { + pub fn style(mut self, attribute: ::StylingAttributes) -> Self { self.style_attributes.push(attribute); self } } -impl VanityControlBuilder { +impl VanityControlBuilder { /// Sets the getter function. /// /// This function can get a string from the form data to be displayed @@ -153,8 +153,8 @@ impl Display for ControlBuildError { } /// The data returned fomr a control's build function. -pub(crate) struct BuiltControlData { - pub(crate) render_data: ControlRenderData, +pub(crate) struct BuiltControlData { + pub(crate) render_data: ControlRenderData, pub(crate) getter: Rc>, pub(crate) setter: Rc>, pub(crate) parse_fn: Box>, @@ -163,17 +163,17 @@ pub(crate) struct BuiltControlData { +pub struct ControlBuilder { pub(crate) getter: Option>>, pub(crate) setter: Option>>, pub(crate) parse_fn: Option>>, pub(crate) unparse_fn: Option>>, pub(crate) validation_fn: Option>>, - pub(crate) style_attributes: Vec, + pub(crate) style_attributes: Vec<::StylingAttributes>, pub data: C, } -impl ControlBuilder { +impl ControlBuilder { /// Creates a new [`ControlBuilder`] with the given [`ControlData`]. pub(crate) fn new(data: C) -> Self { ControlBuilder { @@ -190,7 +190,7 @@ impl ControlBuilder Result, ControlBuildError> { + pub(crate) fn build(self) -> Result, ControlBuildError> { let getter = match self.getter { Some(getter) => getter, None => return Err(ControlBuildError::MissingGetter), @@ -259,16 +259,15 @@ impl ControlBuilder Self { + pub fn style(mut self, attribute: ::StylingAttributes) -> Self { self.style_attributes.push(attribute); self } } -impl ControlBuilder +impl ControlBuilder where FD: FormToolData, - FS: FormStyle, C: ControlData, FDT: TryFrom<::ReturnType>, ::ReturnType>>::Error: ToString, @@ -291,10 +290,9 @@ where } } -impl ControlBuilder +impl ControlBuilder where FD: FormToolData, - FS: FormStyle, C: ControlData, FDT: FromStr + ToString, ::Err: ToString, @@ -335,7 +333,7 @@ where } } -impl ControlBuilder { +impl ControlBuilder { /// Sets the validation function for this control /// /// This allows you to check if the parsed value is a valid value. diff --git a/src/controls/output.rs b/src/controls/output.rs index 797574b..2e734c9 100644 --- a/src/controls/output.rs +++ b/src/controls/output.rs @@ -18,10 +18,10 @@ impl VanityControlData for OutputData { } impl GetterVanityControlData for OutputData {} -impl FormBuilder { +impl FormBuilder { pub fn output( self, - builder: impl BuilderFn, CX>, + builder: impl BuilderFn, FD::Context>, ) -> Self { self.new_vanity(builder) } diff --git a/src/controls/radio_buttons.rs b/src/controls/radio_buttons.rs index 2cd2a1c..2212a27 100644 --- a/src/controls/radio_buttons.rs +++ b/src/controls/radio_buttons.rs @@ -24,16 +24,16 @@ impl ControlData for RadioButtonsData { } impl ValidatedControlData for RadioButtonsData {} -impl FormBuilder { +impl FormBuilder { pub fn radio_buttons( self, - builder: impl BuilderFn, CX>, + builder: impl BuilderFn, FD::Context>, ) -> Self { self.new_control(builder) } } -impl ControlBuilder { +impl ControlBuilder { pub fn named(mut self, control_name: impl ToString) -> Self { self.data.name = control_name.to_string(); self diff --git a/src/controls/select.rs b/src/controls/select.rs index 46b404a..cb84ce5 100644 --- a/src/controls/select.rs +++ b/src/controls/select.rs @@ -27,16 +27,16 @@ impl ControlData for SelectData { } impl ValidatedControlData for SelectData {} -impl FormBuilder { +impl FormBuilder { pub fn select( self, - builder: impl BuilderFn, CX>, + builder: impl BuilderFn, FD::Context>, ) -> Self { self.new_control(builder) } } -impl ControlBuilder { +impl ControlBuilder { pub fn named(mut self, control_name: impl ToString) -> Self { self.data.name = control_name.to_string(); self diff --git a/src/controls/slider.rs b/src/controls/slider.rs index b73fbe7..9f9cb50 100644 --- a/src/controls/slider.rs +++ b/src/controls/slider.rs @@ -36,16 +36,16 @@ impl ControlData for SliderData { } } -impl FormBuilder { +impl FormBuilder { pub fn slider( self, - builder: impl BuilderFn, CX>, + builder: impl BuilderFn, FD::Context>, ) -> Self { self.new_control(builder) } } -impl ControlBuilder { +impl ControlBuilder { pub fn named(mut self, control_name: impl ToString) -> Self { self.data.name = control_name.to_string(); self diff --git a/src/controls/spacer.rs b/src/controls/spacer.rs index 979fd7d..6d19b23 100644 --- a/src/controls/spacer.rs +++ b/src/controls/spacer.rs @@ -17,16 +17,16 @@ impl VanityControlData for SpacerData { } } -impl FormBuilder { +impl FormBuilder { pub fn spacer( self, - builder: impl BuilderFn, CX>, + builder: impl BuilderFn, FD::Context>, ) -> Self { self.new_vanity(builder) } } -impl VanityControlBuilder { +impl VanityControlBuilder { pub fn height(mut self, height: impl ToString) -> Self { self.data.height = Some(height.to_string()); self diff --git a/src/controls/stepper.rs b/src/controls/stepper.rs index 9904f25..f52c662 100644 --- a/src/controls/stepper.rs +++ b/src/controls/stepper.rs @@ -27,16 +27,16 @@ impl ControlData for StepperData { } impl ValidatedControlData for StepperData {} -impl FormBuilder { +impl FormBuilder { pub fn stepper( self, - builder: impl BuilderFn, CX>, + builder: impl BuilderFn, FD::Context>, ) -> Self { self.new_control(builder) } } -impl ControlBuilder { +impl ControlBuilder { pub fn named(mut self, control_name: impl ToString) -> Self { self.data.name = control_name.to_string(); self diff --git a/src/controls/submit.rs b/src/controls/submit.rs index 5a8c8e5..28a8c9b 100644 --- a/src/controls/submit.rs +++ b/src/controls/submit.rs @@ -17,16 +17,16 @@ impl VanityControlData for SubmitData { } } -impl FormBuilder { +impl FormBuilder { pub fn submit( self, - builder: impl BuilderFn, CX>, + builder: impl BuilderFn, FD::Context>, ) -> Self { self.new_vanity(builder) } } -impl VanityControlBuilder { +impl VanityControlBuilder { pub fn text(mut self, text: impl ToString) -> Self { self.data.text = text.to_string(); self diff --git a/src/controls/text_area.rs b/src/controls/text_area.rs index 94a93e6..d16c06f 100644 --- a/src/controls/text_area.rs +++ b/src/controls/text_area.rs @@ -23,16 +23,16 @@ impl ControlData for TextAreaData { } impl ValidatedControlData for TextAreaData {} -impl FormBuilder { +impl FormBuilder { pub fn text_area( self, - builder: impl BuilderFn, CX>, + builder: impl BuilderFn, FD::Context>, ) -> Self { self.new_control(builder) } } -impl ControlBuilder { +impl ControlBuilder { pub fn placeholder(mut self, placeholder: impl ToString) -> Self { self.data.placeholder = Some(placeholder.to_string()); self diff --git a/src/controls/text_input.rs b/src/controls/text_input.rs index dfe34cc..7bfc063 100644 --- a/src/controls/text_input.rs +++ b/src/controls/text_input.rs @@ -38,16 +38,16 @@ impl ControlData for TextInputData { } impl ValidatedControlData for TextInputData {} -impl FormBuilder { +impl FormBuilder { pub fn text_input( self, - builder: impl BuilderFn, CX>, + builder: impl BuilderFn, FD::Context>, ) -> Self { self.new_control(builder) } } -impl ControlBuilder { +impl ControlBuilder { pub fn named(mut self, control_name: impl ToString) -> Self { self.data.name = control_name.to_string(); self diff --git a/src/form.rs b/src/form.rs index ec49e59..b8055a7 100644 --- a/src/form.rs +++ b/src/form.rs @@ -90,9 +90,7 @@ pub trait FormToolData: Clone + 'static { /// Uses the given form builder to specify what fields should be present /// in the form, what properties those fields should have, and how that /// data should be parsed and checked. - fn build_form( - fb: FormBuilder, - ) -> FormBuilder; + fn build_form(fb: FormBuilder) -> FormBuilder; /// Constructs a [`Form`] for this [`FormToolData`] type. /// diff --git a/src/form_builder.rs b/src/form_builder.rs index b9340b5..5d5a964 100644 --- a/src/form_builder.rs +++ b/src/form_builder.rs @@ -16,6 +16,9 @@ use serde::de::DeserializeOwned; use std::rc::Rc; use web_sys::{FormData, SubmitEvent}; +// TODO: FS, and CX may be uncessisary, as FS is the same as FD::Style +// and CX is the same as FD::Context. + /// A builder for laying out forms. /// /// This builder allows you to specify what components should make up the form. @@ -24,19 +27,30 @@ use web_sys::{FormData, SubmitEvent}; /// - `FD`: FormToolData - Your form data /// - `FS`: FormStyle - The form style you are using /// - `CX`: Context - A user defined context that you are rendering the form in -pub struct FormBuilder { - pub(crate) cx: CX, +pub struct FormBuilder { + pub(crate) cx: Rc, /// The list of [`ValidationFn`]s. pub(crate) validations: Vec>>, /// The list of functions that will render the form. - pub(crate) render_fns: Vec>>, + pub(crate) render_fns: Vec>>, /// The list of styling attributes applied on the form level - pub(crate) styles: Vec, + pub(crate) styles: Vec<::StylingAttributes>, } -impl FormBuilder { +impl FormBuilder { /// Creates a new [`FormBuilder`] - pub(crate) fn new(cx: CX) -> Self { + pub(crate) fn new(cx: FD::Context) -> Self { + FormBuilder { + cx: Rc::new(cx), + validations: Vec::new(), + render_fns: Vec::new(), + styles: Vec::new(), + } + } + + /// Creates a new [`FormBuilder`] with the given Rc'ed context, for + //// building a form group. + pub(crate) fn new_group(cx: Rc) -> Self { FormBuilder { cx, validations: Vec::new(), @@ -45,14 +59,14 @@ impl FormBuilder { } } - pub fn style(mut self, style: FS::StylingAttributes) -> Self { + pub fn style(mut self, style: ::StylingAttributes) -> Self { self.styles.push(style); self } pub(crate) fn new_vanity( mut self, - builder: impl BuilderFn, CX>, + builder: impl BuilderFn, FD::Context>, ) -> Self { let vanity_builder = VanityControlBuilder::new(C::default()); let control = builder(vanity_builder, &self.cx); @@ -62,7 +76,7 @@ impl FormBuilder { pub(crate) fn new_control( mut self, - builder: impl BuilderFn, CX>, + builder: impl BuilderFn, FD::Context>, ) -> Self { let control_builder = ControlBuilder::new(C::default()); let control = builder(control_builder, &self.cx); @@ -73,14 +87,14 @@ impl FormBuilder { // TODO: test this from a user context. A user adding a custom defined component. pub fn add_vanity( &mut self, - vanity_control: VanityControlBuilder, + vanity_control: VanityControlBuilder, ) { let BuiltVanityControlData { render_data, getter, } = vanity_control.build(); - let render_fn = move |fs: &FS, fd: RwSignal| { + let render_fn = move |fs: &FD::Style, fd: RwSignal| { let value_getter = getter.map(|getter| (move || getter(fd.get())).into_signal()); let view = VanityControlData::build_control(fs, render_data, value_getter); (view, None) @@ -92,7 +106,7 @@ impl FormBuilder { // TODO: test this from a user context. A user adding a custom defined component. pub fn add_control( &mut self, - control: ControlBuilder, + control: ControlBuilder, ) { let built_control_data = match control.build() { Ok(c) => c, @@ -103,7 +117,7 @@ impl FormBuilder { self.validations.push(validation_fn.clone()); } - let render_fn = move |fs: &FS, fd: RwSignal| { + let render_fn = move |fs: &FD::Style, fd: RwSignal| { let (view, cb) = Self::build_control_view(fd, fs, built_control_data); (view, Some(cb)) }; @@ -113,8 +127,8 @@ impl FormBuilder { fn build_control_view( fd: RwSignal, - fs: &FS, - control_data: BuiltControlData, + fs: &FD::Style, + control_data: BuiltControlData, ) -> (View, Box) { let BuiltControlData { render_data, @@ -211,7 +225,7 @@ impl FormBuilder { self, action: Action>>, fd: FD, - fs: FS, + fs: FD::Style, ) -> Form where ServFn: DeserializeOwned + ServerFn + 'static, @@ -256,7 +270,7 @@ impl FormBuilder { } } - pub(crate) fn build_plain_form(self, url: String, fd: FD, fs: FS) -> Form { + pub(crate) fn build_plain_form(self, url: String, fd: FD, fs: FD::Style) -> Form { let fd = create_rw_signal(fd); let (views, validation_cbs): (Vec<_>, Vec<_>) = self diff --git a/src/styles/grid_form.rs b/src/styles/grid_form.rs index 3a76b16..b505db6 100644 --- a/src/styles/grid_form.rs +++ b/src/styles/grid_form.rs @@ -365,7 +365,7 @@ impl FormStyle for GridFormStyle { let action = control.data.action.clone(); let on_click = move |ev: MouseEvent| { if let Some(action) = action.clone() { - data_signal.update(|fd| action(ev, fd)); + action(ev, data_signal) } };