use super::FormStyle; use crate::{ controls::{ button::ButtonData, checkbox::CheckboxData, heading::HeadingData, hidden::HiddenData, output::OutputData, radio_buttons::RadioButtonsData, select::SelectData, slider::SliderData, spacer::SpacerData, stepper::StepperData, submit::SubmitData, text_area::TextAreaData, text_input::TextInputData, ControlData, ControlRenderData, }, FormToolData, }; use leptos::*; use std::rc::Rc; use web_sys::MouseEvent; /// 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), /// 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)] pub struct GridFormStyle; impl FormStyle for GridFormStyle { type StylingAttributes = GFStyleAttr; fn form_frame(&self, form: ControlRenderData) -> View { view! {
{form.data}
}.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! {
{inner}
} .into_view() } fn group(&self, group: Rc>) -> View { let view = view! {
{&group.data}
} .into_view(); self.custom_component(&group.styles, view) } fn spacer(&self, control: Rc>) -> View { self.custom_component( &control.styles, view! {
}.into_view(), ) } fn heading(&self, control: Rc>) -> View { self.custom_component( &control.styles, view! {

{&control.data.title}

}.into_view(), ) } fn submit(&self, control: Rc>) -> View { self.custom_component( &control.styles, view! { } .into_view(), ) } fn button( &self, control: Rc>>, data_signal: RwSignal, ) -> 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! { } .into_view(); self.custom_component(&control.styles, view) } fn output( &self, control: Rc>, value_getter: Option>, ) -> View { let view = view! { {move || value_getter.map(|g| g.get())} }.into_view(); self.custom_component(&control.styles, view) } fn hidden( &self, control: Rc>, value_getter: Option>, ) -> View { let value_getter = move || value_getter.map(|g| g.get()); view! { } .into_view() } fn text_input( &self, control: Rc>, value_getter: Signal<::ReturnType>, value_setter: Rc::ReturnType)>, validation_state: Signal>, ) -> View { let view = view! {
{move || validation_state.get().err()}
} .into_view(); self.custom_component(&control.styles, view) } fn text_area( &self, control: Rc>, value_getter: Signal<::ReturnType>, value_setter: Rc::ReturnType)>, validation_state: Signal>, ) -> View { let view = view! {
{move || validation_state.get().err()}
} .into_view(); self.custom_component(&control.styles, view) } fn radio_buttons( &self, control: Rc>, value_getter: Signal<::ReturnType>, value_setter: Rc::ReturnType)>, validation_state: Signal>, ) -> 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! {
} }) .collect_view(); let view = view! {
{move || validation_state.get().err()}
{buttons_view}
} .into_view(); self.custom_component(&control.styles, view) } fn select( &self, control: Rc>, value_getter: Signal<::ReturnType>, value_setter: Rc::ReturnType)>, validation_state: Signal>, ) -> View { let options_view = control .data .options .iter() .map(|(display, value)| { let display = display.clone(); let value = value.clone(); view! { } }) .collect_view(); let view = view! {
{move || validation_state.get().err()}
} .into_view(); self.custom_component(&control.styles, view) } fn checkbox( &self, control: Rc>, value_getter: Signal<::ReturnType>, value_setter: Rc::ReturnType)>, ) -> View { let view = view! { } .into_view(); self.custom_component(&control.styles, view) } fn stepper( &self, control: Rc>, value_getter: Signal<::ReturnType>, value_setter: Rc::ReturnType)>, validation_state: Signal>, ) -> View { let view = view! {
{move || validation_state.get().err()}
} .into_view(); self.custom_component(&control.styles, view) } fn slider( &self, control: Rc>, value_getter: Signal<::ReturnType>, value_setter: Rc::ReturnType)>, validation_state: Signal>, ) -> View { let view = view! {
{move || validation_state.get().err()}
().ok(); if let Some(value) = value { value_setter(value); } } class="form_input" /> } .into_view(); self.custom_component(&control.styles, view) } }