generated from mitchell/rust_template
add docs and refactor GFStyle
This commit is contained in:
parent
1dc93d69f4
commit
5f4358277e
@ -9,6 +9,7 @@ use web_sys::MouseEvent;
|
|||||||
|
|
||||||
type ButtonAction<FD> = dyn Fn(MouseEvent, RwSignal<FD>) + 'static;
|
type ButtonAction<FD> = dyn Fn(MouseEvent, RwSignal<FD>) + 'static;
|
||||||
|
|
||||||
|
/// Data used for the button control.
|
||||||
pub struct ButtonData<FD: FormToolData> {
|
pub struct ButtonData<FD: FormToolData> {
|
||||||
pub text: String,
|
pub text: String,
|
||||||
pub action: Option<Rc<ButtonAction<FD>>>,
|
pub action: Option<Rc<ButtonAction<FD>>>,
|
||||||
@ -31,18 +32,21 @@ impl<FD: FormToolData> Clone for ButtonData<FD> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<FD: FormToolData> FormBuilder<FD> {
|
impl<FD: FormToolData> FormBuilder<FD> {
|
||||||
|
/// Builds a button and adds it to the form.
|
||||||
pub fn button(self, builder: impl BuilderFn<ButtonBuilder<FD>>) -> Self {
|
pub fn button(self, builder: impl BuilderFn<ButtonBuilder<FD>>) -> Self {
|
||||||
let button_builder = ButtonBuilder::new();
|
let button_builder = ButtonBuilder::new();
|
||||||
let control = builder(button_builder);
|
let control = builder(button_builder);
|
||||||
self.button_helper(control)
|
self.button_helper(control)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds a button using the form's context and adds it to the form.
|
||||||
pub fn button_cx(self, builder: impl BuilderCxFn<ButtonBuilder<FD>, FD::Context>) -> Self {
|
pub fn button_cx(self, builder: impl BuilderCxFn<ButtonBuilder<FD>, FD::Context>) -> Self {
|
||||||
let button_builder = ButtonBuilder::new();
|
let button_builder = ButtonBuilder::new();
|
||||||
let control = builder(button_builder, self.cx.clone());
|
let control = builder(button_builder, self.cx.clone());
|
||||||
self.button_helper(control)
|
self.button_helper(control)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The common functionality for adding a button.
|
||||||
fn button_helper(mut self, control: ButtonBuilder<FD>) -> Self {
|
fn button_helper(mut self, control: ButtonBuilder<FD>) -> Self {
|
||||||
let render_data = ControlRenderData {
|
let render_data = ControlRenderData {
|
||||||
data: control.data,
|
data: control.data,
|
||||||
@ -74,6 +78,7 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The struct that allows you to specify the attributes of the button.
|
||||||
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>,
|
||||||
@ -81,6 +86,7 @@ pub struct ButtonBuilder<FD: FormToolData> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<FD: FormToolData> ButtonBuilder<FD> {
|
impl<FD: FormToolData> ButtonBuilder<FD> {
|
||||||
|
/// Creates a new [`ButtonBuilder`].
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
ButtonBuilder {
|
ButtonBuilder {
|
||||||
styles: Vec::default(),
|
styles: Vec::default(),
|
||||||
@ -90,8 +96,6 @@ impl<FD: FormToolData> ButtonBuilder<FD> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the function to decide when to render the control.
|
/// Sets the function to decide when to render the control.
|
||||||
///
|
|
||||||
/// Validations for components that are not shown DO NOT run.
|
|
||||||
pub fn show_when(
|
pub fn show_when(
|
||||||
mut self,
|
mut self,
|
||||||
when: impl Fn(Signal<FD>, Rc<FD::Context>) -> bool + 'static,
|
when: impl Fn(Signal<FD>, Rc<FD::Context>) -> bool + 'static,
|
||||||
@ -100,16 +104,19 @@ impl<FD: FormToolData> ButtonBuilder<FD> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a styling attribute to the button.
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the text of the button.
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the action that is preformed when the button is clicked.
|
||||||
pub fn action(mut self, action: impl Fn(MouseEvent, RwSignal<FD>) + 'static) -> Self {
|
pub fn action(mut self, action: impl Fn(MouseEvent, RwSignal<FD>) + 'static) -> Self {
|
||||||
self.data.action = Some(Rc::new(action));
|
self.data.action = Some(Rc::new(action));
|
||||||
self
|
self
|
||||||
|
|||||||
@ -3,6 +3,7 @@ use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
|
|||||||
use leptos::{Signal, View};
|
use leptos::{Signal, View};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
/// Data used for the checkbox control.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||||
pub struct CheckboxData {
|
pub struct CheckboxData {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@ -24,6 +25,7 @@ impl ControlData for CheckboxData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<FD: FormToolData> FormBuilder<FD> {
|
impl<FD: FormToolData> FormBuilder<FD> {
|
||||||
|
/// Builds a checkbox and adds it to the form.
|
||||||
pub fn checkbox<FDT: Clone + PartialEq + 'static>(
|
pub fn checkbox<FDT: Clone + PartialEq + 'static>(
|
||||||
self,
|
self,
|
||||||
builder: impl BuilderFn<ControlBuilder<FD, CheckboxData, FDT>>,
|
builder: impl BuilderFn<ControlBuilder<FD, CheckboxData, FDT>>,
|
||||||
@ -31,6 +33,7 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
self.new_control(builder)
|
self.new_control(builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds a checkbox using the form's context and adds it to the form.
|
||||||
pub fn checkbox_cx<FDT: Clone + PartialEq + 'static>(
|
pub fn checkbox_cx<FDT: Clone + PartialEq + 'static>(
|
||||||
self,
|
self,
|
||||||
builder: impl BuilderCxFn<ControlBuilder<FD, CheckboxData, FDT>, FD::Context>,
|
builder: impl BuilderCxFn<ControlBuilder<FD, CheckboxData, FDT>, FD::Context>,
|
||||||
@ -40,11 +43,20 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<FD: FormToolData, FDT> ControlBuilder<FD, CheckboxData, FDT> {
|
impl<FD: FormToolData, FDT> ControlBuilder<FD, CheckboxData, FDT> {
|
||||||
|
/// Sets the name of the checkbox.
|
||||||
|
///
|
||||||
|
/// This is used for the html element's "name" attribute.
|
||||||
|
/// In forms, the name attribute is the key that the data is sent
|
||||||
|
/// with.
|
||||||
|
///
|
||||||
|
/// For checkbox controls, the value "checked" is sent or no key value
|
||||||
|
/// pair is sent.
|
||||||
pub fn named(mut self, control_name: impl ToString) -> Self {
|
pub fn named(mut self, control_name: impl ToString) -> Self {
|
||||||
self.data.name = control_name.to_string();
|
self.data.name = control_name.to_string();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the text of the checkbox's label.
|
||||||
pub fn labeled(mut self, label: impl ToString) -> Self {
|
pub fn labeled(mut self, label: impl ToString) -> Self {
|
||||||
self.data.label = Some(label.to_string());
|
self.data.label = Some(label.to_string());
|
||||||
self
|
self
|
||||||
|
|||||||
@ -2,6 +2,7 @@ use super::{BuilderCxFn, BuilderFn, ControlBuilder, ControlData};
|
|||||||
use crate::{FormBuilder, FormToolData};
|
use crate::{FormBuilder, FormToolData};
|
||||||
|
|
||||||
impl<FD: FormToolData> FormBuilder<FD> {
|
impl<FD: FormToolData> FormBuilder<FD> {
|
||||||
|
/// Builds a custom component and adds it to the form.
|
||||||
pub fn custom<CC: ControlData, FDT: Clone + PartialEq + 'static>(
|
pub fn custom<CC: ControlData, FDT: Clone + PartialEq + 'static>(
|
||||||
mut self,
|
mut self,
|
||||||
control_data: CC,
|
control_data: CC,
|
||||||
@ -13,6 +14,8 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds a custom component using the form's context and adds it to the
|
||||||
|
/// form.
|
||||||
pub fn custom_cx<CC: ControlData, FDT: Clone + PartialEq + 'static>(
|
pub fn custom_cx<CC: ControlData, FDT: Clone + PartialEq + 'static>(
|
||||||
mut self,
|
mut self,
|
||||||
control_data: CC,
|
control_data: CC,
|
||||||
@ -24,6 +27,8 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds a custom component, starting with the default
|
||||||
|
/// CustomControlData, and adds it to the form.
|
||||||
pub fn custom_default<CC: Default + ControlData, FDT: Clone + PartialEq + 'static>(
|
pub fn custom_default<CC: Default + ControlData, FDT: Clone + PartialEq + 'static>(
|
||||||
self,
|
self,
|
||||||
builder: impl BuilderFn<ControlBuilder<FD, CC, FDT>>,
|
builder: impl BuilderFn<ControlBuilder<FD, CC, FDT>>,
|
||||||
@ -31,6 +36,8 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
self.new_control(builder)
|
self.new_control(builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds a custom component, starting with the default
|
||||||
|
/// CustomControlData using the form's context, and adds it to the form.
|
||||||
pub fn custom_default_cx<CC: Default + ControlData, FDT: Clone + PartialEq + 'static>(
|
pub fn custom_default_cx<CC: Default + ControlData, FDT: Clone + PartialEq + 'static>(
|
||||||
self,
|
self,
|
||||||
builder: impl BuilderCxFn<ControlBuilder<FD, CC, FDT>, FD::Context>,
|
builder: impl BuilderCxFn<ControlBuilder<FD, CC, FDT>, FD::Context>,
|
||||||
|
|||||||
@ -6,6 +6,10 @@ use crate::{form::FormToolData, form_builder::FormBuilder};
|
|||||||
use leptos::{CollectView, RwSignal};
|
use leptos::{CollectView, RwSignal};
|
||||||
|
|
||||||
impl<FD: FormToolData> FormBuilder<FD> {
|
impl<FD: FormToolData> FormBuilder<FD> {
|
||||||
|
/// Creates a form group.
|
||||||
|
///
|
||||||
|
/// This creates a subsection of the form that controls can be added to
|
||||||
|
/// like a normal form.
|
||||||
pub fn group(mut self, builder: impl Fn(FormBuilder<FD>) -> FormBuilder<FD>) -> Self {
|
pub fn group(mut self, builder: impl Fn(FormBuilder<FD>) -> FormBuilder<FD>) -> Self {
|
||||||
let mut group_builder = FormBuilder::new_group(self.cx);
|
let mut group_builder = FormBuilder::new_group(self.cx);
|
||||||
group_builder = builder(group_builder);
|
group_builder = builder(group_builder);
|
||||||
@ -30,6 +34,7 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let view = fs.group(render_data.clone());
|
let view = fs.group(render_data.clone());
|
||||||
|
// TODO: add conditional rendering
|
||||||
|
|
||||||
let validation_cb = move || {
|
let validation_cb = move || {
|
||||||
let mut success = true;
|
let mut success = true;
|
||||||
|
|||||||
@ -3,6 +3,7 @@ use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
|
|||||||
use leptos::View;
|
use leptos::View;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
/// Data used for the heading control.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||||
pub struct HeadingData {
|
pub struct HeadingData {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
@ -19,10 +20,12 @@ impl VanityControlData for HeadingData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<FD: FormToolData> FormBuilder<FD> {
|
impl<FD: FormToolData> FormBuilder<FD> {
|
||||||
|
/// Builds a heading and adds it to the form.
|
||||||
pub fn heading(self, builder: impl BuilderFn<VanityControlBuilder<FD, HeadingData>>) -> Self {
|
pub fn heading(self, builder: impl BuilderFn<VanityControlBuilder<FD, HeadingData>>) -> Self {
|
||||||
self.new_vanity(builder)
|
self.new_vanity(builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds a hehading using the form's context and adds it to the form.
|
||||||
pub fn heading_cx(
|
pub fn heading_cx(
|
||||||
self,
|
self,
|
||||||
builder: impl BuilderCxFn<VanityControlBuilder<FD, HeadingData>, FD::Context>,
|
builder: impl BuilderCxFn<VanityControlBuilder<FD, HeadingData>, FD::Context>,
|
||||||
@ -32,6 +35,7 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<FD: FormToolData> VanityControlBuilder<FD, HeadingData> {
|
impl<FD: FormToolData> VanityControlBuilder<FD, HeadingData> {
|
||||||
|
/// Sets the title of this heading.
|
||||||
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
|
||||||
|
|||||||
@ -6,6 +6,7 @@ use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
|
|||||||
use leptos::{Signal, View};
|
use leptos::{Signal, View};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
/// Data used for the hidden control.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||||
pub struct HiddenData {
|
pub struct HiddenData {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@ -23,10 +24,19 @@ impl VanityControlData for HiddenData {
|
|||||||
impl GetterVanityControlData for HiddenData {}
|
impl GetterVanityControlData for HiddenData {}
|
||||||
|
|
||||||
impl<FD: FormToolData> FormBuilder<FD> {
|
impl<FD: FormToolData> FormBuilder<FD> {
|
||||||
|
/// Builds a hidden form control and adds it to the form.
|
||||||
|
///
|
||||||
|
/// This will be an input in the html form allowing you to insert some
|
||||||
|
/// data the you might not want the user modifying.
|
||||||
pub fn hidden(self, builder: impl BuilderFn<VanityControlBuilder<FD, HiddenData>>) -> Self {
|
pub fn hidden(self, builder: impl BuilderFn<VanityControlBuilder<FD, HiddenData>>) -> Self {
|
||||||
self.new_vanity(builder)
|
self.new_vanity(builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds a hidden form control using the form's context and adds it to
|
||||||
|
/// the form.
|
||||||
|
///
|
||||||
|
/// This will be an input in the html form allowing you to insert some
|
||||||
|
/// data the you might not want the user modifying.
|
||||||
pub fn hidden_cx(
|
pub fn hidden_cx(
|
||||||
self,
|
self,
|
||||||
builder: impl BuilderCxFn<VanityControlBuilder<FD, HiddenData>, FD::Context>,
|
builder: impl BuilderCxFn<VanityControlBuilder<FD, HiddenData>, FD::Context>,
|
||||||
@ -36,6 +46,11 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<FD: FormToolData> VanityControlBuilder<FD, HiddenData> {
|
impl<FD: FormToolData> VanityControlBuilder<FD, HiddenData> {
|
||||||
|
/// Sets the name of the hidden control.
|
||||||
|
///
|
||||||
|
/// This is used for the html element's "name" attribute.
|
||||||
|
/// In forms, the name attribute is the key that the data is sent
|
||||||
|
/// with.
|
||||||
pub fn named(mut self, control_name: impl ToString) -> Self {
|
pub fn named(mut self, control_name: impl ToString) -> Self {
|
||||||
self.data.name = control_name.to_string();
|
self.data.name = control_name.to_string();
|
||||||
self
|
self
|
||||||
|
|||||||
@ -6,6 +6,7 @@ use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
|
|||||||
use leptos::{Signal, View};
|
use leptos::{Signal, View};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
/// Data used for the output control.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||||
pub struct OutputData;
|
pub struct OutputData;
|
||||||
|
|
||||||
@ -21,10 +22,19 @@ impl VanityControlData for OutputData {
|
|||||||
impl GetterVanityControlData for OutputData {}
|
impl GetterVanityControlData for OutputData {}
|
||||||
|
|
||||||
impl<FD: FormToolData> FormBuilder<FD> {
|
impl<FD: FormToolData> FormBuilder<FD> {
|
||||||
|
/// Builds an output form control and adds it to the form.
|
||||||
|
///
|
||||||
|
/// This control allows you to output some text to the user based on the
|
||||||
|
/// form data.
|
||||||
pub fn output(self, builder: impl BuilderFn<VanityControlBuilder<FD, OutputData>>) -> Self {
|
pub fn output(self, builder: impl BuilderFn<VanityControlBuilder<FD, OutputData>>) -> Self {
|
||||||
self.new_vanity(builder)
|
self.new_vanity(builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds an output form control using the form's context and adds it to
|
||||||
|
/// the form.
|
||||||
|
///
|
||||||
|
/// This control allows you to output some text to the user based on the
|
||||||
|
/// form data and form context.
|
||||||
pub fn output_cx(
|
pub fn output_cx(
|
||||||
self,
|
self,
|
||||||
builder: impl BuilderCxFn<VanityControlBuilder<FD, OutputData>, FD::Context>,
|
builder: impl BuilderCxFn<VanityControlBuilder<FD, OutputData>, FD::Context>,
|
||||||
|
|||||||
@ -5,11 +5,15 @@ use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
|
|||||||
use leptos::{Signal, View};
|
use leptos::{Signal, View};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
/// Data used for the radio buttons control.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||||
pub struct RadioButtonsData {
|
pub struct RadioButtonsData {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub label: Option<String>,
|
pub label: Option<String>,
|
||||||
pub options: Vec<String>,
|
/// The options for the select.
|
||||||
|
///
|
||||||
|
/// The first value is the string to display, the second is the value.
|
||||||
|
pub options: Vec<(String, String)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ControlData for RadioButtonsData {
|
impl ControlData for RadioButtonsData {
|
||||||
@ -28,6 +32,7 @@ impl ControlData for RadioButtonsData {
|
|||||||
impl ValidatedControlData for RadioButtonsData {}
|
impl ValidatedControlData for RadioButtonsData {}
|
||||||
|
|
||||||
impl<FD: FormToolData> FormBuilder<FD> {
|
impl<FD: FormToolData> FormBuilder<FD> {
|
||||||
|
/// Builds a radio buttons control and adds it to the form.
|
||||||
pub fn radio_buttons<FDT: Clone + PartialEq + 'static>(
|
pub fn radio_buttons<FDT: Clone + PartialEq + 'static>(
|
||||||
self,
|
self,
|
||||||
builder: impl BuilderFn<ControlBuilder<FD, RadioButtonsData, FDT>>,
|
builder: impl BuilderFn<ControlBuilder<FD, RadioButtonsData, FDT>>,
|
||||||
@ -35,6 +40,8 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
self.new_control(builder)
|
self.new_control(builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds a radio buttons control using the form's context and adds it to
|
||||||
|
/// the form.
|
||||||
pub fn radio_buttons_cx<FDT: Clone + PartialEq + 'static>(
|
pub fn radio_buttons_cx<FDT: Clone + PartialEq + 'static>(
|
||||||
self,
|
self,
|
||||||
builder: impl BuilderCxFn<ControlBuilder<FD, RadioButtonsData, FDT>, FD::Context>,
|
builder: impl BuilderCxFn<ControlBuilder<FD, RadioButtonsData, FDT>, FD::Context>,
|
||||||
@ -44,24 +51,60 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<FD: FormToolData, FDT> ControlBuilder<FD, RadioButtonsData, FDT> {
|
impl<FD: FormToolData, FDT> ControlBuilder<FD, RadioButtonsData, FDT> {
|
||||||
|
/// Sets the name of the radio button inputs.
|
||||||
|
///
|
||||||
|
/// This is used for the html element's "name" attribute.
|
||||||
|
/// In forms, the name attribute is the key that the data is sent
|
||||||
|
/// with.
|
||||||
pub fn named(mut self, control_name: impl ToString) -> Self {
|
pub fn named(mut self, control_name: impl ToString) -> Self {
|
||||||
self.data.name = control_name.to_string();
|
self.data.name = control_name.to_string();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the label for the radio button group.
|
||||||
pub fn labeled(mut self, label: impl ToString) -> Self {
|
pub fn labeled(mut self, label: impl ToString) -> Self {
|
||||||
self.data.label = Some(label.to_string());
|
self.data.label = Some(label.to_string());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds the option to the radio button group.
|
||||||
pub fn with_option(mut self, option: impl ToString) -> Self {
|
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
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds the option to the radio button group, specifying a different
|
||||||
|
/// value than what is displayed.
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds all the options in the provided iterator to the radio button
|
||||||
|
/// group.
|
||||||
pub fn with_options(mut self, options: impl Iterator<Item = impl ToString>) -> Self {
|
pub fn with_options(mut self, options: impl Iterator<Item = impl ToString>) -> Self {
|
||||||
for option in options {
|
for option in options {
|
||||||
self.data.options.push(option.to_string());
|
self.data
|
||||||
|
.options
|
||||||
|
.push((option.to_string(), option.to_string()));
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds all the (display_string, value) pairs in the provided iterator
|
||||||
|
/// to the radio button group.
|
||||||
|
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
|
self
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
|
|||||||
use leptos::{Signal, View};
|
use leptos::{Signal, View};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
/// Data used for the select control.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||||
pub struct SelectData {
|
pub struct SelectData {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@ -31,12 +32,16 @@ impl ControlData for SelectData {
|
|||||||
impl ValidatedControlData for SelectData {}
|
impl ValidatedControlData for SelectData {}
|
||||||
|
|
||||||
impl<FD: FormToolData> FormBuilder<FD> {
|
impl<FD: FormToolData> FormBuilder<FD> {
|
||||||
|
/// Builds a select control and adds it to the form.
|
||||||
pub fn select<FDT: Clone + PartialEq + 'static>(
|
pub fn select<FDT: Clone + PartialEq + 'static>(
|
||||||
self,
|
self,
|
||||||
builder: impl BuilderFn<ControlBuilder<FD, SelectData, FDT>>,
|
builder: impl BuilderFn<ControlBuilder<FD, SelectData, FDT>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
self.new_control(builder)
|
self.new_control(builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds a select control using the form's context and adds it to the
|
||||||
|
/// form.
|
||||||
pub fn select_cx<FDT: Clone + PartialEq + 'static>(
|
pub fn select_cx<FDT: Clone + PartialEq + 'static>(
|
||||||
self,
|
self,
|
||||||
builder: impl BuilderCxFn<ControlBuilder<FD, SelectData, FDT>, FD::Context>,
|
builder: impl BuilderCxFn<ControlBuilder<FD, SelectData, FDT>, FD::Context>,
|
||||||
@ -46,16 +51,23 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<FD: FormToolData, FDT> ControlBuilder<FD, SelectData, FDT> {
|
impl<FD: FormToolData, FDT> ControlBuilder<FD, SelectData, FDT> {
|
||||||
|
/// Sets the name of the radio button inputs.
|
||||||
|
///
|
||||||
|
/// This is used for the html element's "name" attribute.
|
||||||
|
/// In forms, the name attribute is the key that the data is sent
|
||||||
|
/// with.
|
||||||
pub fn named(mut self, control_name: impl ToString) -> Self {
|
pub fn named(mut self, control_name: impl ToString) -> Self {
|
||||||
self.data.name = control_name.to_string();
|
self.data.name = control_name.to_string();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the label for the select.
|
||||||
pub fn labeled(mut self, label: impl ToString) -> Self {
|
pub fn labeled(mut self, label: impl ToString) -> Self {
|
||||||
self.data.label = Some(label.to_string());
|
self.data.label = Some(label.to_string());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds the option to the select.
|
||||||
pub fn with_option(mut self, option: impl ToString) -> Self {
|
pub fn with_option(mut self, option: impl ToString) -> Self {
|
||||||
self.data
|
self.data
|
||||||
.options
|
.options
|
||||||
@ -63,6 +75,8 @@ impl<FD: FormToolData, FDT> ControlBuilder<FD, SelectData, FDT> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds the option to the select, specifying a different
|
||||||
|
/// value than what is displayed.
|
||||||
pub fn with_option_valued(mut self, display: impl ToString, value: impl ToString) -> Self {
|
pub fn with_option_valued(mut self, display: impl ToString, value: impl ToString) -> Self {
|
||||||
self.data
|
self.data
|
||||||
.options
|
.options
|
||||||
@ -70,6 +84,7 @@ impl<FD: FormToolData, FDT> ControlBuilder<FD, SelectData, FDT> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds all the options in the provided iterator to the select.
|
||||||
pub fn with_options(mut self, options: impl Iterator<Item = impl ToString>) -> Self {
|
pub fn with_options(mut self, options: impl Iterator<Item = impl ToString>) -> Self {
|
||||||
for option in options {
|
for option in options {
|
||||||
self.data
|
self.data
|
||||||
@ -79,6 +94,8 @@ impl<FD: FormToolData, FDT> ControlBuilder<FD, SelectData, FDT> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds all the (display_string, value) pairs in the provided iterator
|
||||||
|
/// to the select.
|
||||||
pub fn with_options_valued(
|
pub fn with_options_valued(
|
||||||
mut self,
|
mut self,
|
||||||
options: impl Iterator<Item = (impl ToString, impl ToString)>,
|
options: impl Iterator<Item = (impl ToString, impl ToString)>,
|
||||||
|
|||||||
@ -3,6 +3,7 @@ use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
|
|||||||
use leptos::{Signal, View};
|
use leptos::{Signal, View};
|
||||||
use std::{ops::RangeInclusive, rc::Rc};
|
use std::{ops::RangeInclusive, rc::Rc};
|
||||||
|
|
||||||
|
/// Data used for the slider control.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct SliderData {
|
pub struct SliderData {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@ -37,6 +38,7 @@ impl ControlData for SliderData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<FD: FormToolData> FormBuilder<FD> {
|
impl<FD: FormToolData> FormBuilder<FD> {
|
||||||
|
/// Builds a slider (or range) control and adds it to the form.
|
||||||
pub fn slider<FDT: Clone + PartialEq + 'static>(
|
pub fn slider<FDT: Clone + PartialEq + 'static>(
|
||||||
self,
|
self,
|
||||||
builder: impl BuilderFn<ControlBuilder<FD, SliderData, FDT>>,
|
builder: impl BuilderFn<ControlBuilder<FD, SliderData, FDT>>,
|
||||||
@ -44,6 +46,8 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
self.new_control(builder)
|
self.new_control(builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Bulids a slider (or range) control using the form's context and adds
|
||||||
|
/// it to the form.
|
||||||
pub fn slider_cx<FDT: Clone + PartialEq + 'static>(
|
pub fn slider_cx<FDT: Clone + PartialEq + 'static>(
|
||||||
self,
|
self,
|
||||||
builder: impl BuilderCxFn<ControlBuilder<FD, SliderData, FDT>, FD::Context>,
|
builder: impl BuilderCxFn<ControlBuilder<FD, SliderData, FDT>, FD::Context>,
|
||||||
@ -53,26 +57,36 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<FD: FormToolData, FDT> ControlBuilder<FD, SliderData, FDT> {
|
impl<FD: FormToolData, FDT> ControlBuilder<FD, SliderData, FDT> {
|
||||||
|
/// Sets the name of the slider.
|
||||||
|
///
|
||||||
|
/// This is used for the html element's "name" attribute.
|
||||||
|
/// In forms, the name attribute is the key that the data is sent
|
||||||
|
/// with.
|
||||||
pub fn named(mut self, control_name: impl ToString) -> Self {
|
pub fn named(mut self, control_name: impl ToString) -> Self {
|
||||||
self.data.name = control_name.to_string();
|
self.data.name = control_name.to_string();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the label for the slider.
|
||||||
pub fn labeled(mut self, label: impl ToString) -> Self {
|
pub fn labeled(mut self, label: impl ToString) -> Self {
|
||||||
self.data.label = Some(label.to_string());
|
self.data.label = Some(label.to_string());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the minimum value for the slider.
|
||||||
pub fn min(mut self, min: i32) -> Self {
|
pub fn min(mut self, min: i32) -> Self {
|
||||||
self.data.min = min;
|
self.data.min = min;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the maximum value for the slider.
|
||||||
pub fn max(mut self, max: i32) -> Self {
|
pub fn max(mut self, max: i32) -> Self {
|
||||||
self.data.max = max;
|
self.data.max = max;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the minimum and maximum values for the slider by providing a
|
||||||
|
/// range.
|
||||||
pub fn range(mut self, range: RangeInclusive<i32>) -> Self {
|
pub fn range(mut self, range: RangeInclusive<i32>) -> Self {
|
||||||
self.data.min = *range.start();
|
self.data.min = *range.start();
|
||||||
self.data.max = *range.end();
|
self.data.max = *range.end();
|
||||||
|
|||||||
@ -3,6 +3,7 @@ use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
|
|||||||
use leptos::{prelude::Signal, View};
|
use leptos::{prelude::Signal, View};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
/// Data used for the spacer control.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||||
pub struct SpacerData {
|
pub struct SpacerData {
|
||||||
pub height: Option<String>,
|
pub height: Option<String>,
|
||||||
@ -19,10 +20,12 @@ impl VanityControlData for SpacerData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<FD: FormToolData> FormBuilder<FD> {
|
impl<FD: FormToolData> FormBuilder<FD> {
|
||||||
|
/// Builds a spacer and adds it to the form.
|
||||||
pub fn spacer(self, builder: impl BuilderFn<VanityControlBuilder<FD, SpacerData>>) -> Self {
|
pub fn spacer(self, builder: impl BuilderFn<VanityControlBuilder<FD, SpacerData>>) -> Self {
|
||||||
self.new_vanity(builder)
|
self.new_vanity(builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds a spacer using the form's context and adds it to the form.
|
||||||
pub fn spacer_cx(
|
pub fn spacer_cx(
|
||||||
self,
|
self,
|
||||||
builder: impl BuilderCxFn<VanityControlBuilder<FD, SpacerData>, FD::Context>,
|
builder: impl BuilderCxFn<VanityControlBuilder<FD, SpacerData>, FD::Context>,
|
||||||
@ -32,6 +35,9 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<FD: FormToolData> VanityControlBuilder<FD, SpacerData> {
|
impl<FD: FormToolData> VanityControlBuilder<FD, SpacerData> {
|
||||||
|
/// Sets the height of the spacer.
|
||||||
|
///
|
||||||
|
/// This may or may not be respected based on the Style implementation.
|
||||||
pub fn height(mut self, height: impl ToString) -> Self {
|
pub fn height(mut self, height: impl ToString) -> Self {
|
||||||
self.data.height = Some(height.to_string());
|
self.data.height = Some(height.to_string());
|
||||||
self
|
self
|
||||||
|
|||||||
@ -5,6 +5,7 @@ use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
|
|||||||
use leptos::{Signal, View};
|
use leptos::{Signal, View};
|
||||||
use std::{ops::RangeInclusive, rc::Rc};
|
use std::{ops::RangeInclusive, rc::Rc};
|
||||||
|
|
||||||
|
/// Data used for the stepper control.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||||
pub struct StepperData {
|
pub struct StepperData {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@ -30,6 +31,7 @@ impl ControlData for StepperData {
|
|||||||
impl ValidatedControlData for StepperData {}
|
impl ValidatedControlData for StepperData {}
|
||||||
|
|
||||||
impl<FD: FormToolData> FormBuilder<FD> {
|
impl<FD: FormToolData> FormBuilder<FD> {
|
||||||
|
/// Builds a stepper control and adds it to the form.
|
||||||
pub fn stepper<FDT: Clone + PartialEq + 'static>(
|
pub fn stepper<FDT: Clone + PartialEq + 'static>(
|
||||||
self,
|
self,
|
||||||
builder: impl BuilderFn<ControlBuilder<FD, StepperData, FDT>>,
|
builder: impl BuilderFn<ControlBuilder<FD, StepperData, FDT>>,
|
||||||
@ -37,6 +39,8 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
self.new_control(builder)
|
self.new_control(builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds a new stepper control using the form's context and adds it to
|
||||||
|
/// the form.
|
||||||
pub fn stepper_cx<FDT: Clone + PartialEq + 'static>(
|
pub fn stepper_cx<FDT: Clone + PartialEq + 'static>(
|
||||||
self,
|
self,
|
||||||
builder: impl BuilderCxFn<ControlBuilder<FD, StepperData, FDT>, FD::Context>,
|
builder: impl BuilderCxFn<ControlBuilder<FD, StepperData, FDT>, FD::Context>,
|
||||||
@ -46,31 +50,41 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<FD: FormToolData, FDT> ControlBuilder<FD, StepperData, FDT> {
|
impl<FD: FormToolData, FDT> ControlBuilder<FD, StepperData, FDT> {
|
||||||
|
/// Sets the name of the stepper control.
|
||||||
|
///
|
||||||
|
/// This is used for the html element's "name" attribute.
|
||||||
|
/// In forms, the name attribute is the key that the data is sent
|
||||||
|
/// with.
|
||||||
pub fn named(mut self, control_name: impl ToString) -> Self {
|
pub fn named(mut self, control_name: impl ToString) -> Self {
|
||||||
self.data.name = control_name.to_string();
|
self.data.name = control_name.to_string();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the label of the stepper.
|
||||||
pub fn labeled(mut self, label: impl ToString) -> Self {
|
pub fn labeled(mut self, label: impl ToString) -> Self {
|
||||||
self.data.label = Some(label.to_string());
|
self.data.label = Some(label.to_string());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the step ammount.
|
||||||
pub fn step(mut self, step: i32) -> Self {
|
pub fn step(mut self, step: i32) -> Self {
|
||||||
self.data.step = Some(step);
|
self.data.step = Some(step);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets a minimum value.
|
||||||
pub fn min(mut self, min: i32) -> Self {
|
pub fn min(mut self, min: i32) -> Self {
|
||||||
self.data.min = Some(min);
|
self.data.min = Some(min);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets a maximum value.
|
||||||
pub fn max(mut self, max: i32) -> Self {
|
pub fn max(mut self, max: i32) -> Self {
|
||||||
self.data.max = Some(max);
|
self.data.max = Some(max);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the minimum and maximum values using the range.
|
||||||
pub fn range(mut self, range: RangeInclusive<i32>) -> Self {
|
pub fn range(mut self, range: RangeInclusive<i32>) -> Self {
|
||||||
self.data.min = Some(*range.start());
|
self.data.min = Some(*range.start());
|
||||||
self.data.max = Some(*range.end());
|
self.data.max = Some(*range.end());
|
||||||
|
|||||||
@ -3,6 +3,7 @@ use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
|
|||||||
use leptos::{prelude::Signal, View};
|
use leptos::{prelude::Signal, View};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
/// Data used for the submit button control.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||||
pub struct SubmitData {
|
pub struct SubmitData {
|
||||||
pub text: String,
|
pub text: String,
|
||||||
@ -19,10 +20,13 @@ impl VanityControlData for SubmitData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<FD: FormToolData> FormBuilder<FD> {
|
impl<FD: FormToolData> FormBuilder<FD> {
|
||||||
|
/// Builds a submit button and adds it to the form.
|
||||||
pub fn submit(self, builder: impl BuilderFn<VanityControlBuilder<FD, SubmitData>>) -> Self {
|
pub fn submit(self, builder: impl BuilderFn<VanityControlBuilder<FD, SubmitData>>) -> Self {
|
||||||
self.new_vanity(builder)
|
self.new_vanity(builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds a submit button using the form's context and adds it to the
|
||||||
|
/// form.
|
||||||
pub fn submit_cx(
|
pub fn submit_cx(
|
||||||
self,
|
self,
|
||||||
builder: impl BuilderCxFn<VanityControlBuilder<FD, SubmitData>, FD::Context>,
|
builder: impl BuilderCxFn<VanityControlBuilder<FD, SubmitData>, FD::Context>,
|
||||||
@ -32,6 +36,7 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<FD: FormToolData> VanityControlBuilder<FD, SubmitData> {
|
impl<FD: FormToolData> VanityControlBuilder<FD, SubmitData> {
|
||||||
|
/// Sets the submit button's text.
|
||||||
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
|
||||||
|
|||||||
@ -5,10 +5,13 @@ use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
|
|||||||
use leptos::{Signal, View};
|
use leptos::{Signal, View};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
/// Data used for the text area control.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||||
pub struct TextAreaData {
|
pub struct TextAreaData {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub placeholder: Option<String>,
|
pub placeholder: Option<String>,
|
||||||
|
pub label: Option<String>,
|
||||||
|
pub initial_text: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ControlData for TextAreaData {
|
impl ControlData for TextAreaData {
|
||||||
@ -27,6 +30,7 @@ impl ControlData for TextAreaData {
|
|||||||
impl ValidatedControlData for TextAreaData {}
|
impl ValidatedControlData for TextAreaData {}
|
||||||
|
|
||||||
impl<FD: FormToolData> FormBuilder<FD> {
|
impl<FD: FormToolData> FormBuilder<FD> {
|
||||||
|
/// Builds a text area control and adds it to the form.
|
||||||
pub fn text_area<FDT: Clone + PartialEq + 'static>(
|
pub fn text_area<FDT: Clone + PartialEq + 'static>(
|
||||||
self,
|
self,
|
||||||
builder: impl BuilderFn<ControlBuilder<FD, TextAreaData, FDT>>,
|
builder: impl BuilderFn<ControlBuilder<FD, TextAreaData, FDT>>,
|
||||||
@ -34,6 +38,8 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
self.new_control(builder)
|
self.new_control(builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds a text area control using the forms context and adds it to the
|
||||||
|
/// form.
|
||||||
pub fn text_area_cx<FDT: Clone + PartialEq + 'static>(
|
pub fn text_area_cx<FDT: Clone + PartialEq + 'static>(
|
||||||
self,
|
self,
|
||||||
builder: impl BuilderCxFn<ControlBuilder<FD, TextAreaData, FDT>, FD::Context>,
|
builder: impl BuilderCxFn<ControlBuilder<FD, TextAreaData, FDT>, FD::Context>,
|
||||||
@ -43,8 +49,31 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<FD: FormToolData, FDT> ControlBuilder<FD, TextAreaData, FDT> {
|
impl<FD: FormToolData, FDT> ControlBuilder<FD, TextAreaData, FDT> {
|
||||||
|
/// Sets the name of the text area.
|
||||||
|
///
|
||||||
|
/// This is used for the html element's "name" attribute.
|
||||||
|
/// In forms, the name attribute is the key that the data is sent
|
||||||
|
/// with.
|
||||||
|
pub fn named(mut self, control_name: impl ToString) -> Self {
|
||||||
|
self.data.name = control_name.to_string();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the label for the text area.
|
||||||
|
pub fn labeled(mut self, label: impl ToString) -> Self {
|
||||||
|
self.data.label = Some(label.to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the placeholder for the text area.
|
||||||
pub fn placeholder(mut self, placeholder: impl ToString) -> Self {
|
pub fn placeholder(mut self, placeholder: impl ToString) -> Self {
|
||||||
self.data.placeholder = Some(placeholder.to_string());
|
self.data.placeholder = Some(placeholder.to_string());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the intial_text for the text area.
|
||||||
|
pub fn initial_text(mut self, text: impl ToString) -> Self {
|
||||||
|
self.data.initial_text = text.to_string();
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
|
|||||||
use leptos::{Signal, View};
|
use leptos::{Signal, View};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
/// Data used for the text input control.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct TextInputData {
|
pub struct TextInputData {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@ -42,6 +43,7 @@ impl ControlData for TextInputData {
|
|||||||
impl ValidatedControlData for TextInputData {}
|
impl ValidatedControlData for TextInputData {}
|
||||||
|
|
||||||
impl<FD: FormToolData> FormBuilder<FD> {
|
impl<FD: FormToolData> FormBuilder<FD> {
|
||||||
|
/// Builds a text input control and adds it to the form.
|
||||||
pub fn text_input<FDT: Clone + PartialEq + 'static>(
|
pub fn text_input<FDT: Clone + PartialEq + 'static>(
|
||||||
self,
|
self,
|
||||||
builder: impl BuilderFn<ControlBuilder<FD, TextInputData, FDT>>,
|
builder: impl BuilderFn<ControlBuilder<FD, TextInputData, FDT>>,
|
||||||
@ -49,6 +51,8 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
self.new_control(builder)
|
self.new_control(builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds a text input control using the form's context and adds it to
|
||||||
|
/// the form.
|
||||||
pub fn text_input_cx<FDT: Clone + PartialEq + 'static>(
|
pub fn text_input_cx<FDT: Clone + PartialEq + 'static>(
|
||||||
self,
|
self,
|
||||||
builder: impl BuilderCxFn<ControlBuilder<FD, TextInputData, FDT>, FD::Context>,
|
builder: impl BuilderCxFn<ControlBuilder<FD, TextInputData, FDT>, FD::Context>,
|
||||||
@ -58,28 +62,49 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<FD: FormToolData, FDT> ControlBuilder<FD, TextInputData, FDT> {
|
impl<FD: FormToolData, FDT> ControlBuilder<FD, TextInputData, FDT> {
|
||||||
|
/// Sets the name of the text input.
|
||||||
|
///
|
||||||
|
/// This is used for the html element's "name" attribute.
|
||||||
|
/// In forms, the name attribute is the key that the data is sent
|
||||||
|
/// with.
|
||||||
pub fn named(mut self, control_name: impl ToString) -> Self {
|
pub fn named(mut self, control_name: impl ToString) -> Self {
|
||||||
self.data.name = control_name.to_string();
|
self.data.name = control_name.to_string();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the label for the text input.
|
||||||
|
pub fn labeled(mut self, label: impl ToString) -> Self {
|
||||||
|
self.data.label = Some(label.to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the placeholder for the text input.
|
||||||
pub fn placeholder(mut self, placeholder: impl ToString) -> Self {
|
pub fn placeholder(mut self, placeholder: impl ToString) -> Self {
|
||||||
self.data.placeholder = Some(placeholder.to_string());
|
self.data.placeholder = Some(placeholder.to_string());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn label(mut self, label: impl ToString) -> Self {
|
/// Sets the intial_text for the text input.
|
||||||
self.data.label = Some(label.to_string());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn initial_text(mut self, text: impl ToString) -> Self {
|
pub fn initial_text(mut self, text: impl ToString) -> Self {
|
||||||
self.data.initial_text = text.to_string();
|
self.data.initial_text = text.to_string();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the text input to be the "password" type.
|
||||||
pub fn password(mut self) -> Self {
|
pub fn password(mut self) -> Self {
|
||||||
self.data.input_type = "password";
|
self.data.input_type = "password";
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the text input to be the "date" type.
|
||||||
|
pub fn date(mut self) -> Self {
|
||||||
|
self.data.input_type = "date";
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the text input to be the specified type.
|
||||||
|
pub fn input_type(mut self, input_type: &'static str) -> Self {
|
||||||
|
self.data.input_type = input_type;
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
27
src/form.rs
27
src/form.rs
@ -28,7 +28,7 @@ impl<FD: FormToolData> FormValidator<FD> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A constructed form object.
|
/// A constructed, rendered form object.
|
||||||
///
|
///
|
||||||
/// With this, you can render the form, get the form data, or get
|
/// With this, you can render the form, get the form data, or get
|
||||||
/// a validator for the data.
|
/// a validator for the data.
|
||||||
@ -48,7 +48,7 @@ impl<FD: FormToolData> Form<FD> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validates the [`FormToolData`], returning the result
|
/// Validates the [`FormToolData`], returning the result.
|
||||||
pub fn validate(&self) -> Result<(), String> {
|
pub fn validate(&self) -> Result<(), String> {
|
||||||
let validator = self.validator();
|
let validator = self.validator();
|
||||||
validator.validate(&self.fd.get_untracked())
|
validator.validate(&self.fd.get_untracked())
|
||||||
@ -79,13 +79,21 @@ impl<FD: FormToolData> IntoView for Form<FD> {
|
|||||||
|
|
||||||
/// A trait allowing a form to be built around its containing data.
|
/// A trait allowing a form to be built around its containing data.
|
||||||
///
|
///
|
||||||
/// This trait defines a function that can be used to build all the data needed
|
/// This trait defines a function that can be used to build all the data
|
||||||
/// to physically lay out a form, and how that data should be parsed and validated.
|
/// needed to physically lay out a form, and how that data should be parsed
|
||||||
|
/// and validated.
|
||||||
pub trait FormToolData: Clone + 'static {
|
pub trait FormToolData: Clone + 'static {
|
||||||
|
/// The style that this form uses.
|
||||||
type Style: FormStyle;
|
type Style: FormStyle;
|
||||||
|
/// The context that this form is rendered in.
|
||||||
|
///
|
||||||
|
/// This will need to be provided when building a form or a validator.
|
||||||
|
/// Therefore, you will need to be able to replicate this context
|
||||||
|
/// on the client for rendering and the server for validating.
|
||||||
type Context: 'static;
|
type Context: 'static;
|
||||||
|
|
||||||
/// Defines how the form should be layed out and how the data should be parsed and validated.
|
/// Defines how the form should be laid out and how the data should be
|
||||||
|
/// parsed and validated.
|
||||||
///
|
///
|
||||||
/// To construct a [`From`] object, use one of the `get_form` methods.
|
/// To construct a [`From`] object, use one of the `get_form` methods.
|
||||||
///
|
///
|
||||||
@ -100,12 +108,13 @@ pub trait FormToolData: Clone + 'static {
|
|||||||
/// [`ActionForm`](leptos_router::ActionForm) that sends the form data
|
/// [`ActionForm`](leptos_router::ActionForm) that sends the form data
|
||||||
/// directly by calling the server function.
|
/// directly by calling the server function.
|
||||||
///
|
///
|
||||||
/// By doing this, we avoid doing the [`FromFormData`](leptos_router::FromFormData)
|
/// By doing this, we avoid doing the
|
||||||
|
/// [`FromFormData`](leptos_router::FromFormData)
|
||||||
/// conversion. However, to support
|
/// conversion. However, to support
|
||||||
/// [Progressive Enhancement](https://book.leptos.dev/progressive_enhancement/index.html),
|
/// [Progressive Enhancement](https://book.leptos.dev/progressive_enhancement/index.html),
|
||||||
/// you should name the form elements to work with a plain ActionForm anyway.
|
/// you should name the form elements to work with a plain ActionForm
|
||||||
/// If progresssive enhancement is not important to you, you may freely
|
/// anyway. If progresssive enhancement is not important to you, you may
|
||||||
/// use this version
|
/// freely use this version.
|
||||||
///
|
///
|
||||||
/// For the other ways to construct a [`Form`], see:
|
/// For the other ways to construct a [`Form`], see:
|
||||||
/// - [`get_action_form`](Self::get_action_form)
|
/// - [`get_action_form`](Self::get_action_form)
|
||||||
|
|||||||
@ -19,11 +19,6 @@ use web_sys::{FormData, SubmitEvent};
|
|||||||
/// A builder for laying out forms.
|
/// A builder for laying out forms.
|
||||||
///
|
///
|
||||||
/// This builder allows you to specify what components should make up the form.
|
/// This builder allows you to specify what components should make up the form.
|
||||||
///
|
|
||||||
/// ### Type Parameters
|
|
||||||
/// - `FD`: FormToolData - Your form data
|
|
||||||
/// - `FS`: FormStyle - The form style you are using
|
|
||||||
/// - `CX`: Context - A user defined context that you are rendering the form in
|
|
||||||
pub struct FormBuilder<FD: FormToolData> {
|
pub struct FormBuilder<FD: FormToolData> {
|
||||||
pub(crate) cx: Rc<FD::Context>,
|
pub(crate) cx: Rc<FD::Context>,
|
||||||
/// The list of [`ValidationFn`]s.
|
/// The list of [`ValidationFn`]s.
|
||||||
@ -56,11 +51,13 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a styling attribute to the entire form.
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a new vanity control to the form.
|
||||||
pub(crate) fn new_vanity<C: VanityControlData + Default>(
|
pub(crate) fn new_vanity<C: VanityControlData + Default>(
|
||||||
mut self,
|
mut self,
|
||||||
builder: impl BuilderFn<VanityControlBuilder<FD, C>>,
|
builder: impl BuilderFn<VanityControlBuilder<FD, C>>,
|
||||||
@ -71,6 +68,7 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a new vanity control to the form using the form's context.
|
||||||
pub(crate) fn new_vanity_cx<C: VanityControlData + Default>(
|
pub(crate) fn new_vanity_cx<C: VanityControlData + Default>(
|
||||||
mut self,
|
mut self,
|
||||||
builder: impl BuilderCxFn<VanityControlBuilder<FD, C>, FD::Context>,
|
builder: impl BuilderCxFn<VanityControlBuilder<FD, C>, FD::Context>,
|
||||||
@ -81,6 +79,7 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a new control to the form using the form's context.
|
||||||
pub(crate) fn new_control<C: ControlData + Default, FDT: Clone + PartialEq + 'static>(
|
pub(crate) fn new_control<C: ControlData + Default, FDT: Clone + PartialEq + 'static>(
|
||||||
mut self,
|
mut self,
|
||||||
builder: impl BuilderFn<ControlBuilder<FD, C, FDT>>,
|
builder: impl BuilderFn<ControlBuilder<FD, C, FDT>>,
|
||||||
@ -91,6 +90,7 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a new control to the form using the form's context.
|
||||||
pub(crate) fn new_control_cx<C: ControlData + Default, FDT: Clone + PartialEq + 'static>(
|
pub(crate) fn new_control_cx<C: ControlData + Default, FDT: Clone + PartialEq + 'static>(
|
||||||
mut self,
|
mut self,
|
||||||
builder: impl BuilderCxFn<ControlBuilder<FD, C, FDT>, FD::Context>,
|
builder: impl BuilderCxFn<ControlBuilder<FD, C, FDT>, FD::Context>,
|
||||||
@ -101,8 +101,8 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test this from a user context. A user adding a custom defined component.
|
/// Adds a vanity control to the form.
|
||||||
pub fn add_vanity<C: VanityControlData>(
|
pub(crate) fn add_vanity<C: VanityControlData>(
|
||||||
&mut self,
|
&mut self,
|
||||||
vanity_control: VanityControlBuilder<FD, C>,
|
vanity_control: VanityControlBuilder<FD, C>,
|
||||||
) {
|
) {
|
||||||
@ -135,14 +135,20 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
self.render_fns.push(Box::new(render_fn));
|
self.render_fns.push(Box::new(render_fn));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test this from a user context. A user adding a custom defined component.
|
/// Adds a control to the form.
|
||||||
pub fn add_control<C: ControlData, FDT: Clone + PartialEq + 'static>(
|
pub(crate) fn add_control<C: ControlData, FDT: Clone + PartialEq + 'static>(
|
||||||
&mut self,
|
&mut self,
|
||||||
control: ControlBuilder<FD, C, FDT>,
|
control: ControlBuilder<FD, C, FDT>,
|
||||||
) {
|
) {
|
||||||
let built_control_data = match control.build() {
|
let built_control_data = match control.build() {
|
||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
Err(e) => panic!("Invalid Component: {}", e),
|
Err(e) => {
|
||||||
|
let item_name = std::any::type_name::<C>()
|
||||||
|
.rsplit("::")
|
||||||
|
.next()
|
||||||
|
.expect("split to have at least 1 element");
|
||||||
|
panic!("Invalid Component ({}): {}", item_name, e)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(validation_fn) = built_control_data.validation_fn.clone() {
|
if let Some(validation_fn) = built_control_data.validation_fn.clone() {
|
||||||
@ -174,6 +180,8 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
self.render_fns.push(Box::new(render_fn));
|
self.render_fns.push(Box::new(render_fn));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper for building all the functions and everything needed to render
|
||||||
|
/// the view.
|
||||||
fn build_control_view<C: ControlData, FDT: 'static>(
|
fn build_control_view<C: ControlData, FDT: 'static>(
|
||||||
fd: RwSignal<FD>,
|
fd: RwSignal<FD>,
|
||||||
fs: Rc<FD::Style>,
|
fs: Rc<FD::Style>,
|
||||||
@ -271,6 +279,7 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
(view, validation_cb)
|
(view, validation_cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper for creating a setter function.
|
||||||
fn create_value_setter<CRT: 'static, FDT: 'static>(
|
fn create_value_setter<CRT: 'static, FDT: 'static>(
|
||||||
validation_cb: Box<dyn Fn() -> bool + 'static>,
|
validation_cb: Box<dyn Fn() -> bool + 'static>,
|
||||||
validation_signal_set: WriteSignal<Result<(), String>>,
|
validation_signal_set: WriteSignal<Result<(), String>>,
|
||||||
@ -301,6 +310,7 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
Rc::new(value_setter)
|
Rc::new(value_setter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds the direct send version of the form.
|
||||||
pub(crate) fn build_form<ServFn>(
|
pub(crate) fn build_form<ServFn>(
|
||||||
self,
|
self,
|
||||||
action: Action<ServFn, Result<ServFn::Output, ServerFnError<ServFn::Error>>>,
|
action: Action<ServFn, Result<ServFn::Output, ServerFnError<ServFn::Error>>>,
|
||||||
@ -357,6 +367,7 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds the action form version of the form.
|
||||||
pub(crate) fn build_action_form<ServFn>(
|
pub(crate) fn build_action_form<ServFn>(
|
||||||
self,
|
self,
|
||||||
action: Action<ServFn, Result<ServFn::Output, ServerFnError<ServFn::Error>>>,
|
action: Action<ServFn, Result<ServFn::Output, ServerFnError<ServFn::Error>>>,
|
||||||
@ -407,6 +418,7 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// builds the plain form version of the form.
|
||||||
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 fs = Rc::new(fs);
|
||||||
@ -447,6 +459,7 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a [`FormValidator`] from this builder.
|
||||||
pub(crate) fn validator(&self) -> FormValidator<FD> {
|
pub(crate) fn validator(&self) -> FormValidator<FD> {
|
||||||
FormValidator {
|
FormValidator {
|
||||||
validations: self.validations.clone(),
|
validations: self.validations.clone(),
|
||||||
|
|||||||
@ -1,3 +1,8 @@
|
|||||||
|
//! `leptos_form_tool` offers a declaritve way to create forms for
|
||||||
|
//! [leptos](https://leptos.dev/).
|
||||||
|
//!
|
||||||
|
//! To learn more, see the
|
||||||
|
//! [README.md](https://github.com/MitchellMarinoDev/leptos_form_tool/src/branch/main/README.md)
|
||||||
pub mod controls;
|
pub mod controls;
|
||||||
mod form;
|
mod form;
|
||||||
mod form_builder;
|
mod form_builder;
|
||||||
|
|||||||
@ -12,22 +12,129 @@ use leptos::*;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use web_sys::MouseEvent;
|
use web_sys::MouseEvent;
|
||||||
|
|
||||||
pub enum GridFormStylingAttributes {
|
/// Styling attributes for the [`GridFormStyle`].
|
||||||
|
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub enum GFStyleAttr {
|
||||||
|
/// Set the width of the control out of 12.
|
||||||
|
/// Defaults to 12/12 (full width).
|
||||||
Width(u32),
|
Width(u32),
|
||||||
|
/// Adds a tooltip to the control.
|
||||||
|
/// This sets the html title attribute, which shows the text when the
|
||||||
|
/// user hovers their mouse over the control for a couple seconds.
|
||||||
|
Tooltip(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A complete useable example for defining a form style.
|
||||||
|
///
|
||||||
|
/// This can be used directly in by your form, or you can copy `grid_form.rs`
|
||||||
|
/// into your project and make any neccesary change. You will also want to
|
||||||
|
/// copy `grid_form.scss` from the git repo and put that in the `styles`
|
||||||
|
/// directory for your leptos project to get all the styling.
|
||||||
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct GridFormStyle;
|
pub struct GridFormStyle;
|
||||||
|
|
||||||
impl FormStyle for GridFormStyle {
|
impl FormStyle for GridFormStyle {
|
||||||
type StylingAttributes = GridFormStylingAttributes;
|
type StylingAttributes = GFStyleAttr;
|
||||||
|
|
||||||
fn form_frame(&self, form: ControlRenderData<Self, View>) -> View {
|
fn form_frame(&self, form: ControlRenderData<Self, View>) -> View {
|
||||||
view! { <div class="form_grid">{form.data}</div> }.into_view()
|
view! { <div class="form_grid">{form.data}</div> }.into_view()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A common function that wraps the given view in the styles
|
||||||
|
fn custom_component(&self, styles: &[Self::StylingAttributes], inner: View) -> View {
|
||||||
|
let mut width = 12;
|
||||||
|
let mut tooltip = None;
|
||||||
|
for style in styles.iter() {
|
||||||
|
match style {
|
||||||
|
GFStyleAttr::Width(w) => width = *w,
|
||||||
|
GFStyleAttr::Tooltip(t) => tooltip = Some(t),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
view! {
|
||||||
|
<div style:grid-column=format!("span {}", width) title=tooltip>
|
||||||
|
{inner}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
.into_view()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn group(&self, group: Rc<ControlRenderData<Self, View>>) -> View {
|
||||||
|
let view = view! {
|
||||||
|
<div class="form_group form_grid">
|
||||||
|
{&group.data}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
.into_view();
|
||||||
|
|
||||||
|
self.custom_component(&group.styles, view)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spacer(&self, control: Rc<ControlRenderData<Self, SpacerData>>) -> View {
|
||||||
|
self.custom_component(
|
||||||
|
&control.styles,
|
||||||
|
view! { <div style:height=control.data.height.as_ref()></div> }.into_view(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn heading(&self, control: Rc<ControlRenderData<Self, HeadingData>>) -> View {
|
fn heading(&self, control: Rc<ControlRenderData<Self, HeadingData>>) -> View {
|
||||||
view! { <h2 class="form_heading">{&control.data.title}</h2> }.into_view()
|
self.custom_component(
|
||||||
|
&control.styles,
|
||||||
|
view! { <h2 class="form_heading">{&control.data.title}</h2> }.into_view(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn submit(&self, control: Rc<ControlRenderData<Self, SubmitData>>) -> View {
|
||||||
|
self.custom_component(
|
||||||
|
&control.styles,
|
||||||
|
view! { <input type="submit" value=&control.data.text class="form_submit"/> }
|
||||||
|
.into_view(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button<FD: FormToolData>(
|
||||||
|
&self,
|
||||||
|
control: Rc<ControlRenderData<Self, ButtonData<FD>>>,
|
||||||
|
data_signal: RwSignal<FD>,
|
||||||
|
) -> View {
|
||||||
|
let action = control.data.action.clone();
|
||||||
|
let on_click = move |ev: MouseEvent| {
|
||||||
|
if let Some(action) = action.clone() {
|
||||||
|
action(ev, data_signal)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let view = view! {
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="form_button"
|
||||||
|
on:click=on_click
|
||||||
|
>
|
||||||
|
{&control.data.text}
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
.into_view();
|
||||||
|
|
||||||
|
self.custom_component(&control.styles, view)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn output(
|
||||||
|
&self,
|
||||||
|
control: Rc<ControlRenderData<Self, OutputData>>,
|
||||||
|
value_getter: Option<Signal<String>>,
|
||||||
|
) -> View {
|
||||||
|
let view = view! { <span>{move || value_getter.map(|g| g.get())}</span> }.into_view();
|
||||||
|
self.custom_component(&control.styles, view)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hidden(
|
||||||
|
&self,
|
||||||
|
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; column-span: none"/> }
|
||||||
|
.into_view()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn text_input(
|
fn text_input(
|
||||||
@ -37,16 +144,7 @@ impl FormStyle for GridFormStyle {
|
|||||||
value_setter: Rc<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
|
let view = view! {
|
||||||
let mut width = 1;
|
|
||||||
for style in control.styles.iter() {
|
|
||||||
match style {
|
|
||||||
GridFormStylingAttributes::Width(w) => width = *w,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
view! {
|
|
||||||
<div style:grid-column=format!("span {}", width)>
|
|
||||||
<div>
|
<div>
|
||||||
<label for=&control.data.name class="form_label">
|
<label for=&control.data.name class="form_label">
|
||||||
{control.data.label.as_ref()}
|
{control.data.label.as_ref()}
|
||||||
@ -62,13 +160,104 @@ impl FormStyle for GridFormStyle {
|
|||||||
on:focusout=move |ev| {
|
on:focusout=move |ev| {
|
||||||
value_setter(event_target_value(&ev));
|
value_setter(event_target_value(&ev));
|
||||||
}
|
}
|
||||||
|
|
||||||
class="form_input"
|
class="form_input"
|
||||||
class=("form_input_invalid", move || validation_state.get().is_err())
|
class=("form_input_invalid", move || validation_state.get().is_err())
|
||||||
/>
|
/>
|
||||||
|
}
|
||||||
|
.into_view();
|
||||||
|
|
||||||
|
self.custom_component(&control.styles, view)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn text_area(
|
||||||
|
&self,
|
||||||
|
control: Rc<ControlRenderData<Self, TextAreaData>>,
|
||||||
|
value_getter: Signal<<TextAreaData as ControlData>::ReturnType>,
|
||||||
|
value_setter: Rc<dyn Fn(<TextAreaData as ControlData>::ReturnType)>,
|
||||||
|
validation_state: Signal<Result<(), String>>,
|
||||||
|
) -> View {
|
||||||
|
let view = view! {
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<label for=&control.data.name class="form_label">
|
||||||
|
{control.data.label.as_ref()}
|
||||||
|
</label>
|
||||||
|
<span class="form_error">{move || validation_state.get().err()}</span>
|
||||||
|
</div>
|
||||||
|
<textarea
|
||||||
|
id=&control.data.name
|
||||||
|
name=&control.data.name
|
||||||
|
placeholder=control.data.placeholder.as_ref()
|
||||||
|
class="form_input"
|
||||||
|
prop:value=move || value_getter.get()
|
||||||
|
on:change=move |ev| {
|
||||||
|
value_setter(event_target_value(&ev));
|
||||||
|
}
|
||||||
|
>
|
||||||
|
</textarea>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
.into_view()
|
.into_view();
|
||||||
|
|
||||||
|
self.custom_component(&control.styles, view)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn radio_buttons(
|
||||||
|
&self,
|
||||||
|
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 buttons_view = control
|
||||||
|
.data
|
||||||
|
.options
|
||||||
|
.iter()
|
||||||
|
.map(|(display, value)| {
|
||||||
|
let value_setter = value_setter.clone();
|
||||||
|
let display = display.clone();
|
||||||
|
let value = value.clone();
|
||||||
|
let value_clone = value.clone();
|
||||||
|
let value_clone2 = value.clone();
|
||||||
|
view! {
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
id=&value
|
||||||
|
name=&control.data.name
|
||||||
|
value=&value
|
||||||
|
prop:checked=move || { &value_getter.get() == &value_clone }
|
||||||
|
on:input=move |ev| {
|
||||||
|
let new_value = event_target_checked(&ev);
|
||||||
|
if new_value {
|
||||||
|
value_setter(value_clone2.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<label for=&value>{display}</label>
|
||||||
|
<br/>
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect_view();
|
||||||
|
|
||||||
|
let view = view! {
|
||||||
|
<div>
|
||||||
|
<label for=&control.data.name class="form_label">
|
||||||
|
{control.data.label.as_ref()}
|
||||||
|
</label>
|
||||||
|
<span class="form_error">{move || validation_state.get().err()}</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="form_input"
|
||||||
|
class:form_input_invalid=move || validation_state.get().is_err()
|
||||||
|
>
|
||||||
|
{buttons_view}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
.into_view();
|
||||||
|
|
||||||
|
self.custom_component(&control.styles, view)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select(
|
fn select(
|
||||||
@ -78,13 +267,6 @@ impl FormStyle for GridFormStyle {
|
|||||||
value_setter: Rc<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;
|
|
||||||
for style in control.styles.iter() {
|
|
||||||
match style {
|
|
||||||
GridFormStylingAttributes::Width(w) => width = *w,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let options_view = control
|
let options_view = control
|
||||||
.data
|
.data
|
||||||
.options
|
.options
|
||||||
@ -100,8 +282,7 @@ impl FormStyle for GridFormStyle {
|
|||||||
})
|
})
|
||||||
.collect_view();
|
.collect_view();
|
||||||
|
|
||||||
view! {
|
let view = view! {
|
||||||
<div style:grid-column=format!("span {}", width)>
|
|
||||||
<div>
|
<div>
|
||||||
<label for=&control.data.name class="form_label">
|
<label for=&control.data.name class="form_label">
|
||||||
{control.data.label.as_ref()}
|
{control.data.label.as_ref()}
|
||||||
@ -119,118 +300,10 @@ impl FormStyle for GridFormStyle {
|
|||||||
|
|
||||||
{options_view}
|
{options_view}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
|
||||||
}
|
|
||||||
.into_view()
|
|
||||||
}
|
}
|
||||||
|
.into_view();
|
||||||
|
|
||||||
fn submit(&self, control: Rc<ControlRenderData<Self, SubmitData>>) -> View {
|
self.custom_component(&control.styles, view)
|
||||||
view! { <input type="submit" value=&control.data.text class="form_submit"/> }.into_view()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn text_area(
|
|
||||||
&self,
|
|
||||||
control: Rc<ControlRenderData<Self, TextAreaData>>,
|
|
||||||
value_getter: Signal<<TextAreaData as ControlData>::ReturnType>,
|
|
||||||
value_setter: Rc<dyn Fn(<TextAreaData as ControlData>::ReturnType)>,
|
|
||||||
validation_state: Signal<Result<(), String>>,
|
|
||||||
) -> View {
|
|
||||||
view! {
|
|
||||||
<div>
|
|
||||||
{move || format!("{:?}", validation_state.get())}
|
|
||||||
<textarea
|
|
||||||
id=&control.data.name
|
|
||||||
name=&control.data.name
|
|
||||||
placeholder=control.data.placeholder.as_ref()
|
|
||||||
class="form_input"
|
|
||||||
prop:value=move || value_getter.get()
|
|
||||||
on:change=move |ev| {
|
|
||||||
value_setter(event_target_value(&ev));
|
|
||||||
}
|
|
||||||
>
|
|
||||||
</textarea>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
.into_view()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn custom_component(&self, view: View) -> View {
|
|
||||||
view
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hidden(
|
|
||||||
&self,
|
|
||||||
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"/> }
|
|
||||||
.into_view()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn radio_buttons(
|
|
||||||
&self,
|
|
||||||
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.iter() {
|
|
||||||
match style {
|
|
||||||
GridFormStylingAttributes::Width(w) => width = *w,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let value_setter = Rc::new(value_setter);
|
|
||||||
let buttons_view = control
|
|
||||||
.data
|
|
||||||
.options
|
|
||||||
.iter()
|
|
||||||
.map(|o| {
|
|
||||||
let value_setter = value_setter.clone();
|
|
||||||
let o_clone1 = o.clone();
|
|
||||||
let o_clone2 = o.clone();
|
|
||||||
view! {
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
id=o.clone()
|
|
||||||
_str
|
|
||||||
name=&control.data.name
|
|
||||||
value=o.clone()
|
|
||||||
prop:checked=move || { value_getter.get() == o_clone1 }
|
|
||||||
on:input=move |ev| {
|
|
||||||
let new_value = event_target_checked(&ev);
|
|
||||||
if new_value {
|
|
||||||
value_setter(o_clone2.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<label for=o>{o}</label>
|
|
||||||
<br/>
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect_view();
|
|
||||||
|
|
||||||
view! {
|
|
||||||
<div style:grid-column=format!("span {}", width)>
|
|
||||||
<div>
|
|
||||||
<label for=&control.data.name class="form_label">
|
|
||||||
{control.data.label.as_ref()}
|
|
||||||
</label>
|
|
||||||
<span class="form_error">{move || validation_state.get().err()}</span>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="form_input"
|
|
||||||
class:form_input_invalid=move || validation_state.get().is_err()
|
|
||||||
>
|
|
||||||
{buttons_view}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
.into_view()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn checkbox(
|
fn checkbox(
|
||||||
@ -239,15 +312,7 @@ impl FormStyle for GridFormStyle {
|
|||||||
value_getter: Signal<<CheckboxData as ControlData>::ReturnType>,
|
value_getter: Signal<<CheckboxData as ControlData>::ReturnType>,
|
||||||
value_setter: Rc<dyn Fn(<CheckboxData as ControlData>::ReturnType)>,
|
value_setter: Rc<dyn Fn(<CheckboxData as ControlData>::ReturnType)>,
|
||||||
) -> View {
|
) -> View {
|
||||||
let mut width = 1;
|
let view = view! {
|
||||||
for style in control.styles.iter() {
|
|
||||||
match style {
|
|
||||||
GridFormStylingAttributes::Width(w) => width = *w,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
view! {
|
|
||||||
<div style:grid-column=format!("span {}", width)>
|
|
||||||
<label for=&control.data.name class="form_label">
|
<label for=&control.data.name class="form_label">
|
||||||
{control.data.label.as_ref()}
|
{control.data.label.as_ref()}
|
||||||
</label>
|
</label>
|
||||||
@ -265,9 +330,10 @@ impl FormStyle for GridFormStyle {
|
|||||||
|
|
||||||
<span>{control.data.label.as_ref()}</span>
|
<span>{control.data.label.as_ref()}</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
.into_view()
|
.into_view();
|
||||||
|
|
||||||
|
self.custom_component(&control.styles, view)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stepper(
|
fn stepper(
|
||||||
@ -277,15 +343,7 @@ impl FormStyle for GridFormStyle {
|
|||||||
value_setter: Rc<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 {
|
||||||
let mut width = 1;
|
let view = view! {
|
||||||
for style in control.styles.iter() {
|
|
||||||
match style {
|
|
||||||
GridFormStylingAttributes::Width(w) => width = *w,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
view! {
|
|
||||||
<div style:grid-column=format!("span {}", width)>
|
|
||||||
<div>
|
<div>
|
||||||
<label for=&control.data.name class="form_label">
|
<label for=&control.data.name class="form_label">
|
||||||
{control.data.label.as_ref()}
|
{control.data.label.as_ref()}
|
||||||
@ -304,17 +362,10 @@ impl FormStyle for GridFormStyle {
|
|||||||
|
|
||||||
class="form_input"
|
class="form_input"
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
}
|
|
||||||
.into_view()
|
|
||||||
}
|
}
|
||||||
|
.into_view();
|
||||||
|
|
||||||
fn output(
|
self.custom_component(&control.styles, view)
|
||||||
&self,
|
|
||||||
_control: Rc<ControlRenderData<Self, OutputData>>,
|
|
||||||
value_getter: Option<Signal<String>>,
|
|
||||||
) -> View {
|
|
||||||
view! { <div>{move || value_getter.map(|g| g.get())}</div> }.into_view()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn slider(
|
fn slider(
|
||||||
@ -324,15 +375,7 @@ impl FormStyle for GridFormStyle {
|
|||||||
value_setter: Rc<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 {
|
||||||
let mut width = 1;
|
let view = view! {
|
||||||
for style in control.styles.iter() {
|
|
||||||
match style {
|
|
||||||
GridFormStylingAttributes::Width(w) => width = *w,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
view! {
|
|
||||||
<div style:grid-column=format!("span {}", width)>
|
|
||||||
<div>
|
<div>
|
||||||
<label for=&control.data.name class="form_label">
|
<label for=&control.data.name class="form_label">
|
||||||
{control.data.label.as_ref()}
|
{control.data.label.as_ref()}
|
||||||
@ -355,68 +398,9 @@ impl FormStyle for GridFormStyle {
|
|||||||
|
|
||||||
class="form_input"
|
class="form_input"
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
}
|
|
||||||
.into_view()
|
|
||||||
}
|
}
|
||||||
|
.into_view();
|
||||||
|
|
||||||
fn button<FD: FormToolData>(
|
self.custom_component(&control.styles, view)
|
||||||
&self,
|
|
||||||
control: Rc<ControlRenderData<Self, ButtonData<FD>>>,
|
|
||||||
data_signal: RwSignal<FD>,
|
|
||||||
) -> View {
|
|
||||||
let mut width = 1;
|
|
||||||
for style in control.styles.iter() {
|
|
||||||
match style {
|
|
||||||
GridFormStylingAttributes::Width(w) => width = *w,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let action = control.data.action.clone();
|
|
||||||
let on_click = move |ev: MouseEvent| {
|
|
||||||
if let Some(action) = action.clone() {
|
|
||||||
action(ev, data_signal)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
view! {
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="form_button"
|
|
||||||
on:click=on_click
|
|
||||||
style:grid-column=format!("span {}", width)
|
|
||||||
>
|
|
||||||
{&control.data.text}
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
.into_view()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn group(&self, group: Rc<ControlRenderData<Self, View>>) -> View {
|
|
||||||
let mut width = 12;
|
|
||||||
for style in group.styles.iter() {
|
|
||||||
match style {
|
|
||||||
GridFormStylingAttributes::Width(w) => width = *w,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
view! {
|
|
||||||
<div class="form_group form_grid" style:grid-column=format!("span {}", width)>
|
|
||||||
{&group.data}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
.into_view()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn spacer(&self, control: Rc<ControlRenderData<Self, SpacerData>>) -> View {
|
|
||||||
let mut width = 12;
|
|
||||||
for style in control.styles.iter() {
|
|
||||||
match style {
|
|
||||||
GridFormStylingAttributes::Width(w) => width = *w,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
view! { <div style:grid-column=format!("span {}", width) style:height=control.data.height.as_ref()></div> }
|
|
||||||
.into_view()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
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,
|
||||||
@ -12,10 +10,19 @@ use crate::{
|
|||||||
FormToolData,
|
FormToolData,
|
||||||
};
|
};
|
||||||
use leptos::{RwSignal, Signal, View};
|
use leptos::{RwSignal, Signal, View};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub use grid_form::{GridFormStyle, GridFormStylingAttributes};
|
pub use grid_form::{GFStyleAttr, GridFormStyle};
|
||||||
|
|
||||||
|
/// Defines a way to style a form.
|
||||||
|
///
|
||||||
|
/// Provides methods for rendering all the controls.
|
||||||
|
/// This provider is in charge of figuring out what html elements should be
|
||||||
|
/// rendered and how they should be styled.
|
||||||
pub trait FormStyle: 'static {
|
pub trait FormStyle: 'static {
|
||||||
|
/// The type of styling attributes that this [`FormStyle`] takes.
|
||||||
|
///
|
||||||
|
/// These styling attributes can be applied to any of the controls.
|
||||||
type StylingAttributes;
|
type StylingAttributes;
|
||||||
|
|
||||||
/// Render any containing components for the form.
|
/// Render any containing components for the form.
|
||||||
@ -26,12 +33,68 @@ 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;
|
||||||
|
|
||||||
|
/// Wraps the view of a custom component.
|
||||||
|
///
|
||||||
|
/// The rendering of the custom component is given by the `inner` view.
|
||||||
|
/// Here the styler has a chance wrap the view with other components, or
|
||||||
|
/// applying the styling attributes.
|
||||||
|
///
|
||||||
|
/// This method does not need to be called by the custom component, but
|
||||||
|
/// the custom component may make use of this method for the
|
||||||
|
/// aforementioned reasons.
|
||||||
|
fn custom_component(&self, style: &[Self::StylingAttributes], inner: View) -> View;
|
||||||
|
|
||||||
|
/// Renders a group.
|
||||||
|
///
|
||||||
|
/// The inner view for the group's components is provided.
|
||||||
|
/// This method should wrap the group in any visual grouping elements,
|
||||||
|
/// and apply the styles.
|
||||||
|
fn group(&self, group: Rc<ControlRenderData<Self, View>>) -> View;
|
||||||
|
|
||||||
|
/// Renders a spacer.
|
||||||
|
///
|
||||||
|
/// See [`SpacerData`].
|
||||||
|
fn spacer(&self, control: Rc<ControlRenderData<Self, SpacerData>>) -> View;
|
||||||
|
|
||||||
|
/// Renders a heading for a section of the form.
|
||||||
fn heading(&self, control: Rc<ControlRenderData<Self, HeadingData>>) -> View;
|
fn heading(&self, control: Rc<ControlRenderData<Self, HeadingData>>) -> View;
|
||||||
|
|
||||||
|
/// Renders a submit button.
|
||||||
|
///
|
||||||
|
/// See [`SubmitData`].
|
||||||
|
fn submit(&self, control: Rc<ControlRenderData<Self, SubmitData>>) -> View;
|
||||||
|
|
||||||
|
/// Renders a button.
|
||||||
|
///
|
||||||
|
/// See [`BuuttonData`]
|
||||||
|
fn button<FD: FormToolData>(
|
||||||
|
&self,
|
||||||
|
control: Rc<ControlRenderData<Self, ButtonData<FD>>>,
|
||||||
|
data_signal: RwSignal<FD>,
|
||||||
|
) -> View;
|
||||||
|
|
||||||
|
/// Renders some output text.
|
||||||
|
///
|
||||||
|
/// See [`OutputData`].
|
||||||
|
fn output(
|
||||||
|
&self,
|
||||||
|
control: Rc<ControlRenderData<Self, OutputData>>,
|
||||||
|
value_getter: Option<Signal<String>>,
|
||||||
|
) -> View;
|
||||||
|
|
||||||
|
/// Renders a input control that should be hidden from the user.
|
||||||
|
///
|
||||||
|
/// See [`HiddenData`].
|
||||||
fn hidden(
|
fn hidden(
|
||||||
&self,
|
&self,
|
||||||
control: Rc<ControlRenderData<Self, HiddenData>>,
|
control: Rc<ControlRenderData<Self, HiddenData>>,
|
||||||
value_getter: Option<Signal<String>>,
|
value_getter: Option<Signal<String>>,
|
||||||
) -> View;
|
) -> View;
|
||||||
|
|
||||||
|
/// Renders a text input control.
|
||||||
|
///
|
||||||
|
/// See [`TextInputData`].
|
||||||
fn text_input(
|
fn text_input(
|
||||||
&self,
|
&self,
|
||||||
control: Rc<ControlRenderData<Self, TextInputData>>,
|
control: Rc<ControlRenderData<Self, TextInputData>>,
|
||||||
@ -39,6 +102,10 @@ pub trait FormStyle: 'static {
|
|||||||
value_setter: Rc<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;
|
||||||
|
|
||||||
|
/// Renders a text area control.
|
||||||
|
///
|
||||||
|
/// See [`TextAreaData`].
|
||||||
fn text_area(
|
fn text_area(
|
||||||
&self,
|
&self,
|
||||||
control: Rc<ControlRenderData<Self, TextAreaData>>,
|
control: Rc<ControlRenderData<Self, TextAreaData>>,
|
||||||
@ -46,6 +113,10 @@ pub trait FormStyle: 'static {
|
|||||||
value_setter: Rc<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;
|
||||||
|
|
||||||
|
/// Renders a group of radio buttons.
|
||||||
|
///
|
||||||
|
/// See [`RadioButtonsData`].
|
||||||
fn radio_buttons(
|
fn radio_buttons(
|
||||||
&self,
|
&self,
|
||||||
control: Rc<ControlRenderData<Self, RadioButtonsData>>,
|
control: Rc<ControlRenderData<Self, RadioButtonsData>>,
|
||||||
@ -53,6 +124,10 @@ pub trait FormStyle: 'static {
|
|||||||
value_setter: Rc<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;
|
||||||
|
|
||||||
|
/// Renders a select (or dropdown) control.
|
||||||
|
///
|
||||||
|
/// See [`SelectData`].
|
||||||
fn select(
|
fn select(
|
||||||
&self,
|
&self,
|
||||||
control: Rc<ControlRenderData<Self, SelectData>>,
|
control: Rc<ControlRenderData<Self, SelectData>>,
|
||||||
@ -60,17 +135,20 @@ pub trait FormStyle: 'static {
|
|||||||
value_setter: Rc<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>(
|
|
||||||
&self,
|
/// Renders a checkbox control.
|
||||||
control: Rc<ControlRenderData<Self, ButtonData<FD>>>,
|
///
|
||||||
data_signal: RwSignal<FD>,
|
/// See [`CheckboxData`].
|
||||||
) -> View;
|
|
||||||
fn checkbox(
|
fn checkbox(
|
||||||
&self,
|
&self,
|
||||||
control: Rc<ControlRenderData<Self, CheckboxData>>,
|
control: Rc<ControlRenderData<Self, CheckboxData>>,
|
||||||
value_getter: Signal<<CheckboxData as ControlData>::ReturnType>,
|
value_getter: Signal<<CheckboxData as ControlData>::ReturnType>,
|
||||||
value_setter: Rc<dyn Fn(<CheckboxData as ControlData>::ReturnType)>,
|
value_setter: Rc<dyn Fn(<CheckboxData as ControlData>::ReturnType)>,
|
||||||
) -> View;
|
) -> View;
|
||||||
|
|
||||||
|
/// Renders a stepper control.
|
||||||
|
///
|
||||||
|
/// See [`StepperData`].
|
||||||
fn stepper(
|
fn stepper(
|
||||||
&self,
|
&self,
|
||||||
control: Rc<ControlRenderData<Self, StepperData>>,
|
control: Rc<ControlRenderData<Self, StepperData>>,
|
||||||
@ -78,11 +156,10 @@ pub trait FormStyle: 'static {
|
|||||||
value_setter: Rc<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(
|
|
||||||
&self,
|
/// Renders a slider control.
|
||||||
control: Rc<ControlRenderData<Self, OutputData>>,
|
///
|
||||||
value_getter: Option<Signal<String>>,
|
/// See [`SliderData`].
|
||||||
) -> View;
|
|
||||||
fn slider(
|
fn slider(
|
||||||
&self,
|
&self,
|
||||||
control: Rc<ControlRenderData<Self, SliderData>>,
|
control: Rc<ControlRenderData<Self, SliderData>>,
|
||||||
@ -90,8 +167,4 @@ pub trait FormStyle: 'static {
|
|||||||
value_setter: Rc<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: Rc<ControlRenderData<Self, SubmitData>>) -> View;
|
|
||||||
fn custom_component(&self, view: View) -> 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