From a39f2ce664916d76c5a3cb34dcffc6d565a00633 Mon Sep 17 00:00:00 2001 From: Mitchell M Date: Wed, 12 Jun 2024 15:49:30 -0500 Subject: [PATCH 1/5] selects can have different values and customized button builder --- src/controls/button.rs | 63 +++++++++++++++++++++++------------------ src/controls/mod.rs | 6 ++-- src/controls/select.rs | 32 +++++++++++++++++---- src/styles/grid_form.rs | 62 ++++++++++++++++++++-------------------- src/styles/mod.rs | 8 ++++-- 5 files changed, 104 insertions(+), 67 deletions(-) diff --git a/src/controls/button.rs b/src/controls/button.rs index 1b72b24..e79556b 100644 --- a/src/controls/button.rs +++ b/src/controls/button.rs @@ -1,48 +1,57 @@ -use super::{ControlRenderData, VanityControlBuilder, VanityControlData}; +use super::ControlRenderData; use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle}; -use leptos::{RwSignal, Signal, View}; +use leptos::RwSignal; use std::rc::Rc; use web_sys::MouseEvent; -#[derive(Clone)] +#[derive(Default, Clone)] pub struct ButtonData { pub(crate) text: String, pub(crate) action: Option>, - - // this will need to be set before calling the build method - pub(crate) fd_signal: RwSignal, -} - -impl VanityControlData for ButtonData { - fn build_control( - fs: &FS, - control: ControlRenderData, - _value_getter: Option>, - ) -> View { - fs.button(control) - } } impl FormBuilder { pub fn button( mut self, - builder: impl Fn( - VanityControlBuilder>, - ) -> VanityControlBuilder>, + builder: impl Fn(ButtonBuilder) -> ButtonBuilder, ) -> Self { - let data = ButtonData { - text: String::default(), - action: None, - fd_signal: self.fd, + let button_builder = ButtonBuilder::new(); + let control = builder(button_builder); + + let render_data = ControlRenderData { + data: Box::new(control.data), + styles: control.styles, }; - let vanity_builder = VanityControlBuilder::new(data); - let control = builder(vanity_builder); - self.add_vanity(control); + + let render_fn = move |fs: &FS, fd: RwSignal| { + let view = fs.button(render_data, fd); + (view, None) + }; + self.render_fns.push(Box::new(render_fn)); + self } } -impl VanityControlBuilder> { +#[derive(Clone)] +pub struct ButtonBuilder { + pub(crate) styles: Vec, + pub(crate) data: ButtonData, +} + +impl ButtonBuilder { + fn new() -> Self { + ButtonBuilder { + styles: Vec::default(), + data: ButtonData::default(), + } + } + + pub fn style(mut self, style: FS::StylingAttributes) -> Self { + self.styles.push(style); + self + } + pub fn text(mut self, text: impl ToString) -> Self { self.data.text = text.to_string(); self diff --git a/src/controls/mod.rs b/src/controls/mod.rs index 751cf82..e8b4509 100644 --- a/src/controls/mod.rs +++ b/src/controls/mod.rs @@ -71,7 +71,7 @@ pub trait ValidatedControlData: ControlData {} /// The data needed to render a interactive control of type `C`. pub struct ControlRenderData { pub data: Box, - pub style: Vec, + pub styles: Vec, } /// The data needed to render a read-only control of type `C`. @@ -101,7 +101,7 @@ impl VanityControlBuilder BuiltVanityControlData { render_data: ControlRenderData { data: Box::new(self.data), - style: self.style_attributes, + styles: self.style_attributes, }, getter: self.getter, } @@ -209,7 +209,7 @@ impl ControlBuilder, - pub(crate) options: Vec, + pub(crate) options: Vec<(String, String)>, } impl ControlData for SelectData { @@ -50,13 +49,36 @@ impl ControlBuilder Self { - self.data.options.push(option.to_string()); + self.data + .options + .push((option.to_string(), option.to_string())); + self + } + + pub fn with_option_valued(mut self, display: impl ToString, value: impl ToString) -> Self { + self.data + .options + .push((display.to_string(), value.to_string())); self } pub fn with_options(mut self, options: impl Iterator) -> Self { for option in options { - self.data.options.push(option.to_string()); + self.data + .options + .push((option.to_string(), option.to_string())); + } + self + } + + pub fn with_options_valued( + mut self, + options: impl Iterator, + ) -> Self { + for option in options { + self.data + .options + .push((option.0.to_string(), option.1.to_string())); } self } diff --git a/src/styles/grid_form.rs b/src/styles/grid_form.rs index dc6cf9e..81ca54f 100644 --- a/src/styles/grid_form.rs +++ b/src/styles/grid_form.rs @@ -1,8 +1,11 @@ use super::FormStyle; -use crate::controls::{ - checkbox::CheckboxData, heading::HeadingData, hidden::HiddenData, output::OutputData, - select::SelectData, spacer::SpacerData, submit::SubmitData, text_area::TextAreaData, - text_input::TextInputData, ControlData, ControlRenderData, +use crate::{ + controls::{ + button::ButtonData, checkbox::CheckboxData, heading::HeadingData, hidden::HiddenData, + output::OutputData, select::SelectData, spacer::SpacerData, submit::SubmitData, + text_area::TextAreaData, text_input::TextInputData, ControlData, ControlRenderData, + }, + FormToolData, }; use leptos::*; use std::rc::Rc; @@ -35,7 +38,7 @@ impl FormStyle for GridFormStyle { ) -> View { // TODO: extract this to a common thing let mut width = 1; - for style in control.style { + for style in control.styles { match style { GridFormStylingAttributes::Width(w) => width = w, } @@ -78,14 +81,10 @@ impl FormStyle for GridFormStyle { .data .options .into_iter() - .map(|value| { - let cloned_value = value.clone(); + .map(|(display, value)| { view! { - } }) @@ -112,9 +111,7 @@ impl FormStyle for GridFormStyle { } fn submit(&self, control: ControlRenderData) -> View { - view! { - - } + view! { } .into_view() } @@ -137,7 +134,8 @@ impl FormStyle for GridFormStyle { on:change=move |ev| { value_setter(event_target_value(&ev)); } - > + > + } @@ -168,7 +166,7 @@ impl FormStyle for GridFormStyle { validation_state: Signal>, ) -> View { let mut width = 1; - for style in control.style { + for style in control.styles { match style { GridFormStylingAttributes::Width(w) => width = w, } @@ -198,6 +196,7 @@ impl FormStyle for GridFormStyle { } } /> +
} @@ -230,7 +229,7 @@ impl FormStyle for GridFormStyle { value_setter: Box::ReturnType)>, ) -> View { let mut width = 1; - for style in control.style { + for style in control.styles { match style { GridFormStylingAttributes::Width(w) => width = w, } @@ -270,7 +269,7 @@ impl FormStyle for GridFormStyle { validation_state: Signal>, ) -> View { let mut width = 1; - for style in control.style { + for style in control.styles { match style { GridFormStylingAttributes::Width(w) => width = w, } @@ -317,7 +316,7 @@ impl FormStyle for GridFormStyle { validation_state: Signal>, ) -> View { let mut width = 1; - for style in control.style { + for style in control.styles { match style { GridFormStylingAttributes::Width(w) => width = w, } @@ -352,27 +351,32 @@ impl FormStyle for GridFormStyle { .into_view() } - fn button( + fn button( &self, - control: ControlRenderData>, + control: ControlRenderData>, + data_signal: RwSignal, ) -> View { let mut width = 1; - for style in control.style { + for style in control.styles { match style { GridFormStylingAttributes::Width(w) => width = w, } } let action = control.data.action.clone(); - let signal = control.data.fd_signal.clone(); let on_click = move |ev: MouseEvent| { if let Some(action) = action.clone() { - signal.update(|fd| action(ev, fd)); + data_signal.update(|fd| action(ev, fd)); } }; view! { - } @@ -398,15 +402,13 @@ impl FormStyle for GridFormStyle { fn spacer(&self, control: ControlRenderData) -> View { let mut width = 12; - for style in control.style { + for style in control.styles { match style { GridFormStylingAttributes::Width(w) => width = w, } } - view! { -
- } + view! {
} .into_view() } } diff --git a/src/styles/mod.rs b/src/styles/mod.rs index 36383f6..68fb6cd 100644 --- a/src/styles/mod.rs +++ b/src/styles/mod.rs @@ -9,7 +9,7 @@ use crate::{ }, FormToolData, }; -use leptos::{Signal, View}; +use leptos::{RwSignal, Signal, View}; pub use grid_form::{GridFormStyle, GridFormStylingAttributes}; @@ -58,7 +58,11 @@ pub trait FormStyle: Default + 'static { value_setter: Box::ReturnType)>, validation_state: Signal>, ) -> View; - fn button(&self, control: ControlRenderData>) -> View; + fn button( + &self, + control: ControlRenderData>, + data_signal: RwSignal, + ) -> View; fn checkbox( &self, control: ControlRenderData, From 115ff1abde33ab24a95b6d95b498aa00adf829d9 Mon Sep 17 00:00:00 2001 From: Mitchell M Date: Wed, 12 Jun 2024 16:02:43 -0500 Subject: [PATCH 2/5] remove fd and fs from builder --- src/controls/button.rs | 10 +++++++++- src/controls/group.rs | 3 +-- src/form.rs | 12 ++++++------ src/form_builder.rs | 39 ++++++++++++++------------------------- src/styles/mod.rs | 2 +- 5 files changed, 31 insertions(+), 35 deletions(-) diff --git a/src/controls/button.rs b/src/controls/button.rs index e79556b..d47e803 100644 --- a/src/controls/button.rs +++ b/src/controls/button.rs @@ -4,11 +4,19 @@ use leptos::RwSignal; use std::rc::Rc; use web_sys::MouseEvent; -#[derive(Default, Clone)] +#[derive(Clone)] pub struct ButtonData { pub(crate) text: String, pub(crate) action: Option>, } +impl Default for ButtonData { + fn default() -> Self { + ButtonData { + text: String::default(), + action: None, + } + } +} impl FormBuilder { pub fn button( diff --git a/src/controls/group.rs b/src/controls/group.rs index 1832f41..1379205 100644 --- a/src/controls/group.rs +++ b/src/controls/group.rs @@ -4,9 +4,8 @@ use leptos::{CollectView, RwSignal}; impl FormBuilder { pub fn group(mut self, builder: impl Fn(FormBuilder) -> FormBuilder) -> Self { - let mut group_builder = FormBuilder::new_group(self.fd, self.fs); + let mut group_builder = FormBuilder::new(); group_builder = builder(group_builder); - self.fs = group_builder.fs; // take the style back for validation in group_builder.validations { self.validations.push(validation); diff --git a/src/form.rs b/src/form.rs index c5ed3d8..3d62d03 100644 --- a/src/form.rs +++ b/src/form.rs @@ -78,7 +78,7 @@ impl IntoView for Form { /// /// This trait defines a function that can be used to build all the data needed /// to physically lay out a form, and how that data should be parsed and validated. -pub trait FormToolData: Default + Clone + 'static { +pub trait FormToolData: Clone + 'static { type Style: FormStyle; /// Defines how the form should be layed out and how the data should be parsed and validated. @@ -97,9 +97,9 @@ pub trait FormToolData: Default + Clone + 'static { /// component. Call [`get_action_form`]\() to get the /// [`ActionForm`](leptos_router::ActionForm) version. fn get_form(self, action: impl ToString, style: Self::Style) -> Form { - let builder = FormBuilder::new(self, style); + let builder = FormBuilder::new(); let builder = Self::build_form(builder); - builder.build_plain_form(action.to_string()) + builder.build_plain_form(action.to_string(), self, style) } /// Constructs a [`Form`] for this [`FormToolData`] type. @@ -118,9 +118,9 @@ pub trait FormToolData: Default + Clone + 'static { <>::Request as ClientReq>::FormData: From, { - let builder = FormBuilder::new(self, style); + let builder = FormBuilder::new(); let builder = Self::build_form(builder); - builder.build_action_form(action) + builder.build_action_form(action, self, style) } /// Gets a [`Validator`] for this [`ToolFormData`]. @@ -132,7 +132,7 @@ pub trait FormToolData: Default + Clone + 'static { /// However, the code to render the views are not configured out, it /// simply doesn't run, so the view needs to compile even on the server. fn get_validator() -> FormValidator { - let builder = FormBuilder::new(Self::default(), Self::Style::default()); + let builder = FormBuilder::new(); let builder = Self::build_form(builder); builder.validator() } diff --git a/src/form_builder.rs b/src/form_builder.rs index 49cba10..f649a27 100644 --- a/src/form_builder.rs +++ b/src/form_builder.rs @@ -20,10 +20,6 @@ use web_sys::{FormData, SubmitEvent}; /// /// This builder allows you to specify what components should make up the form. pub struct FormBuilder { - /// The [`ToolFormData`] signal. - pub(crate) fd: RwSignal, - /// The [`FormStyle`]. - pub(crate) fs: FS, /// The list of [`ValidationFn`]s. pub(crate) validations: Vec>>, /// The list of functions that will render the form. @@ -34,21 +30,8 @@ pub struct FormBuilder { impl FormBuilder { /// Creates a new [`FormBuilder`] - pub(crate) fn new(starting_data: FD, form_style: FS) -> FormBuilder { - let fd = create_rw_signal(starting_data); + pub(crate) fn new() -> FormBuilder { FormBuilder { - fd, - fs: form_style, - validations: Vec::new(), - render_fns: Vec::new(), - styles: Vec::new(), - } - } - - pub(crate) fn new_group(fd: RwSignal, fs: FS) -> FormBuilder { - FormBuilder { - fd, - fs, validations: Vec::new(), render_fns: Vec::new(), styles: Vec::new(), @@ -232,19 +215,23 @@ impl FormBuilder { pub(crate) fn build_action_form( self, action: Action>>, + fd: FD, + fs: FS, ) -> Form where ServFn: DeserializeOwned + ServerFn + 'static, <>::Request as ClientReq>::FormData: From, { + let fd = create_rw_signal(fd); + let (views, validation_cbs): (Vec<_>, Vec<_>) = self .render_fns .into_iter() - .map(|r_fn| r_fn(&self.fs, self.fd)) + .map(|r_fn| r_fn(&fs, fd)) .unzip(); - let elements = self.fs.form_frame(views.into_view(), self.styles); + let elements = fs.form_frame(views.into_view(), self.styles); let on_submit = move |ev: SubmitEvent| { let mut failed = false; @@ -265,20 +252,22 @@ impl FormBuilder { }; Form { - fd: self.fd, + fd, validations: self.validations, view, } } - pub(crate) fn build_plain_form(self, url: String) -> Form { + pub(crate) fn build_plain_form(self, url: String, fd: FD, fs: FS) -> Form { + let fd = create_rw_signal(fd); + let (views, validation_cbs): (Vec<_>, Vec<_>) = self .render_fns .into_iter() - .map(|r_fn| r_fn(&self.fs, self.fd)) + .map(|r_fn| r_fn(&fs, fd)) .unzip(); - let elements = self.fs.form_frame(views.into_view(), self.styles); + let elements = fs.form_frame(views.into_view(), self.styles); let on_submit = move |ev: SubmitEvent| { let mut failed = false; @@ -299,7 +288,7 @@ impl FormBuilder { }; Form { - fd: self.fd, + fd, validations: self.validations, view, } diff --git a/src/styles/mod.rs b/src/styles/mod.rs index 68fb6cd..0bd85c8 100644 --- a/src/styles/mod.rs +++ b/src/styles/mod.rs @@ -13,7 +13,7 @@ use leptos::{RwSignal, Signal, View}; pub use grid_form::{GridFormStyle, GridFormStylingAttributes}; -pub trait FormStyle: Default + 'static { +pub trait FormStyle: 'static { type StylingAttributes; /// Render any containing components for the form. From 64d2631140081c8578002e8f431c471facc0cea1 Mon Sep 17 00:00:00 2001 From: Mitchell M Date: Wed, 12 Jun 2024 16:21:09 -0500 Subject: [PATCH 3/5] clean up style trait --- src/controls/group.rs | 5 ++++- src/controls/mod.rs | 1 + src/controls/select.rs | 2 -- src/form_builder.rs | 14 ++++++++++---- src/styles/grid_form.rs | 14 ++++++-------- src/styles/mod.rs | 4 ++-- 6 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/controls/group.rs b/src/controls/group.rs index 1379205..a2ad21e 100644 --- a/src/controls/group.rs +++ b/src/controls/group.rs @@ -18,7 +18,10 @@ impl FormBuilder { .map(|r_fn| r_fn(&fs, fd)) .unzip(); - let view = fs.group(views.collect_view(), group_builder.styles); + let view = fs.group(super::ControlRenderData { + data: Box::new(views.collect_view()), + styles: group_builder.styles, + }); let validation_cb = move || { let mut success = true; for validation in validation_cbs.iter().flatten() { diff --git a/src/controls/mod.rs b/src/controls/mod.rs index e8b4509..b672936 100644 --- a/src/controls/mod.rs +++ b/src/controls/mod.rs @@ -70,6 +70,7 @@ pub trait ValidatedControlData: ControlData {} /// The data needed to render a interactive control of type `C`. pub struct ControlRenderData { + // TODO: Does this need to be boxed? This isn't trait objected any more pub data: Box, pub styles: Vec, } diff --git a/src/controls/select.rs b/src/controls/select.rs index 09f7577..83a775e 100644 --- a/src/controls/select.rs +++ b/src/controls/select.rs @@ -2,8 +2,6 @@ use super::{ControlBuilder, ControlData, ControlRenderData, ValidatedControlData use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle}; use leptos::{Signal, View}; -// TODO: have an option to have a display string and a value string in the options field - #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] pub struct SelectData { pub(crate) name: String, diff --git a/src/form_builder.rs b/src/form_builder.rs index f649a27..0ad5841 100644 --- a/src/form_builder.rs +++ b/src/form_builder.rs @@ -1,7 +1,7 @@ use crate::{ controls::{ - BuiltControlData, BuiltVanityControlData, ControlBuilder, ControlData, FieldGetter, - FieldSetter, ParseFn, RenderFn, UnparseFn, ValidationCb, ValidationFn, + BuiltControlData, BuiltVanityControlData, ControlBuilder, ControlData, ControlRenderData, + FieldGetter, FieldSetter, ParseFn, RenderFn, UnparseFn, ValidationCb, ValidationFn, VanityControlBuilder, VanityControlData, }, form::{Form, FormToolData, FormValidator}, @@ -231,7 +231,10 @@ impl FormBuilder { .map(|r_fn| r_fn(&fs, fd)) .unzip(); - let elements = fs.form_frame(views.into_view(), self.styles); + let elements = fs.form_frame(ControlRenderData { + data: Box::new(views.into_view()), + styles: self.styles, + }); let on_submit = move |ev: SubmitEvent| { let mut failed = false; @@ -267,7 +270,10 @@ impl FormBuilder { .map(|r_fn| r_fn(&fs, fd)) .unzip(); - let elements = fs.form_frame(views.into_view(), self.styles); + let elements = fs.form_frame(ControlRenderData { + data: Box::new(views.into_view()), + styles: self.styles, + }); let on_submit = move |ev: SubmitEvent| { let mut failed = false; diff --git a/src/styles/grid_form.rs b/src/styles/grid_form.rs index 81ca54f..ab4ebae 100644 --- a/src/styles/grid_form.rs +++ b/src/styles/grid_form.rs @@ -21,8 +21,8 @@ pub struct GridFormStyle; impl FormStyle for GridFormStyle { type StylingAttributes = GridFormStylingAttributes; - fn form_frame(&self, children: View, _styles: Vec) -> View { - view! {
{children}
}.into_view() + fn form_frame(&self, form: ControlRenderData) -> View { + view! {
{*form.data}
}.into_view() } fn heading(&self, control: ControlRenderData) -> View { @@ -111,8 +111,7 @@ impl FormStyle for GridFormStyle { } fn submit(&self, control: ControlRenderData) -> View { - view! { } - .into_view() + view! { }.into_view() } fn text_area( @@ -383,10 +382,9 @@ impl FormStyle for GridFormStyle { .into_view() } - // TODO: change this and form frame to use ControlRenderData - fn group(&self, inner: View, styles: Vec) -> View { + fn group(&self, group: ControlRenderData) -> View { let mut width = 12; - for style in styles { + for style in group.styles { match style { GridFormStylingAttributes::Width(w) => width = w, } @@ -394,7 +392,7 @@ impl FormStyle for GridFormStyle { view! {
- {inner} + {*group.data}
} .into_view() diff --git a/src/styles/mod.rs b/src/styles/mod.rs index 0bd85c8..6e3bd47 100644 --- a/src/styles/mod.rs +++ b/src/styles/mod.rs @@ -23,7 +23,7 @@ pub trait FormStyle: 'static { /// /// 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, style: Vec) -> View; + fn form_frame(&self, form: ControlRenderData) -> View; fn heading(&self, control: ControlRenderData) -> View; fn hidden( &self, @@ -91,6 +91,6 @@ pub trait FormStyle: 'static { fn submit(&self, control: ControlRenderData) -> View; // TODO: test custom component fn custom_component(&self, view: View) -> View; - fn group(&self, inner: View, style: Vec) -> View; + fn group(&self, group: ControlRenderData) -> View; fn spacer(&self, control: ControlRenderData) -> View; } From 1e2709dc8c2c2c4a7d54285a1d843f26a8be89d8 Mon Sep 17 00:00:00 2001 From: Mitchell M Date: Wed, 12 Jun 2024 16:29:35 -0500 Subject: [PATCH 4/5] ControlRenderData no long has boxed data --- src/controls/button.rs | 2 +- src/controls/group.rs | 2 +- src/controls/heading.rs | 1 - src/controls/mod.rs | 7 +++---- src/form_builder.rs | 4 ++-- src/styles/grid_form.rs | 4 ++-- src/styles/mod.rs | 1 - 7 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/controls/button.rs b/src/controls/button.rs index d47e803..841d64b 100644 --- a/src/controls/button.rs +++ b/src/controls/button.rs @@ -27,7 +27,7 @@ impl FormBuilder { let control = builder(button_builder); let render_data = ControlRenderData { - data: Box::new(control.data), + data: control.data, styles: control.styles, }; diff --git a/src/controls/group.rs b/src/controls/group.rs index a2ad21e..9ddf664 100644 --- a/src/controls/group.rs +++ b/src/controls/group.rs @@ -19,7 +19,7 @@ impl FormBuilder { .unzip(); let view = fs.group(super::ControlRenderData { - data: Box::new(views.collect_view()), + data: views.collect_view(), styles: group_builder.styles, }); let validation_cb = move || { diff --git a/src/controls/heading.rs b/src/controls/heading.rs index c9d05a9..1f95191 100644 --- a/src/controls/heading.rs +++ b/src/controls/heading.rs @@ -16,7 +16,6 @@ impl VanityControlData for HeadingData { fs.heading(control) } } -// TODO: impl GetterVanityControl impl FormBuilder { pub fn heading( diff --git a/src/controls/mod.rs b/src/controls/mod.rs index b672936..5d8c113 100644 --- a/src/controls/mod.rs +++ b/src/controls/mod.rs @@ -70,9 +70,8 @@ pub trait ValidatedControlData: ControlData {} /// The data needed to render a interactive control of type `C`. pub struct ControlRenderData { - // TODO: Does this need to be boxed? This isn't trait objected any more - pub data: Box, pub styles: Vec, + pub data: C, } /// The data needed to render a read-only control of type `C`. @@ -101,7 +100,7 @@ impl VanityControlBuilder pub(crate) fn build(self) -> BuiltVanityControlData { BuiltVanityControlData { render_data: ControlRenderData { - data: Box::new(self.data), + data: self.data, styles: self.style_attributes, }, getter: self.getter, @@ -209,7 +208,7 @@ impl ControlBuilder FormBuilder { .unzip(); let elements = fs.form_frame(ControlRenderData { - data: Box::new(views.into_view()), + data: views.into_view(), styles: self.styles, }); @@ -271,7 +271,7 @@ impl FormBuilder { .unzip(); let elements = fs.form_frame(ControlRenderData { - data: Box::new(views.into_view()), + data: views.into_view(), styles: self.styles, }); diff --git a/src/styles/grid_form.rs b/src/styles/grid_form.rs index ab4ebae..3a76b16 100644 --- a/src/styles/grid_form.rs +++ b/src/styles/grid_form.rs @@ -22,7 +22,7 @@ impl FormStyle for GridFormStyle { type StylingAttributes = GridFormStylingAttributes; fn form_frame(&self, form: ControlRenderData) -> View { - view! {
{*form.data}
}.into_view() + view! {
{form.data}
}.into_view() } fn heading(&self, control: ControlRenderData) -> View { @@ -392,7 +392,7 @@ impl FormStyle for GridFormStyle { view! {
- {*group.data} + {group.data}
} .into_view() diff --git a/src/styles/mod.rs b/src/styles/mod.rs index 6e3bd47..323d56f 100644 --- a/src/styles/mod.rs +++ b/src/styles/mod.rs @@ -89,7 +89,6 @@ pub trait FormStyle: 'static { validation_state: Signal>, ) -> View; fn submit(&self, control: ControlRenderData) -> View; - // TODO: test custom component fn custom_component(&self, view: View) -> View; fn group(&self, group: ControlRenderData) -> View; fn spacer(&self, control: ControlRenderData) -> View; From 079c9bde53035b966a9352734de2380bdf9c0909 Mon Sep 17 00:00:00 2001 From: Mitchell M Date: Wed, 12 Jun 2024 16:46:03 -0500 Subject: [PATCH 5/5] lint --- src/controls/button.rs | 4 +++- src/controls/group.rs | 2 +- src/form_builder.rs | 42 ++++++++++++++------------------------- src/validation_builder.rs | 8 +++++++- 4 files changed, 26 insertions(+), 30 deletions(-) diff --git a/src/controls/button.rs b/src/controls/button.rs index 841d64b..a3d39fe 100644 --- a/src/controls/button.rs +++ b/src/controls/button.rs @@ -4,10 +4,12 @@ use leptos::RwSignal; use std::rc::Rc; use web_sys::MouseEvent; +type ButtonAction = dyn Fn(MouseEvent, &mut FD); + #[derive(Clone)] pub struct ButtonData { pub(crate) text: String, - pub(crate) action: Option>, + pub(crate) action: Option>>, } impl Default for ButtonData { fn default() -> Self { diff --git a/src/controls/group.rs b/src/controls/group.rs index 9ddf664..27711ac 100644 --- a/src/controls/group.rs +++ b/src/controls/group.rs @@ -15,7 +15,7 @@ impl FormBuilder { let (views, validation_cbs): (Vec<_>, Vec<_>) = group_builder .render_fns .into_iter() - .map(|r_fn| r_fn(&fs, fd)) + .map(|r_fn| r_fn(fs, fd)) .unzip(); let view = fs.group(super::ControlRenderData { diff --git a/src/form_builder.rs b/src/form_builder.rs index 73c317c..de96f90 100644 --- a/src/form_builder.rs +++ b/src/form_builder.rs @@ -1,8 +1,8 @@ use crate::{ controls::{ BuiltControlData, BuiltVanityControlData, ControlBuilder, ControlData, ControlRenderData, - FieldGetter, FieldSetter, ParseFn, RenderFn, UnparseFn, ValidationCb, ValidationFn, - VanityControlBuilder, VanityControlData, + FieldSetter, ParseFn, RenderFn, ValidationCb, ValidationFn, VanityControlBuilder, + VanityControlData, }, form::{Form, FormToolData, FormValidator}, styles::FormStyle, @@ -87,33 +87,17 @@ impl FormBuilder { &mut self, control: ControlBuilder, ) { - let BuiltControlData { - render_data, - getter, - setter, - parse_fn, - unparse_fn, - validation_fn, - } = match control.build() { + let built_control_data = match control.build() { Ok(c) => c, Err(e) => panic!("Invalid Component: {}", e), }; - if let Some(ref validation_fn) = validation_fn { + if let Some(ref validation_fn) = built_control_data.validation_fn { self.validations.push(validation_fn.clone()); } let render_fn = move |fs: &FS, fd: RwSignal| { - let (view, cb) = Self::build_control_view( - fd, - fs, - getter, - setter, - unparse_fn, - parse_fn, - validation_fn, - render_data, - ); + let (view, cb) = Self::build_control_view(fd, fs, built_control_data); (view, Some(cb)) }; @@ -123,13 +107,17 @@ impl FormBuilder { fn build_control_view( fd: RwSignal, fs: &FS, - getter: Rc>, - setter: Rc>, - unparse_fn: Box::ReturnType, FDT>>, - parse_fn: Box::ReturnType, FDT>>, - validation_fn: Option>>, - render_data: crate::controls::ControlRenderData, + control_data: BuiltControlData, ) -> (View, Box) { + let BuiltControlData { + render_data, + getter, + setter, + parse_fn, + unparse_fn, + validation_fn, + } = control_data; + let (validation_signal, validation_signal_set) = create_signal(Ok(())); let validation_fn_clone = validation_fn.clone(); let value_getter = move || { diff --git a/src/validation_builder.rs b/src/validation_builder.rs index 43c4514..b70b254 100644 --- a/src/validation_builder.rs +++ b/src/validation_builder.rs @@ -1,6 +1,12 @@ use crate::{controls::ValidationFn, FormToolData}; use std::fmt::Display; +/// A function that validates a field. +/// +/// This is similar to [`ValidationFn`](crate::controls::ValidationFn) +/// but takes a &str for the name of the field for improved error messages. +type ValidationBuilderFn = dyn Fn(&str, &T) -> Result<(), String> + 'static; + /// A helper builder that allows you to specify a validation function /// declaritivly /// @@ -14,7 +20,7 @@ pub struct ValidationBuilder { /// The getter function for the field to validate. field_fn: Box &T + 'static>, /// The functions to be called when validating. - functions: Vec Result<(), String> + 'static>>, + functions: Vec>>, } impl ValidationBuilder {