generated from mitchell/rust_template
vanity controls can now have optional getters
This commit is contained in:
parent
749ccc272b
commit
9b4bbfdb74
@ -1,6 +1,6 @@
|
|||||||
use super::{ControlRenderData, VanityControlBuilder, VanityControlData};
|
use super::{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::{Signal, View};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||||
pub struct GroupData {
|
pub struct GroupData {
|
||||||
@ -8,7 +8,11 @@ pub struct GroupData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl VanityControlData for GroupData {
|
impl VanityControlData for GroupData {
|
||||||
fn build_control<FS: FormStyle>(fs: &FS, control: ControlRenderData<FS, Self>) -> View {
|
fn build_control<FS: FormStyle>(
|
||||||
|
fs: &FS,
|
||||||
|
control: ControlRenderData<FS, Self>,
|
||||||
|
_value_getter: Option<Signal<String>>,
|
||||||
|
) -> View {
|
||||||
fs.group(control)
|
fs.group(control)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -16,13 +20,15 @@ impl VanityControlData for GroupData {
|
|||||||
impl<FD: FormToolData, FS: FormStyle> FormBuilder<FD, FS> {
|
impl<FD: FormToolData, FS: FormStyle> FormBuilder<FD, FS> {
|
||||||
pub fn group(
|
pub fn group(
|
||||||
self,
|
self,
|
||||||
builder: impl Fn(VanityControlBuilder<FS, GroupData>) -> VanityControlBuilder<FS, GroupData>,
|
builder: impl Fn(
|
||||||
|
VanityControlBuilder<FD, FS, GroupData>,
|
||||||
|
) -> VanityControlBuilder<FD, FS, GroupData>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
self.new_vanity(builder)
|
self.new_vanity(builder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<FS: FormStyle> VanityControlBuilder<FS, GroupData> {
|
impl<FD: FormToolData, FS: FormStyle> VanityControlBuilder<FD, FS, GroupData> {
|
||||||
pub fn title(mut self, title: impl ToString) -> Self {
|
pub fn title(mut self, title: impl ToString) -> Self {
|
||||||
self.data.title = Some(title.to_string());
|
self.data.title = Some(title.to_string());
|
||||||
self
|
self
|
||||||
|
|||||||
@ -8,21 +8,28 @@ pub struct HeadingData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl VanityControlData for HeadingData {
|
impl VanityControlData for HeadingData {
|
||||||
fn build_control<FS: FormStyle>(fs: &FS, control: ControlRenderData<FS, Self>) -> View {
|
fn build_control<FS: FormStyle>(
|
||||||
|
fs: &FS,
|
||||||
|
control: ControlRenderData<FS, Self>,
|
||||||
|
_value_getter: Option<leptos::prelude::Signal<String>>,
|
||||||
|
) -> View {
|
||||||
fs.heading(control)
|
fs.heading(control)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO: impl GetterVanityControl
|
||||||
|
|
||||||
impl<FD: FormToolData, FS: FormStyle> FormBuilder<FD, FS> {
|
impl<FD: FormToolData, FS: FormStyle> FormBuilder<FD, FS> {
|
||||||
pub fn heading(
|
pub fn heading(
|
||||||
self,
|
self,
|
||||||
builder: impl Fn(VanityControlBuilder<FS, HeadingData>) -> VanityControlBuilder<FS, HeadingData>,
|
builder: impl Fn(
|
||||||
|
VanityControlBuilder<FD, FS, HeadingData>,
|
||||||
|
) -> VanityControlBuilder<FD, FS, HeadingData>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
self.new_vanity(builder)
|
self.new_vanity(builder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<FS: FormStyle> VanityControlBuilder<FS, HeadingData> {
|
impl<FD: FormToolData, FS: FormStyle> VanityControlBuilder<FD, FS, HeadingData> {
|
||||||
pub fn title(mut self, title: impl ToString) -> Self {
|
pub fn title(mut self, title: impl ToString) -> Self {
|
||||||
self.data.title = title.to_string();
|
self.data.title = title.to_string();
|
||||||
self
|
self
|
||||||
|
|||||||
@ -41,8 +41,13 @@ impl<FS, FD, F> RenderFn<FS, FD> for F where
|
|||||||
/// A trait for the data needed to render an read-only control.
|
/// A trait for the data needed to render an read-only control.
|
||||||
pub trait VanityControlData: 'static {
|
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>(fs: &FS, control: ControlRenderData<FS, Self>) -> View;
|
fn build_control<FS: FormStyle>(
|
||||||
|
fs: &FS,
|
||||||
|
control: ControlRenderData<FS, Self>,
|
||||||
|
value_getter: Option<Signal<String>>,
|
||||||
|
) -> View;
|
||||||
}
|
}
|
||||||
|
pub trait GetterVanityControlData: VanityControlData {}
|
||||||
|
|
||||||
/// A trait for the data needed to render an interactive control.
|
/// A trait for the data needed to render an interactive control.
|
||||||
pub trait ControlData: 'static {
|
pub trait ControlData: 'static {
|
||||||
@ -66,29 +71,51 @@ pub struct ControlRenderData<FS: FormStyle + ?Sized, C: ?Sized> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The data needed to render a read-only control of type `C`.
|
/// The data needed to render a read-only control of type `C`.
|
||||||
pub struct VanityControlBuilder<FS: FormStyle, C: VanityControlData> {
|
pub struct VanityControlBuilder<FD: FormToolData, FS: FormStyle, C: VanityControlData> {
|
||||||
pub(crate) style_attributes: Vec<FS::StylingAttributes>,
|
pub(crate) style_attributes: Vec<FS::StylingAttributes>,
|
||||||
pub(crate) data: C,
|
pub(crate) data: C,
|
||||||
|
pub(crate) getter: Option<Rc<dyn FieldGetter<FD, String>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<FS: FormStyle, C: VanityControlData> VanityControlBuilder<FS, C> {
|
pub(crate) struct BuiltVanityControlData<FD: FormToolData, FS: FormStyle, C: VanityControlData> {
|
||||||
|
pub(crate) render_data: ControlRenderData<FS, C>,
|
||||||
|
pub(crate) getter: Option<Rc<dyn FieldGetter<FD, String>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<FD: FormToolData, FS: FormStyle, C: VanityControlData> VanityControlBuilder<FD, FS, C> {
|
||||||
/// Creates a new [`VanityControlBuilder`] with the given [`VanityControlData`].
|
/// Creates a new [`VanityControlBuilder`] with the given [`VanityControlData`].
|
||||||
pub(crate) fn new(data: C) -> Self {
|
pub(crate) fn new(data: C) -> Self {
|
||||||
VanityControlBuilder {
|
VanityControlBuilder {
|
||||||
data,
|
data,
|
||||||
style_attributes: Vec::new(),
|
style_attributes: Vec::new(),
|
||||||
|
getter: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds the builder into the data needed to render the control.
|
/// Builds the builder into the data needed to render the control.
|
||||||
pub(crate) fn build(self) -> ControlRenderData<FS, C> {
|
pub(crate) fn build(self) -> BuiltVanityControlData<FD, FS, C> {
|
||||||
ControlRenderData {
|
BuiltVanityControlData {
|
||||||
|
render_data: ControlRenderData {
|
||||||
data: Box::new(self.data),
|
data: Box::new(self.data),
|
||||||
style: self.style_attributes,
|
style: self.style_attributes,
|
||||||
|
},
|
||||||
|
getter: self.getter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<FD: FormToolData, FS: FormStyle, C: GetterVanityControlData> VanityControlBuilder<FD, FS, C> {
|
||||||
|
/// Sets the getter function.
|
||||||
|
///
|
||||||
|
/// This function can get a string from the form data to be displayed
|
||||||
|
///
|
||||||
|
/// Setting this getter field is NOT required for vanity controls like this one.
|
||||||
|
pub fn getter(mut self, getter: impl FieldGetter<FD, String>) -> Self {
|
||||||
|
self.getter = Some(Rc::new(getter));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The possibilities for errors when building a control.
|
/// The possibilities for errors when building a control.
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
|
||||||
pub enum ControlBuildError {
|
pub enum ControlBuildError {
|
||||||
|
|||||||
@ -1,32 +1,29 @@
|
|||||||
use leptos::{Signal, View};
|
use leptos::{Signal, View};
|
||||||
|
|
||||||
use super::{ControlBuilder, ControlData, ControlRenderData};
|
use super::{ControlRenderData, GetterVanityControlData, VanityControlBuilder, VanityControlData};
|
||||||
use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
|
use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||||
pub struct OutputData;
|
pub struct OutputData;
|
||||||
|
|
||||||
impl ControlData for OutputData {
|
impl VanityControlData for OutputData {
|
||||||
type ReturnType = String;
|
|
||||||
|
|
||||||
fn build_control<FS: FormStyle>(
|
fn build_control<FS: FormStyle>(
|
||||||
fs: &FS,
|
fs: &FS,
|
||||||
control: ControlRenderData<FS, Self>,
|
control: ControlRenderData<FS, Self>,
|
||||||
value_getter: Signal<Self::ReturnType>,
|
value_getter: Option<Signal<String>>,
|
||||||
_value_setter: Box<dyn Fn(Self::ReturnType)>,
|
|
||||||
_validation_state: Signal<Result<(), String>>,
|
|
||||||
) -> View {
|
) -> View {
|
||||||
fs.output(control, value_getter)
|
fs.output(control, value_getter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl GetterVanityControlData for OutputData {}
|
||||||
|
|
||||||
impl<FD: FormToolData, FS: FormStyle> FormBuilder<FD, FS> {
|
impl<FD: FormToolData, FS: FormStyle> FormBuilder<FD, FS> {
|
||||||
pub fn output<FDT: Clone + PartialEq + 'static>(
|
pub fn output(
|
||||||
self,
|
self,
|
||||||
builder: impl Fn(
|
builder: impl Fn(
|
||||||
ControlBuilder<FD, FS, OutputData, FDT>,
|
VanityControlBuilder<FD, FS, OutputData>,
|
||||||
) -> ControlBuilder<FD, FS, OutputData, FDT>,
|
) -> VanityControlBuilder<FD, FS, OutputData>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
self.new_control(builder)
|
self.new_vanity(builder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,11 @@ pub struct SubmitData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl VanityControlData for SubmitData {
|
impl VanityControlData for SubmitData {
|
||||||
fn build_control<FS: FormStyle>(fs: &FS, control: ControlRenderData<FS, Self>) -> View {
|
fn build_control<FS: FormStyle>(
|
||||||
|
fs: &FS,
|
||||||
|
control: ControlRenderData<FS, Self>,
|
||||||
|
_value_getter: Option<leptos::prelude::Signal<String>>,
|
||||||
|
) -> View {
|
||||||
fs.submit(control)
|
fs.submit(control)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -17,13 +21,15 @@ impl VanityControlData for SubmitData {
|
|||||||
impl<FD: FormToolData, FS: FormStyle> FormBuilder<FD, FS> {
|
impl<FD: FormToolData, FS: FormStyle> FormBuilder<FD, FS> {
|
||||||
pub fn submit(
|
pub fn submit(
|
||||||
self,
|
self,
|
||||||
builder: impl Fn(VanityControlBuilder<FS, SubmitData>) -> VanityControlBuilder<FS, SubmitData>,
|
builder: impl Fn(
|
||||||
|
VanityControlBuilder<FD, FS, SubmitData>,
|
||||||
|
) -> VanityControlBuilder<FD, FS, SubmitData>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
self.new_vanity(builder)
|
self.new_vanity(builder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<FS: FormStyle> VanityControlBuilder<FS, SubmitData> {
|
impl<FD: FormToolData, FS: FormStyle> VanityControlBuilder<FD, FS, SubmitData> {
|
||||||
pub fn text(mut self, text: impl ToString) -> Self {
|
pub fn text(mut self, text: impl ToString) -> Self {
|
||||||
self.data.text = text.to_string();
|
self.data.text = text.to_string();
|
||||||
self
|
self
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
controls::{
|
controls::{
|
||||||
BuiltControlData, ControlBuilder, ControlData, FieldGetter, FieldSetter, ParseFn, RenderFn,
|
BuiltControlData, BuiltVanityControlData, ControlBuilder, ControlData, FieldGetter,
|
||||||
UnparseFn, ValidationCb, ValidationFn, VanityControlBuilder, VanityControlData,
|
FieldSetter, ParseFn, RenderFn, UnparseFn, ValidationCb, ValidationFn,
|
||||||
|
VanityControlBuilder, VanityControlData,
|
||||||
},
|
},
|
||||||
form::{Form, FormToolData, Validator},
|
form::{Form, FormToolData, Validator},
|
||||||
styles::FormStyle,
|
styles::FormStyle,
|
||||||
@ -43,7 +44,7 @@ impl<FD: FormToolData, FS: FormStyle> FormBuilder<FD, FS> {
|
|||||||
|
|
||||||
pub(crate) fn new_vanity<C: VanityControlData + Default>(
|
pub(crate) fn new_vanity<C: VanityControlData + Default>(
|
||||||
mut self,
|
mut self,
|
||||||
builder: impl Fn(VanityControlBuilder<FS, C>) -> VanityControlBuilder<FS, C>,
|
builder: impl Fn(VanityControlBuilder<FD, FS, C>) -> VanityControlBuilder<FD, FS, C>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let vanity_builder = VanityControlBuilder::new(C::default());
|
let vanity_builder = VanityControlBuilder::new(C::default());
|
||||||
let control = builder(vanity_builder);
|
let control = builder(vanity_builder);
|
||||||
@ -64,12 +65,16 @@ impl<FD: FormToolData, FS: FormStyle> FormBuilder<FD, FS> {
|
|||||||
// TODO: test this from a user context. A user adding a custom defined component.
|
// TODO: test this from a user context. A user adding a custom defined component.
|
||||||
pub fn add_vanity<C: VanityControlData>(
|
pub fn add_vanity<C: VanityControlData>(
|
||||||
&mut self,
|
&mut self,
|
||||||
vanity_control: VanityControlBuilder<FS, C>,
|
vanity_control: VanityControlBuilder<FD, FS, C>,
|
||||||
) {
|
) {
|
||||||
let render_data = vanity_control.build();
|
let BuiltVanityControlData {
|
||||||
|
render_data,
|
||||||
|
getter,
|
||||||
|
} = vanity_control.build();
|
||||||
|
|
||||||
let render_fn = move |fs: &FS, _| {
|
let render_fn = move |fs: &FS, fd: RwSignal<FD>| {
|
||||||
let view = VanityControlData::build_control(fs, render_data);
|
let value_getter = getter.map(|getter| (move || getter(fd.get())).into_signal());
|
||||||
|
let view = VanityControlData::build_control(fs, render_data, value_getter);
|
||||||
(view, None)
|
(view, None)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -18,13 +18,11 @@ impl FormStyle for GridFormStyle {
|
|||||||
type StylingAttributes = GridFormStylingAttributes;
|
type StylingAttributes = GridFormStylingAttributes;
|
||||||
|
|
||||||
fn form_frame(&self, children: View) -> View {
|
fn form_frame(&self, children: View) -> View {
|
||||||
view! { <div class="form_grid">{children}</div> }
|
view! { <div class="form_grid">{children}</div> }.into_view()
|
||||||
.into_view()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn heading(&self, control: ControlRenderData<Self, HeadingData>) -> View {
|
fn heading(&self, control: ControlRenderData<Self, HeadingData>) -> View {
|
||||||
view! { <h2 class="form_heading">{&control.data.title}</h2> }
|
view! { <h2 class="form_heading">{&control.data.title}</h2> }.into_view()
|
||||||
.into_view()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn text_input(
|
fn text_input(
|
||||||
@ -153,8 +151,7 @@ impl FormStyle for GridFormStyle {
|
|||||||
_control: ControlRenderData<Self, HiddenData>,
|
_control: ControlRenderData<Self, HiddenData>,
|
||||||
value_getter: Signal<String>,
|
value_getter: Signal<String>,
|
||||||
) -> View {
|
) -> View {
|
||||||
view! { <input prop:value=value_getter style="visibility: hidden"/> }
|
view! { <input prop:value=value_getter style="visibility: hidden"/> }.into_view()
|
||||||
.into_view()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn radio_buttons(
|
fn radio_buttons(
|
||||||
@ -298,16 +295,16 @@ impl FormStyle for GridFormStyle {
|
|||||||
class="form_input"
|
class="form_input"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}.into_view()
|
}
|
||||||
|
.into_view()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn output(
|
fn output(
|
||||||
&self,
|
&self,
|
||||||
_control: ControlRenderData<Self, OutputData>,
|
_control: ControlRenderData<Self, OutputData>,
|
||||||
value_getter: Signal<String>,
|
value_getter: Option<Signal<String>>,
|
||||||
) -> View {
|
) -> View {
|
||||||
view! { <div>{move || value_getter.get()}</div> }
|
view! { <div>{move || value_getter.map(|g| g.get())}</div> }.into_view()
|
||||||
.into_view()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn slider(
|
fn slider(
|
||||||
|
|||||||
@ -70,7 +70,7 @@ pub trait FormStyle: Default + 'static {
|
|||||||
fn output(
|
fn output(
|
||||||
&self,
|
&self,
|
||||||
control: ControlRenderData<Self, OutputData>,
|
control: ControlRenderData<Self, OutputData>,
|
||||||
value_getter: Signal<String>,
|
value_getter: Option<Signal<String>>,
|
||||||
) -> View;
|
) -> View;
|
||||||
fn slider(
|
fn slider(
|
||||||
&self,
|
&self,
|
||||||
|
|||||||
Reference in New Issue
Block a user