dioxus_ui_system/atoms/
input.rs1use crate::styles::Style;
6use crate::theme::use_style;
7use dioxus::prelude::*;
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(
131 1,
132 if is_focused() {
133 &t.colors.ring
134 } else {
135 &t.colors.border
136 },
137 )
138 .bg(&t.colors.background)
139 .text_color(&t.colors.foreground)
140 .px(&t.spacing, "md")
141 .text(&t.typography, "sm")
142 .transition("all 150ms cubic-bezier(0.4, 0, 0.2, 1)")
143 .outline("none");
144
145 let base = if disabled || readonly {
147 base.cursor("not-allowed").opacity(0.5).bg(&t.colors.muted)
148 } else {
149 base.cursor("text").opacity(1.0)
150 };
151
152 let base = if is_focused() && !disabled {
154 Style {
155 box_shadow: Some(format!("0 0 0 1px {}", t.colors.ring.to_rgba())),
156 ..base
157 }
158 } else {
159 base
160 };
161
162 let base = if is_hovered() && !is_focused() && !disabled {
164 base.border_color(&t.colors.foreground.darken(0.2))
165 } else {
166 base
167 };
168
169 base.build()
170 });
171
172 let final_style = if let Some(custom) = &props.style {
174 format!("{} {}", style(), custom)
175 } else {
176 style()
177 };
178
179 let class = props.class.clone().unwrap_or_default();
180 let input_type = props.input_type.clone();
181 let placeholder = props.placeholder.clone();
182 let name = props.name.clone();
183 let id = props.id.clone();
184 let value = props.value.clone();
185 let required = props.required;
186 let autofocus = props.autofocus;
187 let readonly = props.readonly;
188 let disabled = props.disabled;
189
190 rsx! {
191 input {
192 r#type: input_type.as_str(),
193 style: "{final_style}",
194 class: "{class}",
195 value: "{value}",
196 placeholder: placeholder,
197 name: name,
198 id: id,
199 required: required,
200 autofocus: autofocus,
201 readonly: readonly,
202 disabled: disabled,
203 onmouseenter: move |_| is_hovered.set(true),
204 onmouseleave: move |_| is_hovered.set(false),
205 onfocus: move |e| {
206 is_focused.set(true);
207 if let Some(handler) = &props.onfocus {
208 handler.call(e);
209 }
210 },
211 onblur: move |e| {
212 is_focused.set(false);
213 if let Some(handler) = &props.onblur {
214 handler.call(e);
215 }
216 },
217 oninput: move |e| {
218 if let Some(handler) = &props.oninput {
219 handler.call(e);
220 }
221 },
222 onchange: move |e| {
223 if let Some(handler) = &props.onchange {
224 handler.call(e.value());
225 }
226 },
227 }
228 }
229}
230
231