dioxus_bulma/components/
input.rs1use dioxus::prelude::*;
2use crate::theme::{BulmaColor, BulmaSize};
3use crate::utils::build_class;
4
5#[derive(Debug, Clone, Copy, PartialEq)]
6pub enum InputType {
7 Text,
8 Password,
9 Email,
10 Tel,
11}
12
13impl InputType {
14 pub fn as_str(&self) -> &'static str {
15 match self {
16 InputType::Text => "text",
17 InputType::Password => "password",
18 InputType::Email => "email",
19 InputType::Tel => "tel",
20 }
21 }
22}
23
24#[derive(Props, Clone, PartialEq)]
25pub struct InputProps {
26 #[props(default = InputType::Text)]
27 pub input_type: InputType,
28 #[props(default)]
29 pub value: Option<String>,
30 #[props(default)]
31 pub placeholder: Option<String>,
32 #[props(default)]
33 pub color: Option<BulmaColor>,
34 #[props(default)]
35 pub size: Option<BulmaSize>,
36 #[props(default)]
37 pub rounded: Option<bool>,
38 #[props(default)]
39 pub loading: Option<bool>,
40 #[props(default)]
41 pub disabled: Option<bool>,
42 #[props(default)]
43 pub readonly: Option<bool>,
44 #[props(default)]
45 pub focused: Option<bool>,
46 #[props(default)]
47 pub oninput: Option<EventHandler<FormEvent>>,
48 #[props(default)]
49 pub onchange: Option<EventHandler<FormEvent>>,
50 #[props(default)]
51 pub onfocus: Option<EventHandler<FocusEvent>>,
52 #[props(default)]
53 pub onblur: Option<EventHandler<FocusEvent>>,
54 #[props(default)]
55 pub id: Option<String>,
56 #[props(default)]
57 pub class: Option<String>,
58 #[props(default)]
59 pub style: Option<String>,
60}
61
62#[component]
63pub fn Input(props: InputProps) -> Element {
64 let size = props.size.unwrap_or_default();
65 let rounded = props.rounded.unwrap_or(false);
66 let loading = props.loading.unwrap_or(false);
67 let disabled = props.disabled.unwrap_or(false);
68 let readonly = props.readonly.unwrap_or(false);
69 let focused = props.focused.unwrap_or(false);
70
71 let base_classes = vec!["input"];
72
73 let optional_classes = vec![
74 props.color.map(|c| format!("is-{}", c.as_str())),
75 if size != BulmaSize::Normal { Some(size.as_class().to_string()) } else { None },
76 if rounded { Some("is-rounded".to_string()) } else { None },
77 if loading { Some("is-loading".to_string()) } else { None },
78 if focused { Some("is-focused".to_string()) } else { None },
79 props.class.clone(),
80 ];
81
82 let final_class = build_class(&base_classes, &optional_classes);
83 let input_style = props.style.as_deref().unwrap_or("");
84
85 rsx! {
86 input {
87 r#type: props.input_type.as_str(),
88 class: "{final_class}",
89 style: "{input_style}",
90 id: props.id.clone(),
91 value: props.value.as_deref().unwrap_or(""),
92 placeholder: props.placeholder.as_deref().unwrap_or(""),
93 disabled: disabled,
94 readonly: readonly,
95 oninput: move |evt| {
96 if let Some(handler) = &props.oninput {
97 handler.call(evt);
98 }
99 },
100 onchange: move |evt| {
101 if let Some(handler) = &props.onchange {
102 handler.call(evt);
103 }
104 },
105 onfocus: move |evt| {
106 if let Some(handler) = &props.onfocus {
107 handler.call(evt);
108 }
109 },
110 onblur: move |evt| {
111 if let Some(handler) = &props.onblur {
112 handler.call(evt);
113 }
114 }
115 }
116 }
117}