generated from mitchell/rust_template
before removing VanityControl and Control
This commit is contained in:
parent
fbe746702a
commit
80a967346c
@ -1,5 +1,5 @@
|
||||
use crate::{form::FormData, styles::FormStyle};
|
||||
use leptos::View;
|
||||
use leptos::{Signal, View};
|
||||
|
||||
pub mod heading;
|
||||
pub mod select;
|
||||
@ -18,10 +18,13 @@ pub trait VanityControlData: 'static {
|
||||
}
|
||||
|
||||
pub trait ControlData: 'static {
|
||||
type ReturnType;
|
||||
type ReturnType: Clone;
|
||||
|
||||
// TODO: this should also return a getter for the data
|
||||
fn build_control<FD: FormData, FS: FormStyle>(fs: &FS, control: Control<FD, FS, Self>) -> View;
|
||||
fn build_control<FD: FormData, FS: FormStyle>(
|
||||
fs: &FS,
|
||||
control: Control<FD, FS, Self>,
|
||||
) -> (View, Signal<Self::ReturnType>);
|
||||
}
|
||||
|
||||
pub struct VanityControl<FS: FormStyle + ?Sized, C: VanityControlData + ?Sized> {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use leptos::View;
|
||||
use leptos::{Signal, View};
|
||||
|
||||
use super::{Control, ControlBuilder, ControlData};
|
||||
use crate::{
|
||||
@ -15,7 +15,10 @@ pub struct SelectData {
|
||||
impl ControlData for SelectData {
|
||||
type ReturnType = String;
|
||||
|
||||
fn build_control<FD: FormData, FS: FormStyle>(fs: &FS, control: Control<FD, FS, Self>) -> View {
|
||||
fn build_control<FD: FormData, FS: FormStyle>(
|
||||
fs: &FS,
|
||||
control: Control<FD, FS, Self>,
|
||||
) -> (View, Signal<Self::ReturnType>) {
|
||||
fs.select(control)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
use leptos::View;
|
||||
|
||||
use super::{Control, ControlBuilder, ControlData};
|
||||
use crate::{
|
||||
form::{FormBuilder, FormData},
|
||||
styles::FormStyle,
|
||||
};
|
||||
use leptos::{Signal, View};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||
pub struct TextAreaData {
|
||||
@ -15,7 +14,10 @@ pub struct TextAreaData {
|
||||
impl ControlData for TextAreaData {
|
||||
type ReturnType = String;
|
||||
|
||||
fn build_control<FD: FormData, FS: FormStyle>(fs: &FS, control: Control<FD, FS, Self>) -> View {
|
||||
fn build_control<FD: FormData, FS: FormStyle>(
|
||||
fs: &FS,
|
||||
control: Control<FD, FS, Self>,
|
||||
) -> (View, Signal<Self::ReturnType>) {
|
||||
fs.text_area(control)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use leptos::View;
|
||||
use leptos::{Signal, View};
|
||||
|
||||
use super::{Control, ControlBuilder, ControlData};
|
||||
use crate::{
|
||||
@ -30,7 +30,10 @@ impl Default for TextInputData {
|
||||
impl ControlData for TextInputData {
|
||||
type ReturnType = String;
|
||||
|
||||
fn build_control<FD: FormData, FS: FormStyle>(fs: &FS, control: Control<FD, FS, Self>) -> View {
|
||||
fn build_control<FD: FormData, FS: FormStyle>(
|
||||
fs: &FS,
|
||||
control: Control<FD, FS, Self>,
|
||||
) -> (View, Signal<Self::ReturnType>) {
|
||||
fs.text_input(control)
|
||||
}
|
||||
}
|
||||
|
||||
38
src/form.rs
38
src/form.rs
@ -5,11 +5,16 @@ use crate::{
|
||||
},
|
||||
styles::FormStyle,
|
||||
};
|
||||
use leptos::{IntoView, View};
|
||||
use std::marker::PhantomData;
|
||||
use leptos::{
|
||||
create_effect, create_signal, IntoView, ReadSignal, SignalGet, SignalSet, SignalUpdate, View,
|
||||
WriteSignal,
|
||||
};
|
||||
|
||||
pub struct Form {}
|
||||
|
||||
pub struct FormBuilder<FD: FormData, FS: FormStyle> {
|
||||
_fd: PhantomData<FD>,
|
||||
fd_get: ReadSignal<FD>,
|
||||
fd_set: WriteSignal<FD>,
|
||||
fs: FS,
|
||||
validations: Vec<Box<ValidationFn<FD>>>,
|
||||
views: Vec<View>,
|
||||
@ -17,8 +22,10 @@ pub struct FormBuilder<FD: FormData, FS: FormStyle> {
|
||||
|
||||
impl<FD: FormData, FS: FormStyle> FormBuilder<FD, FS> {
|
||||
pub fn new(form_style: FS) -> FormBuilder<FD, FS> {
|
||||
let (fs_get, fs_set) = create_signal(FD::default());
|
||||
FormBuilder {
|
||||
_fd: PhantomData::default(),
|
||||
fd_get,
|
||||
fd_set,
|
||||
fs: form_style,
|
||||
validations: Vec::new(),
|
||||
views: Vec::new(),
|
||||
@ -51,7 +58,26 @@ impl<FD: FormData, FS: FormStyle> FormBuilder<FD, FS> {
|
||||
}
|
||||
|
||||
fn add_control<C: ControlData>(&mut self, control: Control<FD, FS, C>) {
|
||||
let view = ControlData::build_control(&self.fs, control);
|
||||
let (validation_signal, validation_signal_set) = create_signal(Ok(()));
|
||||
let (view, control_value) = ControlData::build_control(&self.fs, control);
|
||||
// TODO: add a signal that triggers on submit to refresh the validation on_submit
|
||||
// TODO: we might want a way to see if this is the first time this ran, which would
|
||||
// prevent the form's validation to pop up before the user typed anything in
|
||||
// TODO: add validation here that run on the input changing, and writes
|
||||
// it to the fd signals
|
||||
create_effect(move |last_value| {
|
||||
let control_value = control_value.get();
|
||||
let mut validation_result;
|
||||
self.fd_set.update(|v| {
|
||||
validation_result =
|
||||
(control.parse_fn)(control_value, v).and_then(|_| (*control.validation)(v));
|
||||
});
|
||||
// TODO: or this happened on a submit
|
||||
if Some(validation_result) != last_value {
|
||||
validation_signal_set.set(validation_result);
|
||||
}
|
||||
validation_result
|
||||
});
|
||||
self.views.push(view);
|
||||
}
|
||||
|
||||
@ -62,7 +88,7 @@ impl<FD: FormData, FS: FormStyle> FormBuilder<FD, FS> {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait FormData: Default {
|
||||
pub trait FormData: Default + Clone + 'static {
|
||||
// TODO: this should return a Form Object
|
||||
fn create_form() -> View;
|
||||
}
|
||||
|
||||
@ -5,21 +5,32 @@ pub use tw_grid::{TailwindGridFormStyle, TailwindGridStylingAttributes};
|
||||
use crate::{
|
||||
controls::{
|
||||
heading::HeadingData, select::SelectData, submit::SubmitData, text_area::TextAreaData,
|
||||
text_input::TextInputData, Control, VanityControl,
|
||||
text_input::TextInputData, Control, ControlData, VanityControl,
|
||||
},
|
||||
form::FormData,
|
||||
};
|
||||
use leptos::View;
|
||||
use leptos::{Signal, View};
|
||||
|
||||
pub trait FormStyle: 'static {
|
||||
type StylingAttributes;
|
||||
|
||||
// TODO: add form frame
|
||||
// TODO: perhaps we don't want to send the full control type anymore.
|
||||
// as the rendering shouldn't depend on parse or validate anymore.
|
||||
fn heading(&self, control: VanityControl<Self, HeadingData>) -> View;
|
||||
fn text_input<FD: FormData>(&self, control: Control<FD, Self, TextInputData>) -> View;
|
||||
fn select<FD: FormData>(&self, control: Control<FD, Self, SelectData>) -> View;
|
||||
fn text_input<FD: FormData>(
|
||||
&self,
|
||||
control: Control<FD, Self, TextInputData>,
|
||||
) -> (View, Signal<<TextInputData as ControlData>::ReturnType>);
|
||||
fn select<FD: FormData>(
|
||||
&self,
|
||||
control: Control<FD, Self, SelectData>,
|
||||
) -> (View, Signal<<SelectData as ControlData>::ReturnType>);
|
||||
fn submit(&self, control: VanityControl<Self, SubmitData>) -> View;
|
||||
fn text_area<FD: FormData>(&self, control: Control<FD, Self, TextAreaData>) -> View;
|
||||
fn text_area<FD: FormData>(
|
||||
&self,
|
||||
control: Control<FD, Self, TextAreaData>,
|
||||
) -> (View, Signal<<TextAreaData as ControlData>::ReturnType>);
|
||||
fn custom_component(&self, view: View) -> View;
|
||||
// TODO: add group
|
||||
}
|
||||
|
||||
@ -6,8 +6,7 @@ use crate::{
|
||||
},
|
||||
form::FormData,
|
||||
};
|
||||
use leptos::CollectView;
|
||||
use leptos::{view, IntoView, View};
|
||||
use leptos::*;
|
||||
|
||||
pub enum TailwindGridStylingAttributes {
|
||||
Width(u32),
|
||||
@ -27,8 +26,13 @@ impl FormStyle for TailwindGridFormStyle {
|
||||
.into_view()
|
||||
}
|
||||
|
||||
fn text_input<FD: FormData>(&self, control: Control<FD, Self, TextInputData>) -> View {
|
||||
view! {
|
||||
fn text_input<FD: FormData>(
|
||||
&self,
|
||||
control: Control<FD, Self, TextInputData>,
|
||||
) -> (View, ReadSignal<String>) {
|
||||
let (read, write) = create_signal(String::new());
|
||||
|
||||
let view = view! {
|
||||
<div>
|
||||
<label
|
||||
for={&control.data.name}
|
||||
@ -43,10 +47,14 @@ impl FormStyle for TailwindGridFormStyle {
|
||||
name=control.data.name
|
||||
placeholder=control.data.placeholder
|
||||
value=control.data.initial_text
|
||||
on:change=move |ev| {
|
||||
write.set(event_target_value(&ev));
|
||||
}
|
||||
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"
|
||||
/>
|
||||
</div>
|
||||
}.into_view()
|
||||
}.into_view();
|
||||
(view, read)
|
||||
}
|
||||
|
||||
fn select<FD: FormData>(&self, control: Control<FD, Self, SelectData>) -> View {
|
||||
|
||||
Reference in New Issue
Block a user