Conditional Rendering WORKS!

This commit is contained in:
Mitchell Marino 2024-06-18 12:57:56 -05:00
parent 835271cd22
commit da84bdbb27
18 changed files with 194 additions and 140 deletions

View File

@ -1,6 +1,9 @@
use super::{BuilderFn, ControlRenderData};
use super::{BuilderFn, ControlRenderData, ShowWhenFn};
use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
use leptos::view;
use leptos::RwSignal;
use leptos::Show;
use leptos::Signal;
use std::rc::Rc;
use web_sys::MouseEvent;
@ -36,9 +39,24 @@ impl<FD: FormToolData> FormBuilder<FD> {
data: control.data,
styles: control.styles,
};
let show_when = control.show_when;
let render_fn = move |fs: &FD::Style, fd: RwSignal<FD>| {
let view = fs.button(render_data, fd);
let cx = self.cx.clone();
let render_fn = move |fs: Rc<FD::Style>, fd: RwSignal<FD>| {
let render_data = Rc::new(render_data);
// let cloned_fs = fs.clone();
let view = move || fs.clone().button(render_data.clone(), fd);
let view = match show_when {
Some(when) => {
let when = move || when(fd.into(), cx.clone());
view! {
<Show when=when>
{view.clone()}
</Show>
}
}
None => view(),
};
(view, None)
};
self.render_fns.push(Box::new(render_fn));
@ -50,6 +68,7 @@ impl<FD: FormToolData> FormBuilder<FD> {
pub struct ButtonBuilder<FD: FormToolData> {
pub(crate) styles: Vec<<FD::Style as FormStyle>::StylingAttributes>,
pub(crate) data: ButtonData<FD>,
pub(crate) show_when: Option<Box<dyn ShowWhenFn<FD, FD::Context>>>,
}
impl<FD: FormToolData> ButtonBuilder<FD> {
@ -57,9 +76,21 @@ impl<FD: FormToolData> ButtonBuilder<FD> {
ButtonBuilder {
styles: Vec::default(),
data: ButtonData::default(),
show_when: None,
}
}
/// Sets the function to decide when to render the control.
///
/// Validations for components that are not shown DO NOT run.
pub fn show_when(
mut self,
when: impl Fn(Signal<FD>, Rc<FD::Context>) -> bool + 'static,
) -> Self {
self.show_when = Some(Box::new(when));
self
}
pub fn style(mut self, style: <FD::Style as FormStyle>::StylingAttributes) -> Self {
self.styles.push(style);
self

View File

@ -1,6 +1,7 @@
use super::{BuilderFn, ControlBuilder, ControlData, ControlRenderData};
use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
use leptos::{Signal, View};
use std::rc::Rc;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct CheckboxData {
@ -13,9 +14,9 @@ impl ControlData for CheckboxData {
fn build_control<FS: FormStyle>(
fs: &FS,
control: ControlRenderData<FS, Self>,
control: Rc<ControlRenderData<FS, Self>>,
value_getter: Signal<Self::ReturnType>,
value_setter: Box<dyn Fn(Self::ReturnType)>,
value_setter: Rc<dyn Fn(Self::ReturnType)>,
_validation_state: Signal<Result<(), String>>,
) -> View {
fs.checkbox(control, value_getter, value_setter)

View File

@ -1,4 +1,6 @@
use super::ValidationCb;
use std::rc::Rc;
use super::{ControlRenderData, ValidationCb};
use crate::styles::FormStyle;
use crate::{form::FormToolData, form_builder::FormBuilder};
use leptos::{CollectView, RwSignal};
@ -15,17 +17,20 @@ impl<FD: FormToolData> FormBuilder<FD> {
self.validations.push(validation);
}
let render_fn = move |fs: &FD::Style, fd: RwSignal<FD>| {
let render_fn = move |fs: Rc<FD::Style>, fd: RwSignal<FD>| {
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.clone(), fd))
.unzip();
let view = fs.group(super::ControlRenderData {
let render_data = Rc::new(ControlRenderData {
data: views.collect_view(),
styles: group_builder.styles,
});
let view = fs.group(render_data.clone());
let validation_cb = move || {
let mut success = true;
for validation in validation_cbs.iter().flatten() {

View File

@ -1,6 +1,7 @@
use super::{BuilderFn, ControlRenderData, VanityControlBuilder, VanityControlData};
use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
use leptos::View;
use std::rc::Rc;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct HeadingData {
@ -10,7 +11,7 @@ pub struct HeadingData {
impl VanityControlData for HeadingData {
fn build_control<FS: FormStyle>(
fs: &FS,
control: ControlRenderData<FS, Self>,
control: Rc<ControlRenderData<FS, Self>>,
_value_getter: Option<leptos::prelude::Signal<String>>,
) -> View {
fs.heading(control)

View File

@ -3,6 +3,7 @@ use super::{
};
use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
use leptos::{Signal, View};
use std::rc::Rc;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct HiddenData {
@ -12,7 +13,7 @@ pub struct HiddenData {
impl VanityControlData for HiddenData {
fn build_control<FS: FormStyle>(
fs: &FS,
control: ControlRenderData<FS, Self>,
control: Rc<ControlRenderData<FS, Self>>,
value_getter: Option<Signal<String>>,
) -> View {
fs.hidden(control, value_getter)

View File

@ -26,8 +26,8 @@ pub trait UnparseFn<CR, FDT>: Fn(FDT) -> CR + 'static {}
pub trait FieldGetter<FD, FDT>: Fn(FD) -> FDT + 'static {}
pub trait FieldSetter<FD, FDT>: Fn(&mut FD, FDT) + 'static {}
pub trait ShowWhenFn<FD: 'static, CX>: Fn(Signal<FD>, Rc<CX>) -> bool + 'static {}
pub trait RenderFn<FS, FD>:
FnOnce(&FS, RwSignal<FD>) -> (View, Option<Box<dyn ValidationCb>>) + 'static
pub trait RenderFn<FS, FD: 'static>:
FnOnce(Rc<FS>, RwSignal<FD>) -> (View, Option<Box<dyn ValidationCb>>) + 'static
{
}
@ -40,8 +40,8 @@ impl<CR, FDT, F> UnparseFn<CR, FDT> for F where F: Fn(FDT) -> CR + 'static {}
impl<FD, FDT, F> FieldGetter<FD, FDT> for F where F: Fn(FD) -> FDT + 'static {}
impl<FD, FDT, F> FieldSetter<FD, FDT> for F where F: Fn(&mut FD, FDT) + 'static {}
impl<FD: 'static, CX, F> ShowWhenFn<FD, CX> for F where F: Fn(Signal<FD>, Rc<CX>) -> bool + 'static {}
impl<FS, FD, F> RenderFn<FS, FD> for F where
F: FnOnce(&FS, RwSignal<FD>) -> (View, Option<Box<dyn ValidationCb>>) + 'static
impl<FS, FD: 'static, F> RenderFn<FS, FD> for F where
F: FnOnce(Rc<FS>, RwSignal<FD>) -> (View, Option<Box<dyn ValidationCb>>) + 'static
{
}
@ -50,7 +50,7 @@ pub trait VanityControlData: 'static {
/// Builds the control, returning the [`View`] that was built.
fn build_control<FS: FormStyle>(
fs: &FS,
control: ControlRenderData<FS, Self>,
control: Rc<ControlRenderData<FS, Self>>,
value_getter: Option<Signal<String>>,
) -> View;
}
@ -64,9 +64,9 @@ pub trait ControlData: 'static {
/// Builds the control, returning the [`View`] that was built.
fn build_control<FS: FormStyle>(
fs: &FS,
control: ControlRenderData<FS, Self>,
control: Rc<ControlRenderData<FS, Self>>,
value_getter: Signal<Self::ReturnType>,
value_setter: Box<dyn Fn(Self::ReturnType)>,
value_setter: Rc<dyn Fn(Self::ReturnType)>,
validation_state: Signal<Result<(), String>>,
) -> View;
}

View File

@ -3,6 +3,7 @@ use super::{
};
use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
use leptos::{Signal, View};
use std::rc::Rc;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct OutputData;
@ -10,7 +11,7 @@ pub struct OutputData;
impl VanityControlData for OutputData {
fn build_control<FS: FormStyle>(
fs: &FS,
control: ControlRenderData<FS, Self>,
control: Rc<ControlRenderData<FS, Self>>,
value_getter: Option<Signal<String>>,
) -> View {
fs.output(control, value_getter)

View File

@ -1,6 +1,7 @@
use super::{BuilderFn, ControlBuilder, ControlData, ControlRenderData, ValidatedControlData};
use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
use leptos::{Signal, View};
use std::rc::Rc;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct RadioButtonsData {
@ -14,9 +15,9 @@ impl ControlData for RadioButtonsData {
fn build_control<FS: FormStyle>(
fs: &FS,
control: ControlRenderData<FS, Self>,
control: Rc<ControlRenderData<FS, Self>>,
value_getter: Signal<Self::ReturnType>,
value_setter: Box<dyn Fn(Self::ReturnType)>,
value_setter: Rc<dyn Fn(Self::ReturnType)>,
validation_state: Signal<Result<(), String>>,
) -> View {
fs.radio_buttons(control, value_getter, value_setter, validation_state)

View File

@ -1,6 +1,7 @@
use super::{BuilderFn, ControlBuilder, ControlData, ControlRenderData, ValidatedControlData};
use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
use leptos::{Signal, View};
use std::rc::Rc;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct SelectData {
@ -17,9 +18,9 @@ impl ControlData for SelectData {
fn build_control<FS: FormStyle>(
fs: &FS,
control: ControlRenderData<FS, Self>,
control: Rc<ControlRenderData<FS, Self>>,
value_getter: Signal<Self::ReturnType>,
value_setter: Box<dyn Fn(Self::ReturnType)>,
value_setter: Rc<dyn Fn(Self::ReturnType)>,
validation_state: Signal<Result<(), String>>,
) -> View {
fs.select(control, value_getter, value_setter, validation_state)

View File

@ -1,7 +1,7 @@
use super::{BuilderFn, ControlBuilder, ControlData, ControlRenderData};
use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
use leptos::{Signal, View};
use std::ops::RangeInclusive;
use std::{ops::RangeInclusive, rc::Rc};
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SliderData {
@ -27,9 +27,9 @@ impl ControlData for SliderData {
fn build_control<FS: FormStyle>(
fs: &FS,
control: ControlRenderData<FS, Self>,
control: Rc<ControlRenderData<FS, Self>>,
value_getter: Signal<Self::ReturnType>,
value_setter: Box<dyn Fn(Self::ReturnType)>,
value_setter: Rc<dyn Fn(Self::ReturnType)>,
validation_state: Signal<Result<(), String>>,
) -> View {
fs.slider(control, value_getter, value_setter, validation_state)

View File

@ -1,6 +1,7 @@
use super::{BuilderFn, ControlRenderData, VanityControlBuilder, VanityControlData};
use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
use leptos::{prelude::Signal, View};
use std::rc::Rc;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct SpacerData {
@ -10,7 +11,7 @@ pub struct SpacerData {
impl VanityControlData for SpacerData {
fn build_control<FS: FormStyle>(
fs: &FS,
control: ControlRenderData<FS, Self>,
control: Rc<ControlRenderData<FS, Self>>,
_value_getter: Option<Signal<String>>,
) -> View {
fs.spacer(control)

View File

@ -1,7 +1,7 @@
use super::{BuilderFn, ControlBuilder, ControlData, ControlRenderData, ValidatedControlData};
use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
use leptos::{Signal, View};
use std::ops::RangeInclusive;
use std::{ops::RangeInclusive, rc::Rc};
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct StepperData {
@ -17,9 +17,9 @@ impl ControlData for StepperData {
fn build_control<FS: FormStyle>(
fs: &FS,
control: ControlRenderData<FS, Self>,
control: Rc<ControlRenderData<FS, Self>>,
value_getter: Signal<Self::ReturnType>,
value_setter: Box<dyn Fn(Self::ReturnType)>,
value_setter: Rc<dyn Fn(Self::ReturnType)>,
validation_state: Signal<Result<(), String>>,
) -> View {
fs.stepper(control, value_getter, value_setter, validation_state)

View File

@ -1,6 +1,7 @@
use super::{BuilderFn, ControlRenderData, VanityControlBuilder, VanityControlData};
use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
use leptos::{prelude::Signal, View};
use std::rc::Rc;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct SubmitData {
@ -10,7 +11,7 @@ pub struct SubmitData {
impl VanityControlData for SubmitData {
fn build_control<FS: FormStyle>(
fs: &FS,
control: ControlRenderData<FS, Self>,
control: Rc<ControlRenderData<FS, Self>>,
_value_getter: Option<Signal<String>>,
) -> View {
fs.submit(control)

View File

@ -1,6 +1,7 @@
use super::{BuilderFn, ControlBuilder, ControlData, ControlRenderData, ValidatedControlData};
use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
use leptos::{Signal, View};
use std::rc::Rc;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct TextAreaData {
@ -13,9 +14,9 @@ impl ControlData for TextAreaData {
fn build_control<FS: FormStyle>(
fs: &FS,
control: ControlRenderData<FS, Self>,
control: Rc<ControlRenderData<FS, Self>>,
value_getter: Signal<Self::ReturnType>,
value_setter: Box<dyn Fn(Self::ReturnType)>,
value_setter: Rc<dyn Fn(Self::ReturnType)>,
validation_state: Signal<Result<(), String>>,
) -> View {
fs.text_area(control, value_getter, value_setter, validation_state)

View File

@ -1,3 +1,5 @@
use std::rc::Rc;
use super::{BuilderFn, ControlBuilder, ControlData, ControlRenderData, ValidatedControlData};
use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
use leptos::{Signal, View};
@ -28,9 +30,9 @@ impl ControlData for TextInputData {
fn build_control<FS: FormStyle>(
fs: &FS,
control: ControlRenderData<FS, Self>,
control: Rc<ControlRenderData<FS, Self>>,
value_getter: Signal<Self::ReturnType>,
value_setter: Box<dyn Fn(Self::ReturnType)>,
value_setter: Rc<dyn Fn(Self::ReturnType)>,
validation_state: Signal<Result<(), String>>,
) -> View {
fs.text_input(control, value_getter, value_setter, validation_state)

View File

@ -93,19 +93,21 @@ impl<FD: FormToolData> FormBuilder<FD> {
} = vanity_control.build();
let cx = self.cx.clone();
let render_fn = move |fs: &FD::Style, fd: RwSignal<FD>| {
let render_fn = move |fs: Rc<FD::Style>, fd: RwSignal<FD>| {
let render_data = Rc::new(render_data);
let value_getter = getter.map(|getter| (move || getter(fd.get())).into_signal());
let view = VanityControlData::build_control(fs, render_data, value_getter);
let view =
move || VanityControlData::build_control(&*fs, render_data.clone(), value_getter);
let view = match show_when {
Some(when) => {
let when = move || when(fd.into(), cx.clone());
view! {
<Show when=when>
{&view}
{view.clone()}
</Show>
}
}
None => view,
None => view(),
};
(view, None)
};
@ -128,7 +130,7 @@ impl<FD: FormToolData> FormBuilder<FD> {
}
let cx = self.cx.clone();
let render_fn = move |fs: &FD::Style, fd: RwSignal<FD>| {
let render_fn = move |fs: Rc<FD::Style>, fd: RwSignal<FD>| {
let (view, cb) = Self::build_control_view(fd, fs, built_control_data, cx);
(view, Some(cb))
};
@ -138,7 +140,7 @@ impl<FD: FormToolData> FormBuilder<FD> {
fn build_control_view<C: ControlData, FDT: 'static>(
fd: RwSignal<FD>,
fs: &FD::Style,
fs: Rc<FD::Style>,
control_data: BuiltControlData<FD, C, FDT>,
cx: Rc<FD::Context>,
) -> (View, Box<dyn ValidationCb>) {
@ -152,6 +154,7 @@ impl<FD: FormToolData> FormBuilder<FD> {
show_when,
} = control_data;
let render_data = Rc::new(render_data);
let (validation_signal, validation_signal_set) = create_signal(Ok(()));
let validation_fn_clone = validation_fn.clone();
let value_getter = move || {
@ -194,23 +197,25 @@ impl<FD: FormToolData> FormBuilder<FD> {
fd,
);
let view = C::build_control(
fs,
render_data,
let view = move || {
C::build_control(
&*fs,
render_data.clone(),
value_getter,
value_setter,
value_setter.clone(),
validation_signal.into(),
);
)
};
let view = match show_when {
Some(when) => {
let when = move || when(fd.into(), cx.clone());
view! {
<Show when=when>
{&view}
{view.clone()}
</Show>
}
}
None => view,
None => view(),
};
(view, validation_cb)
}
@ -221,7 +226,7 @@ impl<FD: FormToolData> FormBuilder<FD> {
parse_fn: Box<dyn ParseFn<CRT, FDT>>,
setter: Rc<dyn FieldSetter<FD, FDT>>,
fd: RwSignal<FD>,
) -> Box<dyn Fn(CRT) + 'static> {
) -> Rc<dyn Fn(CRT) + 'static> {
let value_setter = move |value| {
let parsed = match parse_fn(value) {
Ok(p) => {
@ -242,7 +247,7 @@ impl<FD: FormToolData> FormBuilder<FD> {
// run validation
(validation_cb)();
};
Box::new(value_setter)
Rc::new(value_setter)
}
// TODO: impl build_formless function that builds the form without adding
@ -260,11 +265,12 @@ impl<FD: FormToolData> FormBuilder<FD> {
From<FormData>,
{
let fd = create_rw_signal(fd);
let fs = Rc::new(fs);
let (views, validation_cbs): (Vec<_>, Vec<_>) = self
.render_fns
.into_iter()
.map(|r_fn| r_fn(&fs, fd))
.map(|r_fn| r_fn(fs.clone(), fd))
.unzip();
let elements = fs.form_frame(ControlRenderData {
@ -310,11 +316,12 @@ impl<FD: FormToolData> FormBuilder<FD> {
From<FormData>,
{
let fd = create_rw_signal(fd);
let fs = Rc::new(fs);
let (views, validation_cbs): (Vec<_>, Vec<_>) = self
.render_fns
.into_iter()
.map(|r_fn| r_fn(&fs, fd))
.map(|r_fn| r_fn(fs.clone(), fd))
.unzip();
let elements = fs.form_frame(ControlRenderData {
@ -349,11 +356,12 @@ impl<FD: FormToolData> FormBuilder<FD> {
pub(crate) fn build_plain_form(self, url: String, fd: FD, fs: FD::Style) -> Form<FD> {
let fd = create_rw_signal(fd);
let fs = Rc::new(fs);
let (views, validation_cbs): (Vec<_>, Vec<_>) = self
.render_fns
.into_iter()
.map(|r_fn| r_fn(&fs, fd))
.map(|r_fn| r_fn(fs.clone(), fd))
.unzip();
let elements = fs.form_frame(ControlRenderData {

View File

@ -2,7 +2,8 @@ use super::FormStyle;
use crate::{
controls::{
button::ButtonData, checkbox::CheckboxData, heading::HeadingData, hidden::HiddenData,
output::OutputData, select::SelectData, spacer::SpacerData, submit::SubmitData,
output::OutputData, radio_buttons::RadioButtonsData, select::SelectData,
slider::SliderData, spacer::SpacerData, stepper::StepperData, submit::SubmitData,
text_area::TextAreaData, text_input::TextInputData, ControlData, ControlRenderData,
},
FormToolData,
@ -25,22 +26,22 @@ impl FormStyle for GridFormStyle {
view! { <div class="form_grid">{form.data}</div> }.into_view()
}
fn heading(&self, control: ControlRenderData<Self, HeadingData>) -> View {
fn heading(&self, control: Rc<ControlRenderData<Self, HeadingData>>) -> View {
view! { <h2 class="form_heading">{&control.data.title}</h2> }.into_view()
}
fn text_input(
&self,
control: ControlRenderData<Self, TextInputData>,
control: Rc<ControlRenderData<Self, TextInputData>>,
value_getter: Signal<<TextInputData as ControlData>::ReturnType>,
value_setter: Box<dyn Fn(<TextInputData as ControlData>::ReturnType)>,
value_setter: Rc<dyn Fn(<TextInputData as ControlData>::ReturnType)>,
validation_state: Signal<Result<(), String>>,
) -> View {
// TODO: extract this to a common thing
let mut width = 1;
for style in control.styles {
for style in control.styles.iter() {
match style {
GridFormStylingAttributes::Width(w) => width = w,
GridFormStylingAttributes::Width(w) => width = *w,
}
}
@ -55,8 +56,8 @@ impl FormStyle for GridFormStyle {
<input
type=control.data.input_type
id=&control.data.name
name=control.data.name
placeholder=control.data.placeholder
name=&control.data.name
placeholder=control.data.placeholder.as_ref()
prop:value=move || value_getter.get()
on:focusout=move |ev| {
value_setter(event_target_value(&ev));
@ -72,26 +73,28 @@ impl FormStyle for GridFormStyle {
fn select(
&self,
control: ControlRenderData<Self, SelectData>,
control: Rc<ControlRenderData<Self, SelectData>>,
value_getter: Signal<<SelectData as ControlData>::ReturnType>,
value_setter: Box<dyn Fn(<SelectData as ControlData>::ReturnType)>,
value_setter: Rc<dyn Fn(<SelectData as ControlData>::ReturnType)>,
validation_state: Signal<Result<(), String>>,
) -> View {
let mut width = 1;
for style in control.styles {
for style in control.styles.iter() {
match style {
GridFormStylingAttributes::Width(w) => width = w,
GridFormStylingAttributes::Width(w) => width = *w,
}
}
let options_view = control
.data
.options
.into_iter()
.iter()
.map(|(display, value)| {
let display = display.clone();
let value = value.clone();
view! {
<option value=value.clone() selected=move || { value_getter.get() == *value }>
{display.clone()}
{display}
</option>
}
})
@ -107,7 +110,7 @@ impl FormStyle for GridFormStyle {
</div>
<select
id=&control.data.name
name=control.data.name
name=&control.data.name
class="form_input"
on:input=move |ev| {
value_setter(event_target_value(&ev));
@ -121,15 +124,15 @@ impl FormStyle for GridFormStyle {
.into_view()
}
fn submit(&self, control: ControlRenderData<Self, SubmitData>) -> View {
view! { <input type="submit" value=control.data.text class="form_submit"/> }.into_view()
fn submit(&self, control: Rc<ControlRenderData<Self, SubmitData>>) -> View {
view! { <input type="submit" value=&control.data.text class="form_submit"/> }.into_view()
}
fn text_area(
&self,
control: ControlRenderData<Self, TextAreaData>,
control: Rc<ControlRenderData<Self, TextAreaData>>,
value_getter: Signal<<TextAreaData as ControlData>::ReturnType>,
value_setter: Box<dyn Fn(<TextAreaData as ControlData>::ReturnType)>,
value_setter: Rc<dyn Fn(<TextAreaData as ControlData>::ReturnType)>,
validation_state: Signal<Result<(), String>>,
) -> View {
view! {
@ -137,8 +140,8 @@ impl FormStyle for GridFormStyle {
{move || format!("{:?}", validation_state.get())}
<textarea
id=&control.data.name
name=control.data.name
placeholder=control.data.placeholder
name=&control.data.name
placeholder=control.data.placeholder.as_ref()
class="form_input"
prop:value=move || value_getter.get()
on:change=move |ev| {
@ -158,29 +161,25 @@ impl FormStyle for GridFormStyle {
fn hidden(
&self,
control: ControlRenderData<Self, HiddenData>,
control: Rc<ControlRenderData<Self, HiddenData>>,
value_getter: Option<Signal<String>>,
) -> View {
let value_getter = move || value_getter.map(|g| g.get());
view! { <input name=control.data.name prop:value=value_getter style="visibility: hidden"/> }
view! { <input name=&control.data.name prop:value=value_getter style="visibility: hidden"/> }
.into_view()
}
fn radio_buttons(
&self,
control: ControlRenderData<Self, crate::controls::radio_buttons::RadioButtonsData>,
value_getter: Signal<
<crate::controls::radio_buttons::RadioButtonsData as ControlData>::ReturnType,
>,
value_setter: Box<
dyn Fn(<crate::controls::radio_buttons::RadioButtonsData as ControlData>::ReturnType),
>,
control: Rc<ControlRenderData<Self, RadioButtonsData>>,
value_getter: Signal<<RadioButtonsData as ControlData>::ReturnType>,
value_setter: Rc<dyn Fn(<RadioButtonsData as ControlData>::ReturnType)>,
validation_state: Signal<Result<(), String>>,
) -> View {
let mut width = 1;
for style in control.styles {
for style in control.styles.iter() {
match style {
GridFormStylingAttributes::Width(w) => width = w,
GridFormStylingAttributes::Width(w) => width = *w,
}
}
@ -188,7 +187,7 @@ impl FormStyle for GridFormStyle {
let buttons_view = control
.data
.options
.into_iter()
.iter()
.map(|o| {
let value_setter = value_setter.clone();
let o_clone1 = o.clone();
@ -209,7 +208,7 @@ impl FormStyle for GridFormStyle {
}
/>
<label for=&o>{&o}</label>
<label for=o>{o}</label>
<br/>
}
})
@ -236,14 +235,14 @@ impl FormStyle for GridFormStyle {
fn checkbox(
&self,
control: ControlRenderData<Self, CheckboxData>,
control: Rc<ControlRenderData<Self, CheckboxData>>,
value_getter: Signal<<CheckboxData as ControlData>::ReturnType>,
value_setter: Box<dyn Fn(<CheckboxData as ControlData>::ReturnType)>,
value_setter: Rc<dyn Fn(<CheckboxData as ControlData>::ReturnType)>,
) -> View {
let mut width = 1;
for style in control.styles {
for style in control.styles.iter() {
match style {
GridFormStylingAttributes::Width(w) => width = w,
GridFormStylingAttributes::Width(w) => width = *w,
}
}
@ -264,7 +263,7 @@ impl FormStyle for GridFormStyle {
}
/>
<span>{control.data.label}</span>
<span>{control.data.label.as_ref()}</span>
</label>
</div>
}
@ -273,17 +272,15 @@ impl FormStyle for GridFormStyle {
fn stepper(
&self,
control: ControlRenderData<Self, crate::controls::stepper::StepperData>,
value_getter: Signal<<crate::controls::stepper::StepperData as ControlData>::ReturnType>,
value_setter: Box<
dyn Fn(<crate::controls::stepper::StepperData as ControlData>::ReturnType),
>,
control: Rc<ControlRenderData<Self, StepperData>>,
value_getter: Signal<<StepperData as ControlData>::ReturnType>,
value_setter: Rc<dyn Fn(<StepperData as ControlData>::ReturnType)>,
validation_state: Signal<Result<(), String>>,
) -> View {
let mut width = 1;
for style in control.styles {
for style in control.styles.iter() {
match style {
GridFormStylingAttributes::Width(w) => width = w,
GridFormStylingAttributes::Width(w) => width = *w,
}
}
@ -314,7 +311,7 @@ impl FormStyle for GridFormStyle {
fn output(
&self,
_control: ControlRenderData<Self, OutputData>,
_control: Rc<ControlRenderData<Self, OutputData>>,
value_getter: Option<Signal<String>>,
) -> View {
view! { <div>{move || value_getter.map(|g| g.get())}</div> }.into_view()
@ -322,15 +319,15 @@ impl FormStyle for GridFormStyle {
fn slider(
&self,
control: ControlRenderData<Self, crate::controls::slider::SliderData>,
value_getter: Signal<<crate::controls::slider::SliderData as ControlData>::ReturnType>,
value_setter: Box<dyn Fn(<crate::controls::slider::SliderData as ControlData>::ReturnType)>,
control: Rc<ControlRenderData<Self, SliderData>>,
value_getter: Signal<<SliderData as ControlData>::ReturnType>,
value_setter: Rc<dyn Fn(<SliderData as ControlData>::ReturnType)>,
validation_state: Signal<Result<(), String>>,
) -> View {
let mut width = 1;
for style in control.styles {
for style in control.styles.iter() {
match style {
GridFormStylingAttributes::Width(w) => width = w,
GridFormStylingAttributes::Width(w) => width = *w,
}
}
@ -365,13 +362,13 @@ impl FormStyle for GridFormStyle {
fn button<FD: FormToolData>(
&self,
control: ControlRenderData<Self, ButtonData<FD>>,
control: Rc<ControlRenderData<Self, ButtonData<FD>>>,
data_signal: RwSignal<FD>,
) -> View {
let mut width = 1;
for style in control.styles {
for style in control.styles.iter() {
match style {
GridFormStylingAttributes::Width(w) => width = w,
GridFormStylingAttributes::Width(w) => width = *w,
}
}
@ -389,37 +386,37 @@ impl FormStyle for GridFormStyle {
on:click=on_click
style:grid-column=format!("span {}", width)
>
{control.data.text}
{&control.data.text}
</button>
}
.into_view()
}
fn group(&self, group: ControlRenderData<Self, View>) -> View {
fn group(&self, group: Rc<ControlRenderData<Self, View>>) -> View {
let mut width = 12;
for style in group.styles {
for style in group.styles.iter() {
match style {
GridFormStylingAttributes::Width(w) => width = w,
GridFormStylingAttributes::Width(w) => width = *w,
}
}
view! {
<div class="form_group form_grid" style:grid-column=format!("span {}", width)>
{group.data}
{&group.data}
</div>
}
.into_view()
}
fn spacer(&self, control: ControlRenderData<Self, SpacerData>) -> View {
fn spacer(&self, control: Rc<ControlRenderData<Self, SpacerData>>) -> View {
let mut width = 12;
for style in control.styles {
for style in control.styles.iter() {
match style {
GridFormStylingAttributes::Width(w) => width = w,
GridFormStylingAttributes::Width(w) => width = *w,
}
}
view! { <div style:grid-column=format!("span {}", width) style:height=control.data.height></div> }
view! { <div style:grid-column=format!("span {}", width) style:height=control.data.height.as_ref()></div> }
.into_view()
}
}

View File

@ -1,5 +1,7 @@
mod grid_form;
use std::rc::Rc;
use crate::{
controls::{
button::ButtonData, checkbox::CheckboxData, heading::HeadingData, hidden::HiddenData,
@ -24,72 +26,72 @@ 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, form: ControlRenderData<Self, View>) -> View;
fn heading(&self, control: ControlRenderData<Self, HeadingData>) -> View;
fn heading(&self, control: Rc<ControlRenderData<Self, HeadingData>>) -> View;
fn hidden(
&self,
control: ControlRenderData<Self, HiddenData>,
control: Rc<ControlRenderData<Self, HiddenData>>,
value_getter: Option<Signal<String>>,
) -> View;
fn text_input(
&self,
control: ControlRenderData<Self, TextInputData>,
control: Rc<ControlRenderData<Self, TextInputData>>,
value_getter: Signal<<TextInputData as ControlData>::ReturnType>,
value_setter: Box<dyn Fn(<TextInputData as ControlData>::ReturnType)>,
value_setter: Rc<dyn Fn(<TextInputData as ControlData>::ReturnType)>,
validation_state: Signal<Result<(), String>>,
) -> View;
fn text_area(
&self,
control: ControlRenderData<Self, TextAreaData>,
control: Rc<ControlRenderData<Self, TextAreaData>>,
value_getter: Signal<<TextAreaData as ControlData>::ReturnType>,
value_setter: Box<dyn Fn(<TextAreaData as ControlData>::ReturnType)>,
value_setter: Rc<dyn Fn(<TextAreaData as ControlData>::ReturnType)>,
validation_state: Signal<Result<(), String>>,
) -> View;
fn radio_buttons(
&self,
control: ControlRenderData<Self, RadioButtonsData>,
control: Rc<ControlRenderData<Self, RadioButtonsData>>,
value_getter: Signal<<RadioButtonsData as ControlData>::ReturnType>,
value_setter: Box<dyn Fn(<RadioButtonsData as ControlData>::ReturnType)>,
value_setter: Rc<dyn Fn(<RadioButtonsData as ControlData>::ReturnType)>,
validation_state: Signal<Result<(), String>>,
) -> View;
fn select(
&self,
control: ControlRenderData<Self, SelectData>,
control: Rc<ControlRenderData<Self, SelectData>>,
value_getter: Signal<<SelectData as ControlData>::ReturnType>,
value_setter: Box<dyn Fn(<SelectData as ControlData>::ReturnType)>,
value_setter: Rc<dyn Fn(<SelectData as ControlData>::ReturnType)>,
validation_state: Signal<Result<(), String>>,
) -> View;
fn button<FD: FormToolData>(
&self,
control: ControlRenderData<Self, ButtonData<FD>>,
control: Rc<ControlRenderData<Self, ButtonData<FD>>>,
data_signal: RwSignal<FD>,
) -> View;
fn checkbox(
&self,
control: ControlRenderData<Self, CheckboxData>,
control: Rc<ControlRenderData<Self, CheckboxData>>,
value_getter: Signal<<CheckboxData as ControlData>::ReturnType>,
value_setter: Box<dyn Fn(<CheckboxData as ControlData>::ReturnType)>,
value_setter: Rc<dyn Fn(<CheckboxData as ControlData>::ReturnType)>,
) -> View;
fn stepper(
&self,
control: ControlRenderData<Self, StepperData>,
control: Rc<ControlRenderData<Self, StepperData>>,
value_getter: Signal<<StepperData as ControlData>::ReturnType>,
value_setter: Box<dyn Fn(<StepperData as ControlData>::ReturnType)>,
value_setter: Rc<dyn Fn(<StepperData as ControlData>::ReturnType)>,
validation_state: Signal<Result<(), String>>,
) -> View;
fn output(
&self,
control: ControlRenderData<Self, OutputData>,
control: Rc<ControlRenderData<Self, OutputData>>,
value_getter: Option<Signal<String>>,
) -> View;
fn slider(
&self,
control: ControlRenderData<Self, SliderData>,
control: Rc<ControlRenderData<Self, SliderData>>,
value_getter: Signal<<SliderData as ControlData>::ReturnType>,
value_setter: Box<dyn Fn(<SliderData as ControlData>::ReturnType)>,
value_setter: Rc<dyn Fn(<SliderData as ControlData>::ReturnType)>,
validation_state: Signal<Result<(), String>>,
) -> View;
fn submit(&self, control: ControlRenderData<Self, SubmitData>) -> View;
fn submit(&self, control: Rc<ControlRenderData<Self, SubmitData>>) -> View;
fn custom_component(&self, view: View) -> View;
fn group(&self, group: ControlRenderData<Self, View>) -> View;
fn spacer(&self, control: ControlRenderData<Self, SpacerData>) -> View;
fn group(&self, group: Rc<ControlRenderData<Self, View>>) -> View;
fn spacer(&self, control: Rc<ControlRenderData<Self, SpacerData>>) -> View;
}