Skip to content

Commit

Permalink
feat: base of TextField component (#200)
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael-Liendo authored Jun 23, 2024
1 parent 8ab58eb commit eb9ae55
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 0 deletions.
1 change: 1 addition & 0 deletions crates/web/src/components/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod helper;

pub mod button;
pub mod text_field;
84 changes: 84 additions & 0 deletions crates/web/src/components/text_field.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use core::fmt;
use std::{collections::HashSet, fmt::Debug};

use leptos::{component, create_memo, logging, view, IntoView, MaybeProp, SignalGet, TextProp};

#[derive(Clone, Debug, Default)]
pub enum TextFieldVariant {
#[default]
Primary,
}

#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub enum TextFieldType {
#[default]
Text,
Email,
Password,
}

impl fmt::Display for TextFieldType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
TextFieldType::Text => write!(f, "text"),
TextFieldType::Email => write!(f, "email"),
TextFieldType::Password => write!(f, "password"),
}
}
}

#[component]
pub fn TextField(
#[prop(optional, into)] name: TextProp,
#[prop(optional, into)] id: TextProp,
#[prop(optional, into)] placeholder: TextProp,
#[prop(optional, into)] value: TextProp,
#[prop(optional, into)] label: TextProp,
#[prop(optional, into)] variant: MaybeProp<TextFieldVariant>,
#[prop(optional, into)] r#type: TextFieldType,
#[prop(optional, into)] disabled: MaybeProp<bool>,
#[prop(optional, into)] full_width: MaybeProp<bool>,
) -> impl IntoView {
let class_names = create_memo(move |_| {
let mut classes: HashSet<&str> = HashSet::new();

match variant.get().unwrap_or_default() {
TextFieldVariant::Primary => {
classes.insert("px-3.5");
classes.insert("py-2");
classes.insert("rounded");
classes.insert("font-semibold");
classes.insert("placeholder:text-purple-200");
classes.insert("border-2");
classes.insert("border-purple-300");
classes.insert("text-purple-400");
classes.insert("focus:border-purple-400");
classes.insert("focus:ring-purple-500/60");
}
}

// Default Classes

if let Some(is_full_width) = full_width.get() {
if is_full_width {
classes.insert("w-full");
}
}

if let Some(is_disabled) = disabled.get() {
if is_disabled {
classes.insert("opacity-70");
classes.insert("!cursor-not-allowed");
}
}

classes.into_iter().collect::<Vec<&str>>().join(" ")
});

view! {
<div>
<label class="block mb-2 text-sm font-medium text-purple-500" for=id.clone()>{label}</label>
<input type=format!("{}", r#type) name=name value=value id=id placeholder=placeholder class=class_names disabled=disabled />
</div>
}
}
4 changes: 4 additions & 0 deletions crates/web/src/views/home.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::components::text_field::{TextField, TextFieldType};
use leptos::{component, view, IntoView};

use crate::components::button::{Button, ButtonVariant};
Expand All @@ -11,6 +12,9 @@ pub fn Home() -> impl IntoView {
<Button variant={ButtonVariant::Text}>{"Text"}</Button>
<Button variant={ButtonVariant::Contained}>{"Contained"}</Button>
<Button variant={ButtonVariant::Outlined}>{"Outlined"}</Button>
<TextField r#type=TextFieldType::Text placeholder="Simple" />
<TextField placeholder="Label" label="Input Label" id="label" />
<TextField placeholder="Disabled" disabled={true}/>
</section>
}
}
1 change: 1 addition & 0 deletions crates/web/tests/components/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
mod button;
mod text_field;
52 changes: 52 additions & 0 deletions crates/web/tests/components/text_field.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use leptos::{mount_to, view};

use wasm_bindgen::JsCast;
use wasm_bindgen_test::*;

use web::components::text_field::{TextField, TextFieldType};

wasm_bindgen_test_configure!(run_in_browser);

#[wasm_bindgen_test]
fn default_text_field_class_names_integrity() {
let document = leptos::document();
let test_wrapper = document.create_element("div").unwrap();
let _ = document.body().unwrap().append_child(&test_wrapper);

mount_to(
test_wrapper.clone().unchecked_into(),
|| view! { <TextField id="text-field" /> },
);

let text_field_el = test_wrapper
.query_selector("#text-field")
.expect("Failed to access document")
.expect("text_field Element not found")
.unchecked_into::<web_sys::HtmlInputElement>();

let want_class_names = vec![
"px-3.5",
"py-2",
"rounded",
"font-semibold",
"placeholder:text-purple-200",
"border-2",
"border-purple-300",
"text-purple-400",
"focus:border-purple-400",
"focus:ring-purple-500/60",
];

let have_class_names = text_field_el.get_attribute("class").unwrap();

for class_name in want_class_names.iter() {
assert!(have_class_names.contains(class_name));
}
}

#[wasm_bindgen_test]
fn text_field_types() {
assert_eq!(TextFieldType::Text.to_string(), "text");
assert_eq!(TextFieldType::Email.to_string(), "email");
assert_eq!(TextFieldType::Password.to_string(), "password");
}

0 comments on commit eb9ae55

Please sign in to comment.