Skip to main content

dioxus_bulma/components/
input.rs

1use 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}