dioxus_element_plug/components/
input.rs1use dioxus::prelude::*;
2pub const INPUT: &str = "el-input";
6pub const INPUT_INNER: &str = "el-input__inner";
7pub const INPUT_WRAPPER: &str = "el-input__wrapper";
8pub const INPUT_PREFIX: &str = "el-input__prefix";
9pub const INPUT_SUFFIX: &str = "el-input__suffix";
10pub const INPUT_DISABLED: &str = "is-disabled";
11pub const INPUT_LARGE: &str = "el-input--large";
12pub const INPUT_MEDIUM: &str = "el-input--medium";
13pub const INPUT_SMALL: &str = "el-input--small";
14pub const INPUT_MINI: &str = "el-input--mini";
15pub const INPUT_ERROR: &str = "is-error";
16pub const INPUT_GROUP: &str = "el-input-group";
17pub const INPUT_GROUP_APPEND: &str = "el-input-group__append";
18pub const INPUT_GROUP_PREPEND: &str = "el-input-group__prepend";
19
20#[derive(Clone, PartialEq)]
22pub enum InputSize {
23 Large,
24 Medium,
25 Small,
26 Mini,
27}
28
29impl InputSize {
30 pub fn as_class(&self) -> &'static str {
31 match self {
32 InputSize::Large => "el-input--large",
33 InputSize::Medium => "el-input--medium",
34 InputSize::Small => "el-input--small",
35 InputSize::Mini => "el-input--mini",
36 }
37 }
38}
39
40#[derive(Clone, PartialEq)]
42pub enum InputType {
43 Text,
44 Password,
45 Email,
46 Url,
47 Number,
48 Tel,
49 Search,
50 Textarea,
51}
52
53impl InputType {
54 pub fn as_str(&self) -> &'static str {
55 match self {
56 InputType::Text => "text",
57 InputType::Password => "password",
58 InputType::Email => "email",
59 InputType::Url => "url",
60 InputType::Number => "number",
61 InputType::Tel => "tel",
62 InputType::Search => "search",
63 InputType::Textarea => "textarea",
64 }
65 }
66}
67
68#[derive(Props, Clone, PartialEq)]
70pub struct InputProps {
71 #[props(default)]
73 pub value: Option<String>,
74
75 #[props(default)]
77 pub placeholder: Option<String>,
78
79 #[props(default = InputType::Text)]
81 pub input_type: InputType,
82
83 #[props(default)]
85 pub size: Option<InputSize>,
86
87 #[props(default = false)]
89 pub disabled: bool,
90
91 #[props(default = false)]
93 pub readonly: bool,
94
95 #[props(default = false)]
97 pub clearable: bool,
98
99 #[props(default = false)]
101 pub show_password: bool,
102
103 #[props(default = false)]
105 pub error: bool,
106
107 #[props(default)]
109 pub label: Option<String>,
110
111 #[props(default)]
113 pub prefix_icon: Option<String>,
114
115 #[props(default)]
117 pub suffix_icon: Option<String>,
118
119 #[props(default)]
121 pub maxlength: Option<u32>,
122
123 #[props(default)]
125 pub minlength: Option<u32>,
126
127 #[props(default = false)]
129 pub autofocus: bool,
130
131 #[props(default)]
133 pub name: Option<String>,
134
135 #[props(default)]
137 pub id: Option<String>,
138
139 #[props(default)]
141 pub on_input: Option<EventHandler<FormEvent>>,
142
143 #[props(default)]
145 pub on_change: Option<EventHandler<FormEvent>>,
146
147 #[props(default)]
149 pub on_focus: Option<EventHandler<FocusEvent>>,
150
151 #[props(default)]
153 pub on_blur: Option<EventHandler<FocusEvent>>,
154
155 #[props(default)]
157 pub on_keydown: Option<EventHandler<KeyboardEvent>>,
158
159 #[props(default)]
161 pub class: Option<String>,
162
163 #[props(default)]
165 pub style: Option<String>,
166}
167
168#[component]
188pub fn Input(props: InputProps) -> Element {
189 let base_class = "el-input";
190 let mut wrapper_classes = vec![base_class];
191
192 if let Some(size) = &props.size {
193 wrapper_classes.push(size.as_class());
194 }
195
196 if props.disabled {
197 wrapper_classes.push("is-disabled");
198 }
199
200 if props.error {
201 wrapper_classes.push("is-error");
202 }
203
204 let wrapper_class_string = wrapper_classes.join(" ");
205
206 let input_class = "el-input__inner";
207
208 let input_element = if props.input_type == InputType::Textarea {
209 rsx! {
210 textarea {
211 class: "{input_class}",
212 value: props.value.unwrap_or_default(),
213 placeholder: props.placeholder.unwrap_or_default(),
214 disabled: props.disabled,
215 readonly: props.readonly,
216 maxlength: props.maxlength.map(|n| n.to_string()).unwrap_or_default(),
217 minlength: props.minlength.map(|n| n.to_string()).unwrap_or_default(),
218 autofocus: props.autofocus,
219 name: props.name.unwrap_or_default(),
220 id: props.id.unwrap_or_default(),
221 style: props.style.unwrap_or_default(),
222 oninput: move |event| {
223 if let Some(handler) = props.on_input {
224 handler.call(event);
225 }
226 },
227 onchange: move |event| {
228 if let Some(handler) = props.on_change {
229 handler.call(event);
230 }
231 },
232 onfocus: move |event| {
233 if let Some(handler) = props.on_focus {
234 handler.call(event);
235 }
236 },
237 onblur: move |event| {
238 if let Some(handler) = props.on_blur {
239 handler.call(event);
240 }
241 },
242 onkeydown: move |event| {
243 if let Some(handler) = props.on_keydown {
244 handler.call(event);
245 }
246 },
247 }
248 }
249 } else {
250 rsx! {
251 input {
252 class: "{input_class}",
253 r#type: props.input_type.as_str(),
254 value: props.value.unwrap_or_default(),
255 placeholder: props.placeholder.unwrap_or_default(),
256 disabled: props.disabled,
257 readonly: props.readonly,
258 maxlength: props.maxlength.map(|n| n.to_string()).unwrap_or_default(),
259 minlength: props.minlength.map(|n| n.to_string()).unwrap_or_default(),
260 autofocus: props.autofocus,
261 name: props.name.unwrap_or_default(),
262 id: props.id.unwrap_or_default(),
263 style: props.style.unwrap_or_default(),
264 oninput: move |event| {
265 if let Some(handler) = props.on_input {
266 handler.call(event);
267 }
268 },
269 onchange: move |event| {
270 if let Some(handler) = props.on_change {
271 handler.call(event);
272 }
273 },
274 onfocus: move |event| {
275 if let Some(handler) = props.on_focus {
276 handler.call(event);
277 }
278 },
279 onblur: move |event| {
280 if let Some(handler) = props.on_blur {
281 handler.call(event);
282 }
283 },
284 onkeydown: move |event| {
285 if let Some(handler) = props.on_keydown {
286 handler.call(event);
287 }
288 },
289 }
290 }
291 };
292
293 rsx! {
294 div {
295 class: "{wrapper_class_string}",
296
297 if let Some(ref label) = props.label {
298 label {
299 class: "el-form-item__label",
300 "{label}"
301 }
302 }
303
304 div {
305 class: "el-input__wrapper",
306
307 if let Some(ref prefix_icon) = props.prefix_icon {
308 span {
309 class: "el-input__prefix",
310 i {
311 class: "{prefix_icon} el-input__icon"
312 }
313 }
314 }
315
316 {input_element}
317
318 if props.clearable {
319 span {
320 class: "el-input__suffix",
321 i {
322 class: "el-input__icon el-icon-circle-close"
323 }
324 }
325 }
326
327 if props.show_password && props.input_type == InputType::Password {
328 span {
329 class: "el-input__suffix",
330 i {
331 class: "el-input__icon el-icon-view"
332 }
333 }
334 }
335
336 if let Some(ref suffix_icon) = props.suffix_icon {
337 span {
338 class: "el-input__suffix",
339 i {
340 class: "{suffix_icon} el-input__icon"
341 }
342 }
343 }
344 }
345 }
346 }
347}
348
349#[component]
351pub fn SearchInput(props: InputProps) -> Element {
352 let mut props = props;
353 if props.suffix_icon.is_none() {
354 props.suffix_icon = Some("el-icon-search".to_string());
355 }
356 Input(props)
357}
358
359#[component]
361pub fn PasswordInput(props: InputProps) -> Element {
362 let mut props = props;
363 props.input_type = InputType::Password;
364 props.show_password = true;
365 Input(props)
366}