Skip to content

Commit 1321d99

Browse files
committed
add support for textarea & password field with end icon toggle
1 parent 15802c1 commit 1321d99

File tree

6 files changed

+90
-14
lines changed

6 files changed

+90
-14
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "input_yew"
3-
version = "0.1.3"
3+
version = "0.1.4"
44
description = "A feature-rich accessible custom reusable input functional component for the Yew framework."
55
license = "Apache-2.0"
66
keywords = ["input", "yew", "rust", "input_yew"]

README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# 💡 Input Yew
22

3-
![demo](./assets/demo.gif)
3+
![text-demo](./assets/text-demo.gif)
4+
![pass-demo](./assets/pass-demo.gif)
5+
![textarea-demo](./assets/textarea-demo.gif)
46

57
## 📜 Prologue
68

assets/pass-demo.gif

302 KB
Loading
File renamed without changes.

assets/textarea-demo.gif

667 KB
Loading

src/lib.rs

+86-12
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use yew::prelude::*;
44
/// Props for a custom input component.
55
#[derive(Properties, PartialEq)]
66
pub struct Props {
7-
/// The type of the input, e.g., "text", "email", "password", etc.
7+
/// The type of the input, e.g., "text", "password", etc.
88
pub input_type: Option<String>,
99

1010
/// The label to be displayed for the input field.
@@ -13,9 +13,6 @@ pub struct Props {
1313
/// The name of the input field, used for form submission and accessibility.
1414
pub name: String,
1515

16-
/// The icon class to be used for displaying an icon alongside the input.
17-
pub icon: String,
18-
1916
/// Indicates whether the input is required or not.
2017
pub required: bool,
2118

@@ -52,6 +49,12 @@ pub struct Props {
5249
/// A callback function to validate the input value. It takes a `String` as input and returns a `bool`.
5350
pub validate_function: Callback<String, bool>,
5451

52+
/// The icon when the password is visible.
53+
pub eye_active: Option<String>,
54+
55+
/// The icon when the password is not visible.
56+
pub eye_disabled: Option<String>,
57+
5558
// Additional props for accessibility and SEO:
5659
/// The ID attribute of the input element.
5760
pub input_id: Option<String>,
@@ -117,7 +120,6 @@ pub struct Props {
117120
/// input_ref={input_email_ref}
118121
/// input_placeholder={"Email".to_string()}
119122
/// icon_class={"fas fa-user".to_string()}
120-
/// icon={"fas fa-user".to_string()}
121123
/// error_message={"Enter a valid email address".to_string()}
122124
/// form_input_class={"".to_string()}
123125
/// form_input_field_class={"form-one-field".to_string()}
@@ -134,13 +136,30 @@ pub struct Props {
134136
/// ```
135137
#[function_component(CustomInput)]
136138
pub fn custom_input(props: &Props) -> Html {
139+
140+
let eye_active_handle = use_state(|| false);
141+
let eye_active = (*eye_active_handle).clone();
142+
143+
let password_type_handle = use_state(|| "password");
144+
let password_type = (*password_type_handle).clone();
145+
137146
let input_valid = *props.input_valid_handle;
138147

139148
let aria_invalid = props
140149
.aria_invalid
141150
.clone()
142151
.unwrap_or_else(|| "true".to_string());
143152

153+
let eye_icon_active = props
154+
.eye_active
155+
.clone()
156+
.unwrap_or_else(|| "fa fa-eye".to_string());
157+
158+
let eye_icon_disabled = props
159+
.eye_disabled
160+
.clone()
161+
.unwrap_or_else(|| "fa fa-eye-slash".to_string());
162+
144163
let aria_required = props
145164
.aria_required
146165
.clone()
@@ -166,14 +185,22 @@ pub fn custom_input(props: &Props) -> Html {
166185
})
167186
};
168187

169-
html! {
170-
<div class={props.form_input_class.clone()}>
171-
<label class={props.form_input_label_class.clone()} for={props.input_id.clone()}>
172-
{&props.label}
173-
</label>
174-
<div class={props.form_input_field_class.clone()}>
188+
let on_toggle_password = {
189+
Callback::from(move |_| {
190+
if eye_active {
191+
password_type_handle.set("password".into())
192+
} else {
193+
password_type_handle.set("text".into())
194+
}
195+
eye_active_handle.set(!eye_active);
196+
})
197+
};
198+
199+
let input_tag = match (*input_type).into() {
200+
"password" => html! {
201+
<>
175202
<input
176-
type={input_type}
203+
type={password_type}
177204
class={props.form_input_input_class.clone()}
178205
id={props.input_id.clone()}
179206
name={props.name.clone()}
@@ -186,6 +213,53 @@ pub fn custom_input(props: &Props) -> Html {
186213
oninput={onchange}
187214
required={props.required}
188215
/>
216+
<span
217+
class={format!("toggle-button {}", if eye_active { eye_icon_active } else { eye_icon_disabled })}
218+
onclick={on_toggle_password}
219+
></span>
220+
</>
221+
},
222+
"textarea" => html! {
223+
<textarea
224+
class={props.form_input_input_class.clone()}
225+
id={props.input_id.clone()}
226+
name={props.name.clone()}
227+
ref={props.input_ref.clone()}
228+
placeholder={props.input_placeholder.clone()}
229+
aria-label={props.aria_label.clone()}
230+
aria-required={aria_required}
231+
aria-invalid={aria_invalid}
232+
aria-describedby={props.aria_describedby.clone()}
233+
oninput={onchange}
234+
required={props.required}
235+
>
236+
</textarea>
237+
},
238+
_ => html! {
239+
<input
240+
type={input_type}
241+
class={props.form_input_input_class.clone()}
242+
id={props.input_id.clone()}
243+
name={props.name.clone()}
244+
ref={props.input_ref.clone()}
245+
placeholder={props.input_placeholder.clone()}
246+
aria-label={props.aria_label.clone()}
247+
aria-required={aria_required}
248+
aria-invalid={aria_invalid}
249+
aria-describedby={props.aria_describedby.clone()}
250+
oninput={onchange}
251+
required={props.required}
252+
/>
253+
}
254+
};
255+
256+
html! {
257+
<div class={props.form_input_class.clone()}>
258+
<label class={props.form_input_label_class.clone()} for={props.input_id.clone()}>
259+
{&props.label}
260+
</label>
261+
<div class={props.form_input_field_class.clone()}>
262+
{ input_tag }
189263
<span class={props.icon_class.clone()}></span>
190264
</div>
191265
if !input_valid {

0 commit comments

Comments
 (0)