generated from mitchell/rust_template
Conditional Rendering WORKS!
This commit is contained in:
parent
835271cd22
commit
da84bdbb27
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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,
|
||||
value_getter,
|
||||
value_setter,
|
||||
validation_signal.into(),
|
||||
);
|
||||
let view = move || {
|
||||
C::build_control(
|
||||
&*fs,
|
||||
render_data.clone(),
|
||||
value_getter,
|
||||
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 {
|
||||
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user