-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 123f62d
Showing
3 changed files
with
318 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
[package] | ||
name = "input_yew" | ||
version = "0.1.0" | ||
description = "An SEO-optimized, accessible, and feature-rich custom reusable input functional component designed specifically for the Rust Yew framework, elevating user interfaces and interactions." | ||
license = "Apache-2.0" | ||
keywords = ["input", "yew", "rust", "input_yew"] | ||
repository = "https://github.com/wiseaidev/input-yew" | ||
documentation = "https://docs.rs/input_yew/" | ||
authors = ["Mahmoud Harmouch <[email protected]>"] | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
yew = { version = "0.20.0", default-features = false } | ||
|
||
[profile.release] | ||
codegen-units = 1 | ||
opt-level = "z" | ||
lto = "thin" | ||
strip = "symbols" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
# 💡 Input Yew | ||
|
||
## 📜 Prologue | ||
|
||
This custom reusable input functional component is a solution built exclusively for the Rust Yew framework. Seamlessly integrating into your Yew applications, it combines powerful functionality with SEO optimization and comprehensive accessibility features. With a focus on reusability and customizability, this component empowers you to effortlessly create dynamic input fields that adapt to various forms of user input. | ||
|
||
## 🤔 Why is this Component Useful? | ||
|
||
The Yew Custom Reusable Input Component is a powerful tool designed to make your life as a Yew developer easier and more enjoyable. Let's explore some of the reasons why this component is an essential addition to your web development arsenal: | ||
|
||
1. 🔄 Reusability: No repetitive code! This component is built to be highly reusable, allowing you to sprinkle it across your application without any fuss. | ||
|
||
1. 🎨 Customizability: You can now fine-tune the appearance and behavior of the input component to fit your specific needs and aesthetics. | ||
|
||
1. ✔️ Validations: You can easily add your custom validation functions. | ||
|
||
1. 🎫 Event Handling: The component exposes the `oninput` event handler, making it super easy to implement dynamic behavior based on your interactions. | ||
|
||
1. ♿ Accessibility: This compoenent was designed with accessibility in mind, ensuring that it's user-friendly and perceivable by all, regardless of ability. | ||
|
||
1. ❌ Error Handling: When users provide invalid input, the component gracefully displays clear error messages, guiding them towards valid data entry and enhancing the overall user experience. | ||
|
||
## Installation ⚙️ | ||
|
||
You can quickly integrate the Yew Custom Reusable Input Component into your Yew project by following these simple steps: | ||
|
||
1. First, make sure you have Yew set up in your project. If not, check out the [Yew documentation](https://yew.rs/docs/getting-started/introduction) for installation instructions. | ||
|
||
2. Then, install the input component package using your preferred package manager: | ||
|
||
```bash | ||
$ cargo add input-yew | ||
``` | ||
|
||
3. Finally, import the component into your Yew application and start using it to power up your forms and user interactions. | ||
|
||
## 🛠️ Usage | ||
|
||
Using this custom reusable input component is a breeze! Simply follow these steps: | ||
|
||
1. Import the component into your Yew application: | ||
|
||
```rust | ||
// Add these lines at the beginning of your file | ||
use yew::prelude::*; | ||
use input_yew::CustomInput; | ||
``` | ||
|
||
1. Use the `CustomInput` component wherever you need an input field: | ||
|
||
```rust | ||
fn validate_email(email: String) -> bool { | ||
let pattern = Regex::new(r"^[^ ]+@[^ ]+\.[a-z]{2,3}$").unwrap(); | ||
pattern.is_match(&email) | ||
} | ||
|
||
|
||
#[function_component(LoginForm)] | ||
pub fn login_form() -> Html { | ||
let input_email_ref = use_node_ref(); | ||
let input_email_handle = use_state(String::default); | ||
let email_valid_handle = use_state(|| true); | ||
let onsubmit = Callback::from(move |event: SubmitEvent| {}; | ||
html! { | ||
<form action="#" aria-label="Sign In Form" onsubmit={onsubmit}> | ||
<CustomInput | ||
input_type={Some("text".to_string())} | ||
label={"".to_string()} | ||
input_handle={input_email_handle} | ||
name={"email".to_string()} | ||
input_ref={input_email_ref} | ||
input_placeholder={"Email".to_string()} | ||
icon_class={"fas fa-user".to_string()} | ||
icon={"fas fa-user".to_string()} | ||
error_message={"Enter a valid email address".to_string()} | ||
form_input_class={"".to_string()} | ||
form_input_field_class={"form-one-field".to_string()} | ||
form_input_label_class={"".to_string()} | ||
form_input_input_class={"".to_string()} | ||
form_input_error_class={"error-txt".to_string()} | ||
required={true} | ||
input_valid_handle={email_valid_handle} | ||
validate_function={validate_email} | ||
/> | ||
</form> | ||
} | ||
} | ||
``` | ||
|
||
1. Customize the input component's appearance and behavior according to your project requirements. | ||
|
||
## Contribution 🤝 | ||
|
||
We welcome contributions from the community to make the Input Yew even better! Feel free to open issues, submit pull requests, or provide feedback. Let's collaborate and create something amazing together! | ||
|
||
## License 📜 | ||
|
||
The Yew Custom Reusable Input Component is licensed under the `Apache-2.0` License, giving you the freedom to use, modify, and distribute it as you see fit. Please check the `LICENSE` file for more details. | ||
|
||
## Epilogue 📝 | ||
|
||
Congratulations! You're now equipped with a fantastic Yew Custom Reusable Input Component that will supercharge your web applications with its flexibility, user-friendliness, and robustness. Happy coding, and may your projects thrive with this powerful tool! 🎉 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
use web_sys::HtmlInputElement; | ||
use yew::prelude::*; | ||
|
||
/// Props for a custom input component. | ||
#[derive(Properties, PartialEq)] | ||
pub struct Props { | ||
/// The type of the input, e.g., "text", "email", "password", etc. | ||
pub input_type: Option<String>, | ||
|
||
/// The label to be displayed for the input field. | ||
pub label: String, | ||
|
||
/// The name of the input field, used for form submission and accessibility. | ||
pub name: String, | ||
|
||
/// The icon class to be used for displaying an icon alongside the input. | ||
pub icon: String, | ||
|
||
/// Indicates whether the input is required or not. | ||
pub required: bool, | ||
|
||
/// A reference to the DOM node of the input element. | ||
pub input_ref: NodeRef, | ||
|
||
/// The error message to display when there is a validation error. | ||
pub error_message: String, | ||
|
||
/// The CSS class to be applied to all inner elements. | ||
pub form_input_class: String, | ||
|
||
/// The CSS class to be applied to the inner input element and icon. | ||
pub form_input_field_class: String, | ||
|
||
/// The CSS class to be applied to the label for the input element. | ||
pub form_input_label_class: String, | ||
|
||
/// The CSS class to be applied to the input element. | ||
pub form_input_input_class: String, | ||
|
||
/// The CSS class to be applied to the error div element. | ||
pub form_input_error_class: String, | ||
|
||
/// The CSS class to be applied to the icon element. | ||
pub icon_class: String, | ||
|
||
/// The state handle for managing the value of the input. | ||
pub input_handle: UseStateHandle<String>, | ||
|
||
/// The state handle for managing the validity state of the input. | ||
pub input_valid_handle: UseStateHandle<bool>, | ||
|
||
/// A callback function to validate the input value. It takes a `String` as input and returns a `bool`. | ||
pub validate_function: Callback<String, bool>, | ||
|
||
// Additional props for accessibility and SEO: | ||
/// The ID attribute of the input element. | ||
pub input_id: Option<String>, | ||
|
||
/// The placeholder text to be displayed in the input element. | ||
pub input_placeholder: Option<String>, | ||
|
||
/// The aria-label attribute for screen readers, providing a label for accessibility. | ||
pub aria_label: Option<String>, | ||
|
||
/// The aria-required attribute for screen readers, indicating whether the input is required. | ||
pub aria_required: Option<String>, | ||
|
||
/// The aria-invalid attribute for screen readers, indicating whether the input value is invalid. | ||
pub aria_invalid: Option<String>, | ||
|
||
/// The aria-describedby attribute for screen readers, describing the input element's error message. | ||
pub aria_describedby: Option<String>, | ||
} | ||
|
||
/// custom_input_component | ||
/// A custom input component that handles user input and validation. | ||
/// | ||
/// # Arguments | ||
/// * `props` - The properties of the component. | ||
/// - `input_valid_handle` - A handle to track the validity of the input. | ||
/// - `aria_invalid` - A string representing the 'aria-invalid' attribute value for accessibility. Defaults to "true". | ||
/// - `aria_required` - A string representing the 'aria-required' attribute value for accessibility. Defaults to "true". | ||
/// - `input_type` - The type of the input element. Defaults to "text". | ||
/// - `input_ref` - A reference to the input element. | ||
/// - `input_handle` - A handle to set the value of the input. | ||
/// - `validate_function` - A callback function to validate the input value. | ||
/// | ||
/// # Returns | ||
/// (Html): An HTML representation of the input component. | ||
/// | ||
/// # Examples | ||
/// ``` | ||
/// // Example of using the custom_input_component | ||
/// use yew::prelude::*; | ||
/// | ||
/// fn validate_email(email: String) -> bool { | ||
/// let pattern = Regex::new(r"^[^ ]+@[^ ]+\.[a-z]{2,3}$").unwrap(); | ||
/// pattern.is_match(&email) | ||
/// } | ||
/// | ||
/// #[function_component(LoginForm)] | ||
/// pub fn login_form() -> Html { | ||
/// | ||
/// let input_email_ref = use_node_ref(); | ||
/// let input_email_handle = use_state(String::default); | ||
/// let email_valid_handle = use_state(|| true); | ||
/// let onsubmit = Callback::from(move |event: SubmitEvent| {}; | ||
/// | ||
/// html! { | ||
/// <form action="#" aria-label="Sign In Form" onsubmit={onsubmit}> | ||
/// <FormInput | ||
/// input_type={Some("text".to_string())} | ||
/// label={"".to_string()} | ||
/// input_handle={input_email_handle} | ||
/// name={"email".to_string()} | ||
/// input_ref={input_email_ref} | ||
/// input_placeholder={"Email".to_string()} | ||
/// icon_class={"fas fa-user".to_string()} | ||
/// icon={"fas fa-user".to_string()} | ||
/// error_message={"Enter a valid email address".to_string()} | ||
/// form_input_class={"".to_string()} | ||
/// form_input_field_class={"form-one-field".to_string()} | ||
/// form_input_label_class={"".to_string()} | ||
/// form_input_input_class={"".to_string()} | ||
/// form_input_error_class={"error-txt".to_string()} | ||
/// required={true} | ||
/// input_valid_handle={email_valid_handle} | ||
/// validate_function={validate_email} | ||
/// /> | ||
/// </form> | ||
/// } | ||
/// } | ||
/// ``` | ||
#[function_component(FormInput)] | ||
pub fn custom_input_component(props: &Props) -> Html { | ||
let input_valid = *props.input_valid_handle; | ||
|
||
let aria_invalid = props | ||
.aria_invalid | ||
.clone() | ||
.unwrap_or_else(|| "true".to_string()); | ||
|
||
let aria_required = props | ||
.aria_required | ||
.clone() | ||
.unwrap_or_else(|| "true".to_string()); | ||
|
||
let input_type = props | ||
.input_type | ||
.clone() | ||
.unwrap_or_else(|| "text".to_string()); | ||
|
||
let onchange = { | ||
let input_ref = props.input_ref.clone(); | ||
let input_handle = props.input_handle.clone(); | ||
let input_valid_handle = props.input_valid_handle.clone(); | ||
let validate_function = props.validate_function.clone(); | ||
|
||
Callback::from(move |_| { | ||
if let Some(input) = input_ref.cast::<HtmlInputElement>() { | ||
let value = input.value(); | ||
input_handle.set(value); | ||
input_valid_handle.set(validate_function.emit(input.value())); | ||
} | ||
}) | ||
}; | ||
|
||
html! { | ||
<div class={props.form_input_class.clone()}> | ||
<label class={props.form_input_label_class.clone()} for={props.input_id.clone()}> | ||
{&props.label} | ||
</label> | ||
<div class={props.form_input_field_class.clone()}> | ||
<input | ||
type={input_type} | ||
class={props.form_input_input_class.clone()} | ||
id={props.input_id.clone()} | ||
name={props.name.clone()} | ||
ref={props.input_ref.clone()} | ||
placeholder={props.input_placeholder.clone()} | ||
aria-label={props.aria_label.clone()} | ||
aria-required={aria_required} | ||
aria-invalid={aria_invalid} | ||
aria-describedby={props.aria_describedby.clone()} | ||
oninput={onchange} | ||
required={props.required} | ||
/> | ||
<span class={props.icon_class.clone()}></span> | ||
</div> | ||
if !input_valid { | ||
<div class={props.form_input_error_class.clone()} id={props.aria_describedby.clone()}>{&props.error_message}</div> | ||
} | ||
</div> | ||
} | ||
} |