generated from mitchell/rust_template
Various improvements #26
@ -1,48 +1,57 @@
|
||||
use super::{ControlRenderData, VanityControlBuilder, VanityControlData};
|
||||
use super::ControlRenderData;
|
||||
use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
|
||||
use leptos::{RwSignal, Signal, View};
|
||||
use leptos::RwSignal;
|
||||
use std::rc::Rc;
|
||||
use web_sys::MouseEvent;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Default, Clone)]
|
||||
pub struct ButtonData<FD: FormToolData> {
|
||||
pub(crate) text: String,
|
||||
pub(crate) action: Option<Rc<dyn Fn(MouseEvent, &mut FD)>>,
|
||||
|
||||
// this will need to be set before calling the build method
|
||||
pub(crate) fd_signal: RwSignal<FD>,
|
||||
}
|
||||
|
||||
impl<FD: FormToolData> VanityControlData for ButtonData<FD> {
|
||||
fn build_control<FS: FormStyle>(
|
||||
fs: &FS,
|
||||
control: ControlRenderData<FS, Self>,
|
||||
_value_getter: Option<Signal<String>>,
|
||||
) -> View {
|
||||
fs.button(control)
|
||||
}
|
||||
}
|
||||
|
||||
impl<FD: FormToolData, FS: FormStyle> FormBuilder<FD, FS> {
|
||||
pub fn button(
|
||||
mut self,
|
||||
builder: impl Fn(
|
||||
VanityControlBuilder<FD, FS, ButtonData<FD>>,
|
||||
) -> VanityControlBuilder<FD, FS, ButtonData<FD>>,
|
||||
builder: impl Fn(ButtonBuilder<FD, FS>) -> ButtonBuilder<FD, FS>,
|
||||
) -> Self {
|
||||
let data = ButtonData {
|
||||
text: String::default(),
|
||||
action: None,
|
||||
fd_signal: self.fd,
|
||||
let button_builder = ButtonBuilder::new();
|
||||
let control = builder(button_builder);
|
||||
|
||||
let render_data = ControlRenderData {
|
||||
data: Box::new(control.data),
|
||||
styles: control.styles,
|
||||
};
|
||||
let vanity_builder = VanityControlBuilder::new(data);
|
||||
let control = builder(vanity_builder);
|
||||
self.add_vanity(control);
|
||||
|
||||
let render_fn = move |fs: &FS, fd: RwSignal<FD>| {
|
||||
let view = fs.button(render_data, fd);
|
||||
(view, None)
|
||||
};
|
||||
self.render_fns.push(Box::new(render_fn));
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<FD: FormToolData, FS: FormStyle> VanityControlBuilder<FD, FS, ButtonData<FD>> {
|
||||
#[derive(Clone)]
|
||||
pub struct ButtonBuilder<FD: FormToolData, FS: FormStyle> {
|
||||
pub(crate) styles: Vec<FS::StylingAttributes>,
|
||||
pub(crate) data: ButtonData<FD>,
|
||||
}
|
||||
|
||||
impl<FD: FormToolData, FS: FormStyle> ButtonBuilder<FD, FS> {
|
||||
fn new() -> Self {
|
||||
ButtonBuilder {
|
||||
styles: Vec::default(),
|
||||
data: ButtonData::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn style(mut self, style: FS::StylingAttributes) -> Self {
|
||||
self.styles.push(style);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn text(mut self, text: impl ToString) -> Self {
|
||||
self.data.text = text.to_string();
|
||||
self
|
||||
|
||||
@ -71,7 +71,7 @@ pub trait ValidatedControlData: ControlData {}
|
||||
/// The data needed to render a interactive control of type `C`.
|
||||
pub struct ControlRenderData<FS: FormStyle + ?Sized, C: ?Sized> {
|
||||
pub data: Box<C>,
|
||||
pub style: Vec<FS::StylingAttributes>,
|
||||
pub styles: Vec<FS::StylingAttributes>,
|
||||
}
|
||||
|
||||
/// The data needed to render a read-only control of type `C`.
|
||||
@ -101,7 +101,7 @@ impl<FD: FormToolData, FS: FormStyle, C: VanityControlData> VanityControlBuilder
|
||||
BuiltVanityControlData {
|
||||
render_data: ControlRenderData {
|
||||
data: Box::new(self.data),
|
||||
style: self.style_attributes,
|
||||
styles: self.style_attributes,
|
||||
},
|
||||
getter: self.getter,
|
||||
}
|
||||
@ -209,7 +209,7 @@ impl<FD: FormToolData, FS: FormStyle, C: ControlData, FDT> ControlBuilder<FD, FS
|
||||
Ok(BuiltControlData {
|
||||
render_data: ControlRenderData {
|
||||
data: Box::new(self.data),
|
||||
style: self.style_attributes,
|
||||
styles: self.style_attributes,
|
||||
},
|
||||
getter,
|
||||
setter,
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
use leptos::{Signal, View};
|
||||
|
||||
use super::{ControlBuilder, ControlData, ControlRenderData, ValidatedControlData};
|
||||
use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
|
||||
use leptos::{Signal, View};
|
||||
|
||||
// TODO: have an option to have a display string and a value string in the options field
|
||||
|
||||
@ -9,7 +8,7 @@ use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
|
||||
pub struct SelectData {
|
||||
pub(crate) name: String,
|
||||
pub(crate) label: Option<String>,
|
||||
pub(crate) options: Vec<String>,
|
||||
pub(crate) options: Vec<(String, String)>,
|
||||
}
|
||||
|
||||
impl ControlData for SelectData {
|
||||
@ -50,13 +49,36 @@ impl<FD: FormToolData, FS: FormStyle, FDT> ControlBuilder<FD, FS, SelectData, FD
|
||||
}
|
||||
|
||||
pub fn with_option(mut self, option: impl ToString) -> Self {
|
||||
self.data.options.push(option.to_string());
|
||||
self.data
|
||||
.options
|
||||
.push((option.to_string(), option.to_string()));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_option_valued(mut self, display: impl ToString, value: impl ToString) -> Self {
|
||||
self.data
|
||||
.options
|
||||
.push((display.to_string(), value.to_string()));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_options(mut self, options: impl Iterator<Item = impl ToString>) -> Self {
|
||||
for option in options {
|
||||
self.data.options.push(option.to_string());
|
||||
self.data
|
||||
.options
|
||||
.push((option.to_string(), option.to_string()));
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_options_valued(
|
||||
mut self,
|
||||
options: impl Iterator<Item = (impl ToString, impl ToString)>,
|
||||
) -> Self {
|
||||
for option in options {
|
||||
self.data
|
||||
.options
|
||||
.push((option.0.to_string(), option.1.to_string()));
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
use super::FormStyle;
|
||||
use crate::controls::{
|
||||
checkbox::CheckboxData, heading::HeadingData, hidden::HiddenData, output::OutputData,
|
||||
select::SelectData, spacer::SpacerData, submit::SubmitData, text_area::TextAreaData,
|
||||
text_input::TextInputData, ControlData, ControlRenderData,
|
||||
use crate::{
|
||||
controls::{
|
||||
button::ButtonData, checkbox::CheckboxData, heading::HeadingData, hidden::HiddenData,
|
||||
output::OutputData, select::SelectData, spacer::SpacerData, submit::SubmitData,
|
||||
text_area::TextAreaData, text_input::TextInputData, ControlData, ControlRenderData,
|
||||
},
|
||||
FormToolData,
|
||||
};
|
||||
use leptos::*;
|
||||
use std::rc::Rc;
|
||||
@ -35,7 +38,7 @@ impl FormStyle for GridFormStyle {
|
||||
) -> View {
|
||||
// TODO: extract this to a common thing
|
||||
let mut width = 1;
|
||||
for style in control.style {
|
||||
for style in control.styles {
|
||||
match style {
|
||||
GridFormStylingAttributes::Width(w) => width = w,
|
||||
}
|
||||
@ -78,14 +81,10 @@ impl FormStyle for GridFormStyle {
|
||||
.data
|
||||
.options
|
||||
.into_iter()
|
||||
.map(|value| {
|
||||
let cloned_value = value.clone();
|
||||
.map(|(display, value)| {
|
||||
view! {
|
||||
<option
|
||||
value=value.clone()
|
||||
selected=move || {value_getter.get() == *cloned_value}
|
||||
>
|
||||
{value.clone()}
|
||||
<option value=value.clone() selected=move || { value_getter.get() == *value }>
|
||||
{display.clone()}
|
||||
</option>
|
||||
}
|
||||
})
|
||||
@ -112,9 +111,7 @@ impl FormStyle for GridFormStyle {
|
||||
}
|
||||
|
||||
fn submit(&self, control: ControlRenderData<Self, SubmitData>) -> View {
|
||||
view! {
|
||||
<input type="submit" value=control.data.text class="form_submit"/>
|
||||
}
|
||||
view! { <input type="submit" value=control.data.text class="form_submit"/> }
|
||||
.into_view()
|
||||
}
|
||||
|
||||
@ -137,7 +134,8 @@ impl FormStyle for GridFormStyle {
|
||||
on:change=move |ev| {
|
||||
value_setter(event_target_value(&ev));
|
||||
}
|
||||
></textarea>
|
||||
>
|
||||
</textarea>
|
||||
|
||||
</div>
|
||||
}
|
||||
@ -168,7 +166,7 @@ impl FormStyle for GridFormStyle {
|
||||
validation_state: Signal<Result<(), String>>,
|
||||
) -> View {
|
||||
let mut width = 1;
|
||||
for style in control.style {
|
||||
for style in control.styles {
|
||||
match style {
|
||||
GridFormStylingAttributes::Width(w) => width = w,
|
||||
}
|
||||
@ -198,6 +196,7 @@ impl FormStyle for GridFormStyle {
|
||||
}
|
||||
}
|
||||
/>
|
||||
|
||||
<label for=&o>{&o}</label>
|
||||
<br/>
|
||||
}
|
||||
@ -230,7 +229,7 @@ impl FormStyle for GridFormStyle {
|
||||
value_setter: Box<dyn Fn(<CheckboxData as ControlData>::ReturnType)>,
|
||||
) -> View {
|
||||
let mut width = 1;
|
||||
for style in control.style {
|
||||
for style in control.styles {
|
||||
match style {
|
||||
GridFormStylingAttributes::Width(w) => width = w,
|
||||
}
|
||||
@ -270,7 +269,7 @@ impl FormStyle for GridFormStyle {
|
||||
validation_state: Signal<Result<(), String>>,
|
||||
) -> View {
|
||||
let mut width = 1;
|
||||
for style in control.style {
|
||||
for style in control.styles {
|
||||
match style {
|
||||
GridFormStylingAttributes::Width(w) => width = w,
|
||||
}
|
||||
@ -317,7 +316,7 @@ impl FormStyle for GridFormStyle {
|
||||
validation_state: Signal<Result<(), String>>,
|
||||
) -> View {
|
||||
let mut width = 1;
|
||||
for style in control.style {
|
||||
for style in control.styles {
|
||||
match style {
|
||||
GridFormStylingAttributes::Width(w) => width = w,
|
||||
}
|
||||
@ -352,27 +351,32 @@ impl FormStyle for GridFormStyle {
|
||||
.into_view()
|
||||
}
|
||||
|
||||
fn button<FD: crate::FormToolData>(
|
||||
fn button<FD: FormToolData>(
|
||||
&self,
|
||||
control: ControlRenderData<Self, crate::controls::button::ButtonData<FD>>,
|
||||
control: ControlRenderData<Self, ButtonData<FD>>,
|
||||
data_signal: RwSignal<FD>,
|
||||
) -> View {
|
||||
let mut width = 1;
|
||||
for style in control.style {
|
||||
for style in control.styles {
|
||||
match style {
|
||||
GridFormStylingAttributes::Width(w) => width = w,
|
||||
}
|
||||
}
|
||||
|
||||
let action = control.data.action.clone();
|
||||
let signal = control.data.fd_signal.clone();
|
||||
let on_click = move |ev: MouseEvent| {
|
||||
if let Some(action) = action.clone() {
|
||||
signal.update(|fd| action(ev, fd));
|
||||
data_signal.update(|fd| action(ev, fd));
|
||||
}
|
||||
};
|
||||
|
||||
view! {
|
||||
<button type="button" class="form_button" on:click=on_click style:grid-column=format!("span {}", width)>
|
||||
<button
|
||||
type="button"
|
||||
class="form_button"
|
||||
on:click=on_click
|
||||
style:grid-column=format!("span {}", width)
|
||||
>
|
||||
{control.data.text}
|
||||
</button>
|
||||
}
|
||||
@ -398,15 +402,13 @@ impl FormStyle for GridFormStyle {
|
||||
|
||||
fn spacer(&self, control: ControlRenderData<Self, SpacerData>) -> View {
|
||||
let mut width = 12;
|
||||
for style in control.style {
|
||||
for style in control.styles {
|
||||
match style {
|
||||
GridFormStylingAttributes::Width(w) => width = w,
|
||||
}
|
||||
}
|
||||
|
||||
view! {
|
||||
<div style:grid-column=format!("span {}", width) style:height=control.data.height/>
|
||||
}
|
||||
view! { <div style:grid-column=format!("span {}", width) style:height=control.data.height></div> }
|
||||
.into_view()
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ use crate::{
|
||||
},
|
||||
FormToolData,
|
||||
};
|
||||
use leptos::{Signal, View};
|
||||
use leptos::{RwSignal, Signal, View};
|
||||
|
||||
pub use grid_form::{GridFormStyle, GridFormStylingAttributes};
|
||||
|
||||
@ -58,7 +58,11 @@ pub trait FormStyle: Default + 'static {
|
||||
value_setter: Box<dyn Fn(<SelectData as ControlData>::ReturnType)>,
|
||||
validation_state: Signal<Result<(), String>>,
|
||||
) -> View;
|
||||
fn button<FD: FormToolData>(&self, control: ControlRenderData<Self, ButtonData<FD>>) -> View;
|
||||
fn button<FD: FormToolData>(
|
||||
&self,
|
||||
control: ControlRenderData<Self, ButtonData<FD>>,
|
||||
data_signal: RwSignal<FD>,
|
||||
) -> View;
|
||||
fn checkbox(
|
||||
&self,
|
||||
control: ControlRenderData<Self, CheckboxData>,
|
||||
|
||||
Reference in New Issue
Block a user