Skip to main content

zino_dioxus/form/
field.rs

1use crate::class::Class;
2use dioxus::prelude::*;
3use zino_core::SharedString;
4
5/// A container for the form field with a label.
6pub fn FieldContainer(props: FieldContainerProps) -> Element {
7    let required_mark = props.required_mark;
8    rsx! {
9        div {
10            class: props.class,
11            label {
12                class: props.label_class,
13                { props.label.into_owned() }
14                if !required_mark.is_empty() {
15                    span {
16                        class: props.mark_class,
17                        { required_mark.into_owned() }
18                    }
19                }
20            }
21            div {
22                class: props.control_class,
23                { props.children }
24            }
25            if let Some(help_text) = props.help_text {
26                p {
27                    class: props.help_class,
28                    { help_text }
29                }
30            }
31        }
32    }
33}
34
35/// The [`FieldContainer`] properties struct for the configuration of the component.
36#[derive(Clone, PartialEq, Props)]
37pub struct FieldContainerProps {
38    /// The class attribute for the component.
39    #[props(into, default = "field")]
40    pub class: Class,
41    /// A class to apply to the `label` element.
42    #[props(into, default = "label")]
43    pub label_class: Class,
44    /// A class to apply custom styles.
45    #[props(into, default = "control")]
46    pub control_class: Class,
47    /// A class to apply to the required mark.
48    #[props(into, default = "has-text-danger")]
49    pub mark_class: Class,
50    /// A class to apply to the help text.
51    #[props(into, default = "help")]
52    pub help_class: Class,
53    /// The label content.
54    #[props(into)]
55    pub label: SharedString,
56    /// The required mark.
57    #[props(into, default)]
58    pub required_mark: SharedString,
59    /// The optional help text.
60    pub help_text: Option<Element>,
61    /// The children to render within the component.
62    children: Element,
63}
64
65/// A horizontal container for the form field with a label.
66pub fn HorizontalFieldContainer(props: HorizontalFieldContainerProps) -> Element {
67    let required_mark = props.required_mark;
68    rsx! {
69        div {
70            class: props.class,
71            div {
72                class: props.field_label_class,
73                label {
74                    class: props.label_class,
75                    { props.label.into_owned() }
76                    if !required_mark.is_empty() {
77                        span {
78                            class: props.mark_class,
79                            { required_mark.into_owned() }
80                        }
81                    }
82                }
83            }
84            div {
85                class: props.field_body_class,
86                { props.children }
87            }
88        }
89    }
90}
91
92/// The [`HorizontalFieldContainer`] properties struct for the configuration of the component.
93#[derive(Clone, PartialEq, Props)]
94pub struct HorizontalFieldContainerProps {
95    /// The class attribute for the component.
96    #[props(into, default = "field is-horizontal")]
97    pub class: Class,
98    /// A class to apply to the field label container.
99    #[props(into, default = "field-label")]
100    pub field_label_class: Class,
101    /// A class to apply to the field body container.
102    #[props(into, default = "field-body")]
103    pub field_body_class: Class,
104    /// A class to apply to the `label` element.
105    #[props(into, default = "label")]
106    pub label_class: Class,
107    /// A class to apply to the required mark.
108    #[props(into, default = "has-text-danger")]
109    pub mark_class: Class,
110    /// The label content.
111    #[props(into)]
112    pub label: SharedString,
113    /// The required mark.
114    #[props(into, default)]
115    pub required_mark: SharedString,
116    /// The children to render within the component.
117    children: Element,
118}
119
120/// A single field with the form control.
121pub fn FormField(props: FormFieldProps) -> Element {
122    rsx! {
123        div {
124            class: props.class,
125            div {
126                class: "{props.control_class}",
127                class: if props.expanded { "is-expanded" },
128                { props.children }
129            }
130            if let Some(help_text) = props.help_text {
131                p {
132                    class: props.help_class,
133                    { help_text }
134                }
135            }
136        }
137    }
138}
139
140/// The [`FormField`] properties struct for the configuration of the component.
141#[derive(Clone, PartialEq, Props)]
142pub struct FormFieldProps {
143    /// The class attribute for the component.
144    #[props(into, default = "field")]
145    pub class: Class,
146    /// A class to apply custom styles.
147    #[props(into, default = "control")]
148    pub control_class: Class,
149    /// A class to apply to the help text.
150    #[props(into, default = "help")]
151    pub help_class: Class,
152    /// A flag to determine whether the control is expanded or not.
153    #[props(default)]
154    pub expanded: bool,
155    /// The optional help text.
156    pub help_text: Option<Element>,
157    /// The children to render within the component.
158    children: Element,
159}
160
161/// Grouped fields with the form control.
162pub fn FormGroup(props: FormGroupProps) -> Element {
163    rsx! {
164        div {
165            class: "{props.class}",
166            class: if props.align == "center" { "is-grouped-centered" },
167            class: if props.align == "right" { "is-grouped-right" },
168            for item in props.items.iter() {
169                div {
170                    class: props.control_class.clone(),
171                    { item }
172                }
173            }
174        }
175    }
176}
177
178/// The [`FormGroup`] properties struct for the configuration of the component.
179#[derive(Clone, PartialEq, Props)]
180pub struct FormGroupProps {
181    /// The class attribute for the component.
182    #[props(into, default = "field is-grouped")]
183    pub class: Class,
184    /// A class to apply custom styles.
185    #[props(into, default = "control")]
186    pub control_class: Class,
187    /// The alignment of the group: `left` | `center` | `right`.
188    #[props(into, default)]
189    pub align: SharedString,
190    /// The items to be grouped.
191    #[props(into)]
192    pub items: Vec<Element>,
193}
194
195/// Attaches inputs, buttons, and dropdowns together with the form control.
196pub fn FormAddons(props: FormAddonsProps) -> Element {
197    rsx! {
198        div {
199            class: props.class,
200            for (index, item) in props.items.iter().enumerate() {
201                div {
202                    class: "{props.control_class}",
203                    class: if props.expand == index + 1 { "is-expanded" },
204                    { item }
205                }
206            }
207        }
208    }
209}
210
211/// The [`FormAddons`] properties struct for the configuration of the component.
212#[derive(Clone, PartialEq, Props)]
213pub struct FormAddonsProps {
214    /// The class attribute for the component.
215    #[props(into, default = "field has-addons")]
216    pub class: Class,
217    /// A class to apply custom styles.
218    #[props(into, default = "control")]
219    pub control_class: Class,
220    /// A modifier to expand the `n`th element to fill up the remaining space.
221    #[props(default = 0)]
222    pub expand: usize,
223    /// The items to be grouped.
224    #[props(into)]
225    pub items: Vec<Element>,
226}