generated from mitchell/rust_template
first stab
This commit is contained in:
parent
eab2e1b19b
commit
bf6529cc1d
@ -3,7 +3,6 @@ name = "leptos_form_tool"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
leptos = "0.6.9"
|
||||||
|
|
||||||
|
|||||||
30
src/controls/heading.rs
Normal file
30
src/controls/heading.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
use leptos::View;
|
||||||
|
|
||||||
|
use crate::{ControlBuilder, ControlData, FormBuilder, FormData, FormStyleProvider};
|
||||||
|
|
||||||
|
pub struct HeadingData {
|
||||||
|
pub(crate) title: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadingData {
|
||||||
|
fn new(title: String) -> Self {
|
||||||
|
HeadingData { title }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<FS: FormStyleProvider> ControlData<FS> for HeadingData {
|
||||||
|
fn build_control(self, fs: &FS, attributes: Vec<FS::StylingAttributes>) -> View {
|
||||||
|
fs.heading(self, attributes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<FD: FormData, FS: FormStyleProvider> FormBuilder<FD, FS> {
|
||||||
|
pub fn heading(self, title: impl ToString) -> ControlBuilder<FD, FS, HeadingData> {
|
||||||
|
ControlBuilder {
|
||||||
|
fb: self,
|
||||||
|
parse_fn: None,
|
||||||
|
style_attributes: Vec::new(),
|
||||||
|
data: HeadingData::new(title.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/controls/mod.rs
Normal file
5
src/controls/mod.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
pub mod heading;
|
||||||
|
pub mod select;
|
||||||
|
pub mod submit;
|
||||||
|
pub mod text_area;
|
||||||
|
pub mod text_input;
|
||||||
41
src/controls/select.rs
Normal file
41
src/controls/select.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
use leptos::View;
|
||||||
|
|
||||||
|
use crate::{ControlBuilder, ControlData, FormBuilder, FormData, FormStyleProvider};
|
||||||
|
|
||||||
|
pub struct SelectData {
|
||||||
|
pub(crate) name: String,
|
||||||
|
pub(crate) options: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SelectData {
|
||||||
|
fn new(name: String) -> Self {
|
||||||
|
SelectData {
|
||||||
|
name,
|
||||||
|
options: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<FS: FormStyleProvider> ControlData<FS> for SelectData {
|
||||||
|
fn build_control(self, fs: &FS, attributes: Vec<FS::StylingAttributes>) -> View {
|
||||||
|
fs.select(self, attributes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<FD: FormData, FS: FormStyleProvider> FormBuilder<FD, FS> {
|
||||||
|
pub fn select(self, name: impl ToString) -> ControlBuilder<FD, FS, SelectData> {
|
||||||
|
ControlBuilder {
|
||||||
|
fb: self,
|
||||||
|
parse_fn: None,
|
||||||
|
style_attributes: Vec::new(),
|
||||||
|
data: SelectData::new(name.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<FD: FormData, FS: FormStyleProvider> ControlBuilder<FD, FS, SelectData> {
|
||||||
|
pub fn options(mut self, options: Vec<String>) -> Self {
|
||||||
|
self.data.options = options;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/controls/submit.rs
Normal file
30
src/controls/submit.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
use leptos::View;
|
||||||
|
|
||||||
|
use crate::{ControlBuilder, ControlData, FormBuilder, FormData, FormStyleProvider};
|
||||||
|
|
||||||
|
pub struct SubmitData {
|
||||||
|
pub(crate) text: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubmitData {
|
||||||
|
fn new(text: String) -> Self {
|
||||||
|
SubmitData { text }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<FS: FormStyleProvider> ControlData<FS> for SubmitData {
|
||||||
|
fn build_control(self, fs: &FS, attributes: Vec<FS::StylingAttributes>) -> View {
|
||||||
|
fs.submit(self, attributes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<FD: FormData, FS: FormStyleProvider> FormBuilder<FD, FS> {
|
||||||
|
pub fn submit(self, text: impl ToString) -> ControlBuilder<FD, FS, SubmitData> {
|
||||||
|
ControlBuilder {
|
||||||
|
fb: self,
|
||||||
|
parse_fn: None,
|
||||||
|
style_attributes: Vec::new(),
|
||||||
|
data: SubmitData::new(text.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/controls/text_area.rs
Normal file
41
src/controls/text_area.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
use leptos::View;
|
||||||
|
|
||||||
|
use crate::{ControlBuilder, ControlData, FormBuilder, FormData, FormStyleProvider};
|
||||||
|
|
||||||
|
pub struct TextAreaData {
|
||||||
|
pub(crate) name: String,
|
||||||
|
pub(crate) placeholder: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TextAreaData {
|
||||||
|
fn new(name: String) -> Self {
|
||||||
|
TextAreaData {
|
||||||
|
name,
|
||||||
|
placeholder: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<FS: FormStyleProvider> ControlData<FS> for TextAreaData {
|
||||||
|
fn build_control(self, fs: &FS, attributes: Vec<FS::StylingAttributes>) -> View {
|
||||||
|
fs.text_area(self, attributes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<FD: FormData, FS: FormStyleProvider> FormBuilder<FD, FS> {
|
||||||
|
pub fn text_area(self, name: impl ToString) -> ControlBuilder<FD, FS, TextAreaData> {
|
||||||
|
ControlBuilder {
|
||||||
|
fb: self,
|
||||||
|
parse_fn: None,
|
||||||
|
style_attributes: Vec::new(),
|
||||||
|
data: TextAreaData::new(name.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<FD: FormData, FS: FormStyleProvider> ControlBuilder<FD, FS, TextAreaData> {
|
||||||
|
pub fn placeholder(mut self, placeholder: impl ToString) -> Self {
|
||||||
|
self.data.placeholder = Some(placeholder.to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
62
src/controls/text_input.rs
Normal file
62
src/controls/text_input.rs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
use leptos::View;
|
||||||
|
|
||||||
|
use crate::{ControlBuilder, ControlData, FormBuilder, FormData, FormStyleProvider};
|
||||||
|
|
||||||
|
pub struct TextInputData {
|
||||||
|
pub(crate) name: String,
|
||||||
|
pub(crate) placeholder: Option<String>,
|
||||||
|
pub(crate) label: Option<String>,
|
||||||
|
pub(crate) initital_text: String,
|
||||||
|
pub(crate) input_type: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TextInputData {
|
||||||
|
fn new(name: String) -> Self {
|
||||||
|
TextInputData {
|
||||||
|
name,
|
||||||
|
placeholder: None,
|
||||||
|
label: None,
|
||||||
|
initital_text: String::new(),
|
||||||
|
input_type: "input",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<FS: FormStyleProvider> ControlData<FS> for TextInputData {
|
||||||
|
fn build_control(self, fs: &FS, attributes: Vec<FS::StylingAttributes>) -> View {
|
||||||
|
fs.text_input(self, attributes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<FD: FormData, FS: FormStyleProvider> FormBuilder<FD, FS> {
|
||||||
|
pub fn text_input(self, name: impl ToString) -> ControlBuilder<FD, FS, TextInputData> {
|
||||||
|
ControlBuilder {
|
||||||
|
fb: self,
|
||||||
|
parse_fn: None,
|
||||||
|
style_attributes: Vec::new(),
|
||||||
|
data: TextInputData::new(name.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<FD: FormData, FS: FormStyleProvider> ControlBuilder<FD, FS, TextInputData> {
|
||||||
|
pub fn placeholder(mut self, placeholder: impl ToString) -> Self {
|
||||||
|
self.data.placeholder = Some(placeholder.to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn label(mut self, label: impl ToString) -> Self {
|
||||||
|
self.data.label = Some(label.to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initial_text(mut self, text: impl ToString) -> Self {
|
||||||
|
self.data.initital_text = text.to_string();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn password(mut self) -> Self {
|
||||||
|
self.data.input_type = "password";
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
59
src/lib.rs
Normal file
59
src/lib.rs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
use controls::{
|
||||||
|
heading::HeadingData, select::SelectData, submit::SubmitData, text_area::TextAreaData,
|
||||||
|
text_input::TextInputData,
|
||||||
|
};
|
||||||
|
use leptos::*;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
mod controls;
|
||||||
|
mod provider_impl;
|
||||||
|
|
||||||
|
pub trait FormStyleProvider {
|
||||||
|
type StylingAttributes;
|
||||||
|
|
||||||
|
fn heading(&self, data: HeadingData, attributes: Vec<Self::StylingAttributes>) -> View;
|
||||||
|
fn text_input(&self, data: TextInputData, attributes: Vec<Self::StylingAttributes>) -> View;
|
||||||
|
fn select(&self, data: SelectData, attributes: Vec<Self::StylingAttributes>) -> View;
|
||||||
|
fn submit(&self, data: SubmitData, attributes: Vec<Self::StylingAttributes>) -> View;
|
||||||
|
fn text_area(&self, data: TextAreaData, attributes: Vec<Self::StylingAttributes>) -> View;
|
||||||
|
fn custom_component(&self, component: View) -> View;
|
||||||
|
// TODO: add group
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ControlData<FS: FormStyleProvider>: 'static {
|
||||||
|
fn build_control(self, fs: &FS, attributes: Vec<FS::StylingAttributes>) -> View;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FormBuilder<FD: FormData, FS: FormStyleProvider> {
|
||||||
|
_fd: PhantomData<FD>,
|
||||||
|
fs: FS,
|
||||||
|
controls: Vec<(Box<dyn ControlData<FS>>, Vec<FS::StylingAttributes>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FormData {}
|
||||||
|
|
||||||
|
pub struct ControlBuilder<FD: FormData, FS: FormStyleProvider, C: ControlData<FS>> {
|
||||||
|
fb: FormBuilder<FD, FS>,
|
||||||
|
parse_fn: Option<Box<dyn Fn(&str, &mut FD)>>,
|
||||||
|
style_attributes: Vec<FS::StylingAttributes>,
|
||||||
|
data: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<FD: FormData, FS: FormStyleProvider, C: ControlData<FS>> ControlBuilder<FD, FS, C> {
|
||||||
|
pub fn parse_fn(mut self, parse_fn: Box<dyn Fn(&str, &mut FD)>) -> Self {
|
||||||
|
self.parse_fn = Some(parse_fn);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn style(mut self, attribute: FS::StylingAttributes) -> Self {
|
||||||
|
self.style_attributes.push(attribute);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn end(mut self) -> FormBuilder<FD, FS> {
|
||||||
|
self.fb
|
||||||
|
.controls
|
||||||
|
.push((Box::new(self.data), self.style_attributes));
|
||||||
|
self.fb
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +0,0 @@
|
|||||||
fn main() {
|
|
||||||
println!("Hello, world!");
|
|
||||||
}
|
|
||||||
86
src/provider_impl.rs
Normal file
86
src/provider_impl.rs
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
use crate::{
|
||||||
|
controls::{select::SelectData, submit::SubmitData, text_area::TextAreaData},
|
||||||
|
FormStyleProvider, HeadingData, TextInputData,
|
||||||
|
};
|
||||||
|
use leptos::*;
|
||||||
|
|
||||||
|
pub enum TailwindStylingAttibutes {
|
||||||
|
Width(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TailwindFormStyleProvider;
|
||||||
|
|
||||||
|
impl FormStyleProvider for TailwindFormStyleProvider {
|
||||||
|
type StylingAttributes = TailwindFormStyleProvider;
|
||||||
|
|
||||||
|
// fn label(&self, data: LabelData) -> View {
|
||||||
|
// view! {
|
||||||
|
// }.into_view()
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn heading(&self, data: HeadingData, attributes: Vec<Self::StylingAttributes>) -> View {
|
||||||
|
view! {
|
||||||
|
<h2 class="text-xl py-2 text-center font-bold text-gray-700 border-b-2 border-gray-800/60 mb-8">
|
||||||
|
{&data.title}
|
||||||
|
</h2>
|
||||||
|
}
|
||||||
|
.into_view()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn text_input(&self, data: TextInputData, attributes: Vec<Self::StylingAttributes>) -> View {
|
||||||
|
view! {
|
||||||
|
<label
|
||||||
|
for={&data.name}
|
||||||
|
class="block uppercase tracking-wide text-left text-gray-700 text-md font-bold ml-2 mb-1"
|
||||||
|
>
|
||||||
|
{data.label.as_ref()}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
// TODO:
|
||||||
|
// type=text_type
|
||||||
|
id=&data.name
|
||||||
|
name=data.name
|
||||||
|
// placeholder=placeholder
|
||||||
|
class="block w-full bg-gray-100 border-2 border-gray-300 text-gray-700 py-2 px-4 rounded-lg leading-tight focus:outline-none focus:bg-white focus:border-sky-400"
|
||||||
|
/>
|
||||||
|
}.into_view()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn select(&self, data: SelectData, attributes: Vec<Self::StylingAttributes>) -> View {
|
||||||
|
view! {
|
||||||
|
<select
|
||||||
|
id=&data.name
|
||||||
|
name=data.name
|
||||||
|
class="block w-full bg-gray-100 border-2 border-gray-300 text-gray-700 py-2 px-4 rounded-lg leading-tight focus:outline-none focus:bg-white focus:border-sky-400"
|
||||||
|
>
|
||||||
|
{data.options}
|
||||||
|
</select>
|
||||||
|
}.into_view()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn submit(&self, data: SubmitData, attributes: Vec<Self::StylingAttributes>) -> View {
|
||||||
|
view! {
|
||||||
|
<input
|
||||||
|
type="submit"
|
||||||
|
value=data.text
|
||||||
|
class="col-span-full rounded-2xl bg-sky-700 text-white font-bold hover:cursor-pointer hover:bg-sky-600 px-5 py-3 mx-auto mt-4"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
.into_view()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn text_area(&self, data: TextAreaData, attributes: Vec<Self::StylingAttributes>) -> View {
|
||||||
|
view! {
|
||||||
|
<textarea
|
||||||
|
id=&data.name
|
||||||
|
name=data.name
|
||||||
|
placeholder=data.placeholder
|
||||||
|
class="block w-full bg-gray-100 border-2 border-gray-300 text-gray-700 py-2 px-4 rounded-lg leading-tight focus:outline-none focus:bg-white focus:border-sky-400"
|
||||||
|
/>
|
||||||
|
}.into_view()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn custom_component(&self, component: View) -> View {
|
||||||
|
component
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user