dioxus_ui_system/atoms/
input.rs1use dioxus::prelude::*;
6use crate::theme::use_style;
7use crate::styles::Style;
8
9#[derive(Default, Clone, PartialEq)]
11pub enum InputType {
12 #[default]
13 Text,
14 Password,
15 Email,
16 Number,
17 Tel,
18 Url,
19 Search,
20 Date,
21 Time,
22 DatetimeLocal,
23 Month,
24 Week,
25 Color,
26}
27
28impl InputType {
29 pub fn as_str(&self) -> &'static str {
30 match self {
31 InputType::Text => "text",
32 InputType::Password => "password",
33 InputType::Email => "email",
34 InputType::Number => "number",
35 InputType::Tel => "tel",
36 InputType::Url => "url",
37 InputType::Search => "search",
38 InputType::Date => "date",
39 InputType::Time => "time",
40 InputType::DatetimeLocal => "datetime-local",
41 InputType::Month => "month",
42 InputType::Week => "week",
43 InputType::Color => "color",
44 }
45 }
46}
47
48#[derive(Props, Clone, PartialEq)]
50pub struct InputProps {
51 #[props(default)]
53 pub value: String,
54 #[props(default)]
56 pub placeholder: Option<String>,
57 #[props(default)]
59 pub input_type: InputType,
60 #[props(default)]
62 pub disabled: bool,
63 #[props(default)]
65 pub readonly: bool,
66 #[props(default)]
68 pub required: bool,
69 #[props(default)]
71 pub autofocus: bool,
72 #[props(default)]
74 pub onchange: Option<EventHandler<String>>,
75 #[props(default)]
77 pub onfocus: Option<EventHandler<FocusEvent>>,
78 #[props(default)]
80 pub onblur: Option<EventHandler<FocusEvent>>,
81 #[props(default)]
83 pub oninput: Option<EventHandler<FormEvent>>,
84 #[props(default)]
86 pub style: Option<String>,
87 #[props(default)]
89 pub class: Option<String>,
90 #[props(default)]
92 pub name: Option<String>,
93 #[props(default)]
95 pub id: Option<String>,
96}
97
98#[component]
115pub fn Input(props: InputProps) -> Element {
116 let disabled = props.disabled;
117 let readonly = props.readonly;
118
119 let mut is_focused = use_signal(|| false);
121 let mut is_hovered = use_signal(|| false);
122
123 let style = use_style(move |t| {
125 let base = Style::new()
126 .flex()
127 .w_full()
128 .h_px(40)
129 .rounded(&t.radius, "md")
130 .border(1, if is_focused() { &t.colors.ring } else { &t.colors.border })
131 .bg(&t.colors.background)
132 .text_color(&t.colors.foreground)
133 .px(&t.spacing, "md")
134 .text(&t.typography, "sm")
135 .transition("all 150ms cubic-bezier(0.4, 0, 0.2, 1)")
136 .outline("none");
137
138 let base = if disabled || readonly {
140 base.cursor("not-allowed")
141 .opacity(0.5)
142 .bg(&t.colors.muted)
143 } else {
144 base.cursor("text")
145 .opacity(1.0)
146 };
147
148 let base = if is_focused() && !disabled {
150 Style {
151 box_shadow: Some(format!("0 0 0 1px {}", t.colors.ring.to_rgba())),
152 ..base
153 }
154 } else {
155 base
156 };
157
158 let base = if is_hovered() && !is_focused() && !disabled {
160 base.border_color(&t.colors.foreground.darken(0.2))
161 } else {
162 base
163 };
164
165 base.build()
166 });
167
168 let final_style = if let Some(custom) = &props.style {
170 format!("{} {}", style(), custom)
171 } else {
172 style()
173 };
174
175 let class = props.class.clone().unwrap_or_default();
176 let input_type = props.input_type.clone();
177 let placeholder = props.placeholder.clone();
178 let name = props.name.clone();
179 let id = props.id.clone();
180 let value = props.value.clone();
181 let required = props.required;
182 let autofocus = props.autofocus;
183 let readonly = props.readonly;
184 let disabled = props.disabled;
185
186 rsx! {
187 input {
188 r#type: input_type.as_str(),
189 style: "{final_style}",
190 class: "{class}",
191 value: "{value}",
192 placeholder: placeholder,
193 name: name,
194 id: id,
195 required: required,
196 autofocus: autofocus,
197 readonly: readonly,
198 disabled: disabled,
199 onmouseenter: move |_| is_hovered.set(true),
200 onmouseleave: move |_| is_hovered.set(false),
201 onfocus: move |e| {
202 is_focused.set(true);
203 if let Some(handler) = &props.onfocus {
204 handler.call(e);
205 }
206 },
207 onblur: move |e| {
208 is_focused.set(false);
209 if let Some(handler) = &props.onblur {
210 handler.call(e);
211 }
212 },
213 oninput: move |e| {
214 if let Some(handler) = &props.oninput {
215 handler.call(e);
216 }
217 },
218 onchange: move |e| {
219 if let Some(handler) = &props.onchange {
220 handler.call(e.value());
221 }
222 },
223 }
224 }
225}
226
227