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"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[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