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 crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
use leptos::view;
use leptos::RwSignal; use leptos::RwSignal;
use leptos::Show;
use leptos::Signal;
use std::rc::Rc; use std::rc::Rc;
use web_sys::MouseEvent; use web_sys::MouseEvent;
@ -36,9 +39,24 @@ impl<FD: FormToolData> FormBuilder<FD> {
data: control.data, data: control.data,
styles: control.styles, styles: control.styles,
}; };
let show_when = control.show_when;
let render_fn = move |fs: &FD::Style, fd: RwSignal<FD>| { let cx = self.cx.clone();
let view = fs.button(render_data, fd); 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) (view, None)
}; };
self.render_fns.push(Box::new(render_fn)); self.render_fns.push(Box::new(render_fn));
@ -50,6 +68,7 @@ impl<FD: FormToolData> FormBuilder<FD> {
pub struct ButtonBuilder<FD: FormToolData> { pub struct ButtonBuilder<FD: FormToolData> {
pub(crate) styles: Vec<<FD::Style as FormStyle>::StylingAttributes>, pub(crate) styles: Vec<<FD::Style as FormStyle>::StylingAttributes>,
pub(crate) data: ButtonData<FD>, pub(crate) data: ButtonData<FD>,
pub(crate) show_when: Option<Box<dyn ShowWhenFn<FD, FD::Context>>>,
} }
impl<FD: FormToolData> ButtonBuilder<FD> { impl<FD: FormToolData> ButtonBuilder<FD> {
@ -57,9 +76,21 @@ impl<FD: FormToolData> ButtonBuilder<FD> {
ButtonBuilder { ButtonBuilder {
styles: Vec::default(), styles: Vec::default(),
data: ButtonData::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 { pub fn style(mut self, style: <FD::Style as FormStyle>::StylingAttributes) -> Self {
self.styles.push(style); self.styles.push(style);
self self

View File

@ -1,6 +1,7 @@
use super::{BuilderFn, ControlBuilder, ControlData, ControlRenderData}; use super::{BuilderFn, ControlBuilder, ControlData, ControlRenderData};
use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle}; use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
use leptos::{Signal, View}; use leptos::{Signal, View};
use std::rc::Rc;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct CheckboxData { pub struct CheckboxData {
@ -13,9 +14,9 @@ impl ControlData for CheckboxData {
fn build_control<FS: FormStyle>( fn build_control<FS: FormStyle>(
fs: &FS, fs: &FS,
control: ControlRenderData<FS, Self>, control: Rc<ControlRenderData<FS, Self>>,
value_getter: Signal<Self::ReturnType>, value_getter: Signal<Self::ReturnType>,
value_setter: Box<dyn Fn(Self::ReturnType)>, value_setter: Rc<dyn Fn(Self::ReturnType)>,
_validation_state: Signal<Result<(), String>>, _validation_state: Signal<Result<(), String>>,
) -> View { ) -> View {
fs.checkbox(control, value_getter, value_setter) 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::styles::FormStyle;
use crate::{form::FormToolData, form_builder::FormBuilder}; use crate::{form::FormToolData, form_builder::FormBuilder};
use leptos::{CollectView, RwSignal}; use leptos::{CollectView, RwSignal};
@ -15,17 +17,20 @@ impl<FD: FormToolData> FormBuilder<FD> {
self.validations.push(validation); 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 let (views, validation_cbs): (Vec<_>, Vec<_>) = group_builder
.render_fns .render_fns
.into_iter() .into_iter()
.map(|r_fn| r_fn(fs, fd)) .map(|r_fn| r_fn(fs.clone(), fd))
.unzip(); .unzip();
let view = fs.group(super::ControlRenderData { let render_data = Rc::new(ControlRenderData {
data: views.collect_view(), data: views.collect_view(),
styles: group_builder.styles, styles: group_builder.styles,
}); });
let view = fs.group(render_data.clone());
let validation_cb = move || { let validation_cb = move || {
let mut success = true; let mut success = true;
for validation in validation_cbs.iter().flatten() { for validation in validation_cbs.iter().flatten() {

View File

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

View File

@ -3,6 +3,7 @@ use super::{
}; };
use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle}; use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
use leptos::{Signal, View}; use leptos::{Signal, View};
use std::rc::Rc;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct HiddenData { pub struct HiddenData {
@ -12,7 +13,7 @@ pub struct HiddenData {
impl VanityControlData for HiddenData { impl VanityControlData for HiddenData {
fn build_control<FS: FormStyle>( fn build_control<FS: FormStyle>(
fs: &FS, fs: &FS,
control: ControlRenderData<FS, Self>, control: Rc<ControlRenderData<FS, Self>>,
value_getter: Option<Signal<String>>, value_getter: Option<Signal<String>>,
) -> View { ) -> View {
fs.hidden(control, value_getter) 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 FieldGetter<FD, FDT>: Fn(FD) -> FDT + 'static {}
pub trait FieldSetter<FD, FDT>: Fn(&mut 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 ShowWhenFn<FD: 'static, CX>: Fn(Signal<FD>, Rc<CX>) -> bool + 'static {}
pub trait RenderFn<FS, FD>: pub trait RenderFn<FS, FD: 'static>:
FnOnce(&FS, RwSignal<FD>) -> (View, Option<Box<dyn ValidationCb>>) + '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> 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, 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<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 impl<FS, FD: 'static, F> RenderFn<FS, FD> for F where
F: FnOnce(&FS, RwSignal<FD>) -> (View, Option<Box<dyn ValidationCb>>) + 'static 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. /// Builds the control, returning the [`View`] that was built.
fn build_control<FS: FormStyle>( fn build_control<FS: FormStyle>(
fs: &FS, fs: &FS,
control: ControlRenderData<FS, Self>, control: Rc<ControlRenderData<FS, Self>>,
value_getter: Option<Signal<String>>, value_getter: Option<Signal<String>>,
) -> View; ) -> View;
} }
@ -64,9 +64,9 @@ pub trait ControlData: 'static {
/// Builds the control, returning the [`View`] that was built. /// Builds the control, returning the [`View`] that was built.
fn build_control<FS: FormStyle>( fn build_control<FS: FormStyle>(
fs: &FS, fs: &FS,
control: ControlRenderData<FS, Self>, control: Rc<ControlRenderData<FS, Self>>,
value_getter: Signal<Self::ReturnType>, value_getter: Signal<Self::ReturnType>,
value_setter: Box<dyn Fn(Self::ReturnType)>, value_setter: Rc<dyn Fn(Self::ReturnType)>,
validation_state: Signal<Result<(), String>>, validation_state: Signal<Result<(), String>>,
) -> View; ) -> View;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,7 @@
mod grid_form; mod grid_form;
use std::rc::Rc;
use crate::{ use crate::{
controls::{ controls::{
button::ButtonData, checkbox::CheckboxData, heading::HeadingData, hidden::HiddenData, 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 /// Do NOT wrap it in an actual `form` element; any
/// wrapping should be done with `div` or similar elements. /// wrapping should be done with `div` or similar elements.
fn form_frame(&self, form: ControlRenderData<Self, View>) -> View; 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( fn hidden(
&self, &self,
control: ControlRenderData<Self, HiddenData>, control: Rc<ControlRenderData<Self, HiddenData>>,
value_getter: Option<Signal<String>>, value_getter: Option<Signal<String>>,
) -> View; ) -> View;
fn text_input( fn text_input(
&self, &self,
control: ControlRenderData<Self, TextInputData>, control: Rc<ControlRenderData<Self, TextInputData>>,
value_getter: Signal<<TextInputData as ControlData>::ReturnType>, 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>>, validation_state: Signal<Result<(), String>>,
) -> View; ) -> View;
fn text_area( fn text_area(
&self, &self,
control: ControlRenderData<Self, TextAreaData>, control: Rc<ControlRenderData<Self, TextAreaData>>,
value_getter: Signal<<TextAreaData as ControlData>::ReturnType>, 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>>, validation_state: Signal<Result<(), String>>,
) -> View; ) -> View;
fn radio_buttons( fn radio_buttons(
&self, &self,
control: ControlRenderData<Self, RadioButtonsData>, control: Rc<ControlRenderData<Self, RadioButtonsData>>,
value_getter: Signal<<RadioButtonsData as ControlData>::ReturnType>, 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>>, validation_state: Signal<Result<(), String>>,
) -> View; ) -> View;
fn select( fn select(
&self, &self,
control: ControlRenderData<Self, SelectData>, control: Rc<ControlRenderData<Self, SelectData>>,
value_getter: Signal<<SelectData as ControlData>::ReturnType>, 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>>, validation_state: Signal<Result<(), String>>,
) -> View; ) -> View;
fn button<FD: FormToolData>( fn button<FD: FormToolData>(
&self, &self,
control: ControlRenderData<Self, ButtonData<FD>>, control: Rc<ControlRenderData<Self, ButtonData<FD>>>,
data_signal: RwSignal<FD>, data_signal: RwSignal<FD>,
) -> View; ) -> View;
fn checkbox( fn checkbox(
&self, &self,
control: ControlRenderData<Self, CheckboxData>, control: Rc<ControlRenderData<Self, CheckboxData>>,
value_getter: Signal<<CheckboxData as ControlData>::ReturnType>, 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; ) -> View;
fn stepper( fn stepper(
&self, &self,
control: ControlRenderData<Self, StepperData>, control: Rc<ControlRenderData<Self, StepperData>>,
value_getter: Signal<<StepperData as ControlData>::ReturnType>, 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>>, validation_state: Signal<Result<(), String>>,
) -> View; ) -> View;
fn output( fn output(
&self, &self,
control: ControlRenderData<Self, OutputData>, control: Rc<ControlRenderData<Self, OutputData>>,
value_getter: Option<Signal<String>>, value_getter: Option<Signal<String>>,
) -> View; ) -> View;
fn slider( fn slider(
&self, &self,
control: ControlRenderData<Self, SliderData>, control: Rc<ControlRenderData<Self, SliderData>>,
value_getter: Signal<<SliderData as ControlData>::ReturnType>, 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>>, validation_state: Signal<Result<(), String>>,
) -> View; ) -> 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 custom_component(&self, view: View) -> View;
fn group(&self, group: ControlRenderData<Self, View>) -> View; fn group(&self, group: Rc<ControlRenderData<Self, View>>) -> View;
fn spacer(&self, control: ControlRenderData<Self, SpacerData>) -> View; fn spacer(&self, control: Rc<ControlRenderData<Self, SpacerData>>) -> View;
} }