use dioxus::prelude::*;
use crate::types::Size;
#[derive(Clone, PartialEq, Props)]
pub struct FormGroupProps {
#[props(default)]
pub label: String,
#[props(default)]
pub class: String,
#[props(extends = GlobalAttributes)]
attributes: Vec<Attribute>,
pub children: Element,
}
#[component]
pub fn FormGroup(props: FormGroupProps) -> Element {
let full_class = if props.class.is_empty() {
"mb-3".to_string()
} else {
format!("mb-3 {}", props.class)
};
rsx! {
div { class: "{full_class}",
..props.attributes,
if !props.label.is_empty() {
label { class: "form-label", "{props.label}" }
}
{props.children}
}
}
}
#[derive(Clone, PartialEq, Props)]
pub struct InputProps {
#[props(default = "text".to_string())]
pub r#type: String,
#[props(default)]
pub value: String,
#[props(default)]
pub placeholder: String,
#[props(default)]
pub size: Size,
#[props(default)]
pub disabled: bool,
#[props(default)]
pub readonly: bool,
#[props(default)]
pub oninput: Option<EventHandler<FormEvent>>,
#[props(default)]
pub class: String,
#[props(extends = GlobalAttributes)]
attributes: Vec<Attribute>,
}
#[component]
pub fn Input(props: InputProps) -> Element {
let size_class = match props.size {
Size::Md => String::new(),
s => format!(" form-control-{s}"),
};
let full_class = if props.class.is_empty() {
format!("form-control{size_class}")
} else {
format!("form-control{size_class} {}", props.class)
};
rsx! {
input {
class: "{full_class}",
r#type: "{props.r#type}",
value: "{props.value}",
placeholder: "{props.placeholder}",
disabled: props.disabled,
readonly: props.readonly,
oninput: move |evt| {
if let Some(handler) = &props.oninput {
handler.call(evt);
}
},
..props.attributes,
}
}
}
#[derive(Clone, PartialEq, Props)]
pub struct SelectProps {
#[props(default)]
pub value: String,
#[props(default)]
pub size: Size,
#[props(default)]
pub disabled: bool,
#[props(default)]
pub onchange: Option<EventHandler<FormEvent>>,
#[props(default)]
pub class: String,
#[props(extends = GlobalAttributes)]
attributes: Vec<Attribute>,
pub children: Element,
}
#[component]
pub fn Select(props: SelectProps) -> Element {
let size_class = match props.size {
Size::Md => String::new(),
s => format!(" form-select-{s}"),
};
let full_class = if props.class.is_empty() {
format!("form-select{size_class}")
} else {
format!("form-select{size_class} {}", props.class)
};
rsx! {
select {
class: "{full_class}",
value: "{props.value}",
disabled: props.disabled,
onchange: move |evt| {
if let Some(handler) = &props.onchange {
handler.call(evt);
}
},
..props.attributes,
{props.children}
}
}
}
#[derive(Clone, PartialEq, Props)]
pub struct TextareaProps {
#[props(default)]
pub value: String,
#[props(default = 3)]
pub rows: u32,
#[props(default)]
pub placeholder: String,
#[props(default)]
pub disabled: bool,
#[props(default)]
pub readonly: bool,
#[props(default)]
pub oninput: Option<EventHandler<FormEvent>>,
#[props(default)]
pub class: String,
#[props(extends = GlobalAttributes)]
attributes: Vec<Attribute>,
}
#[component]
pub fn Textarea(props: TextareaProps) -> Element {
let full_class = if props.class.is_empty() {
"form-control".to_string()
} else {
format!("form-control {}", props.class)
};
rsx! {
textarea {
class: "{full_class}",
rows: "{props.rows}",
placeholder: "{props.placeholder}",
disabled: props.disabled,
readonly: props.readonly,
value: "{props.value}",
oninput: move |evt| {
if let Some(handler) = &props.oninput {
handler.call(evt);
}
},
..props.attributes,
}
}
}
#[derive(Clone, PartialEq, Props)]
pub struct CheckboxProps {
#[props(default)]
pub checked: bool,
#[props(default)]
pub label: String,
#[props(default)]
pub disabled: bool,
#[props(default)]
pub onchange: Option<EventHandler<FormEvent>>,
#[props(default)]
pub class: String,
#[props(extends = GlobalAttributes)]
attributes: Vec<Attribute>,
}
#[component]
pub fn Checkbox(props: CheckboxProps) -> Element {
let full_class = if props.class.is_empty() {
"form-check".to_string()
} else {
format!("form-check {}", props.class)
};
rsx! {
div { class: "{full_class}",
..props.attributes,
input {
class: "form-check-input",
r#type: "checkbox",
checked: props.checked,
disabled: props.disabled,
onchange: move |evt| {
if let Some(handler) = &props.onchange {
handler.call(evt);
}
},
}
if !props.label.is_empty() {
label { class: "form-check-label", "{props.label}" }
}
}
}
}
#[derive(Clone, PartialEq, Props)]
pub struct SwitchProps {
#[props(default)]
pub checked: bool,
#[props(default)]
pub label: String,
#[props(default)]
pub disabled: bool,
#[props(default)]
pub onchange: Option<EventHandler<FormEvent>>,
#[props(default)]
pub class: String,
#[props(extends = GlobalAttributes)]
attributes: Vec<Attribute>,
}
#[component]
pub fn Switch(props: SwitchProps) -> Element {
let full_class = if props.class.is_empty() {
"form-check form-switch".to_string()
} else {
format!("form-check form-switch {}", props.class)
};
rsx! {
div { class: "{full_class}",
..props.attributes,
input {
class: "form-check-input",
r#type: "checkbox",
role: "switch",
checked: props.checked,
disabled: props.disabled,
onchange: move |evt| {
if let Some(handler) = &props.onchange {
handler.call(evt);
}
},
}
if !props.label.is_empty() {
label { class: "form-check-label", "{props.label}" }
}
}
}
}
#[derive(Clone, PartialEq, Props)]
pub struct RangeProps {
#[props(default)]
pub value: String,
#[props(default = "0".to_string())]
pub min: String,
#[props(default = "100".to_string())]
pub max: String,
#[props(default)]
pub step: String,
#[props(default)]
pub disabled: bool,
#[props(default)]
pub oninput: Option<EventHandler<FormEvent>>,
#[props(default)]
pub class: String,
#[props(extends = GlobalAttributes)]
attributes: Vec<Attribute>,
}
#[component]
pub fn Range(props: RangeProps) -> Element {
let full_class = if props.class.is_empty() {
"form-range".to_string()
} else {
format!("form-range {}", props.class)
};
rsx! {
input {
class: "{full_class}",
r#type: "range",
value: "{props.value}",
min: "{props.min}",
max: "{props.max}",
step: if props.step.is_empty() { None } else { Some(props.step.clone()) },
disabled: props.disabled,
oninput: move |evt| {
if let Some(handler) = &props.oninput {
handler.call(evt);
}
},
..props.attributes,
}
}
}
#[derive(Clone, PartialEq, Props)]
pub struct FloatingLabelProps {
pub label: String,
#[props(default)]
pub class: String,
#[props(extends = GlobalAttributes)]
attributes: Vec<Attribute>,
pub children: Element,
}
#[component]
pub fn FloatingLabel(props: FloatingLabelProps) -> Element {
let full_class = if props.class.is_empty() {
"form-floating".to_string()
} else {
format!("form-floating {}", props.class)
};
rsx! {
div { class: "{full_class}",
..props.attributes,
{props.children}
label { "{props.label}" }
}
}
}
#[derive(Clone, PartialEq, Props)]
pub struct FormFeedbackProps {
#[props(default)]
pub valid: bool,
#[props(default)]
pub class: String,
#[props(extends = GlobalAttributes)]
attributes: Vec<Attribute>,
pub children: Element,
}
#[component]
pub fn FormFeedback(props: FormFeedbackProps) -> Element {
let base = if props.valid {
"valid-feedback"
} else {
"invalid-feedback"
};
let full_class = if props.class.is_empty() {
base.to_string()
} else {
format!("{base} {}", props.class)
};
rsx! {
div { class: "{full_class}", ..props.attributes, {props.children} }
}
}
#[derive(Clone, PartialEq, Props)]
pub struct FormTextProps {
#[props(default)]
pub class: String,
#[props(extends = GlobalAttributes)]
attributes: Vec<Attribute>,
pub children: Element,
}
#[component]
pub fn FormText(props: FormTextProps) -> Element {
let full_class = if props.class.is_empty() {
"form-text".to_string()
} else {
format!("form-text {}", props.class)
};
rsx! {
div { class: "{full_class}", ..props.attributes, {props.children} }
}
}
#[derive(Clone, PartialEq, Props)]
pub struct RadioProps {
pub name: String,
#[props(default)]
pub checked: bool,
#[props(default)]
pub label: String,
#[props(default)]
pub disabled: bool,
#[props(default)]
pub onchange: Option<EventHandler<FormEvent>>,
#[props(default)]
pub class: String,
#[props(extends = GlobalAttributes)]
attributes: Vec<Attribute>,
}
#[component]
pub fn Radio(props: RadioProps) -> Element {
let full_class = if props.class.is_empty() {
"form-check".to_string()
} else {
format!("form-check {}", props.class)
};
rsx! {
div { class: "{full_class}",
..props.attributes,
input {
class: "form-check-input",
r#type: "radio",
name: "{props.name}",
checked: props.checked,
disabled: props.disabled,
onchange: move |evt| {
if let Some(handler) = &props.onchange {
handler.call(evt);
}
},
}
if !props.label.is_empty() {
label { class: "form-check-label", "{props.label}" }
}
}
}
}