Skip to content

Commit

Permalink
add project
Browse files Browse the repository at this point in the history
  • Loading branch information
wiseaidev committed Aug 5, 2023
0 parents commit 123f62d
Show file tree
Hide file tree
Showing 3 changed files with 318 additions and 0 deletions.
21 changes: 21 additions & 0 deletions Cargo.toml
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"
102 changes: 102 additions & 0 deletions REAMDE.md
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! 🎉
195 changes: 195 additions & 0 deletions src/lib.rs
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>
}
}

0 comments on commit 123f62d

Please sign in to comment.