✨ Add helper_text to TextInput (previously TextEdit)
This commit is contained in:
@@ -8,5 +8,5 @@ pub mod loading;
|
||||
pub mod login;
|
||||
pub mod main_window;
|
||||
pub mod spinner;
|
||||
pub mod text_field;
|
||||
pub mod text_input;
|
||||
pub mod wallpaper;
|
||||
|
@@ -1,45 +0,0 @@
|
||||
use dioxus::prelude::*;
|
||||
|
||||
turf::style_sheet!("src/components/text_field.scss");
|
||||
|
||||
#[derive(Props)]
|
||||
pub struct TextFieldProps<'a> {
|
||||
id: Option<&'a str>,
|
||||
oninput: Option<EventHandler<'a, Event<FormData>>>,
|
||||
placeholder: Option<&'a str>,
|
||||
r#type: Option<&'a str>,
|
||||
value: Option<&'a str>,
|
||||
#[props(default = true)]
|
||||
is_value_valid: bool,
|
||||
}
|
||||
|
||||
pub fn TextField<'a>(cx: Scope<'a, TextFieldProps<'a>>) -> Element<'a> {
|
||||
let classes = [
|
||||
ClassName::ROOT,
|
||||
if !cx.props.is_value_valid {
|
||||
ClassName::INVALID_DATA
|
||||
} else {
|
||||
""
|
||||
},
|
||||
]
|
||||
.join(" ");
|
||||
|
||||
cx.render(rsx! {
|
||||
style { STYLE_SHEET },
|
||||
|
||||
input {
|
||||
class: "{classes}",
|
||||
|
||||
id: cx.props.id.unwrap_or(""),
|
||||
|
||||
oninput: move |evt| {
|
||||
if let Some(cb) = &cx.props.oninput {
|
||||
cb.call(evt);
|
||||
}
|
||||
},
|
||||
r#type: cx.props.r#type,
|
||||
placeholder: cx.props.placeholder,
|
||||
value: cx.props.value,
|
||||
}
|
||||
})
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
@import "../_base.scss"
|
||||
|
||||
.root {
|
||||
$horizontal-padding: 1vw;
|
||||
|
||||
padding-left: $horizontal-padding;
|
||||
padding-right: $horizontal-padding;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
|
||||
height: calc(100% - (2 * ($border-normal-width)));
|
||||
width: calc(100% - (2 * ($border-normal-width + $horizontal-padding)));
|
||||
|
||||
margin: 0;
|
||||
|
||||
border: $border-normal;
|
||||
border-color: $color-primary-90;
|
||||
border-radius: $border-radius;
|
||||
|
||||
font-size: 2vh;
|
||||
|
||||
&.invalid-data {
|
||||
border-color: $color-critical;
|
||||
}
|
||||
}
|
88
src/components/text_input.rs
Normal file
88
src/components/text_input.rs
Normal file
@@ -0,0 +1,88 @@
|
||||
use dioxus::prelude::*;
|
||||
|
||||
turf::style_sheet!("src/components/text_input.scss");
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TextInputState {
|
||||
pub is_valid: bool,
|
||||
pub helper_text: Option<String>,
|
||||
}
|
||||
|
||||
impl TextInputState {
|
||||
pub fn new() -> Self {
|
||||
TextInputState {
|
||||
is_valid: true,
|
||||
helper_text: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.is_valid = true;
|
||||
self.helper_text = None;
|
||||
}
|
||||
|
||||
pub fn invalidate(&mut self, helper_text: String) {
|
||||
self.is_valid = false;
|
||||
self.helper_text = Some(helper_text);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Props)]
|
||||
pub struct TextInputProps<'a> {
|
||||
id: Option<&'a str>,
|
||||
r#type: Option<&'a str>,
|
||||
value: Option<&'a str>,
|
||||
placeholder: Option<&'a str>,
|
||||
oninput: Option<EventHandler<'a, Event<FormData>>>,
|
||||
state: Option<&'a UseRef<TextInputState>>,
|
||||
}
|
||||
|
||||
pub fn TextInput<'a>(cx: Scope<'a, TextInputProps<'a>>) -> Element<'a> {
|
||||
let mut level_class = "";
|
||||
let mut helper_text: String = "".to_string();
|
||||
|
||||
match cx.props.state {
|
||||
Some(state) => {
|
||||
if !state.read().is_valid {
|
||||
level_class = ClassName::INVALID;
|
||||
}
|
||||
if let Some(text) = &state.read().helper_text {
|
||||
helper_text = text.to_string();
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
cx.render(rsx! {
|
||||
style { STYLE_SHEET },
|
||||
|
||||
div {
|
||||
class: ClassName::ROOT,
|
||||
|
||||
input {
|
||||
class: level_class,
|
||||
|
||||
id: cx.props.id.unwrap_or(""),
|
||||
|
||||
oninput: move |evt| {
|
||||
if let Some(cb) = &cx.props.oninput {
|
||||
cb.call(evt);
|
||||
}
|
||||
},
|
||||
r#type: cx.props.r#type,
|
||||
placeholder: cx.props.placeholder,
|
||||
value: cx.props.value,
|
||||
},
|
||||
|
||||
div {
|
||||
class: ClassName::HELPER_TEXT,
|
||||
|
||||
p {
|
||||
class: level_class,
|
||||
|
||||
helper_text
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
47
src/components/text_input.scss
Normal file
47
src/components/text_input.scss
Normal file
@@ -0,0 +1,47 @@
|
||||
@import "../_base.scss"
|
||||
|
||||
.root {
|
||||
height: 100%;
|
||||
|
||||
input {
|
||||
$horizontal-padding: 1vw;
|
||||
|
||||
padding-left: $horizontal-padding;
|
||||
padding-right: $horizontal-padding;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
|
||||
height: calc(100% - (2 * ($border-normal-width)));
|
||||
width: calc(100% - (2 * ($border-normal-width + $horizontal-padding)));
|
||||
|
||||
margin: 0;
|
||||
|
||||
border: $border-normal;
|
||||
border-color: $color-primary-90;
|
||||
border-radius: $border-radius;
|
||||
|
||||
font-size: 2vh;
|
||||
|
||||
&.invalid {
|
||||
border-color: $color-critical;
|
||||
}
|
||||
}
|
||||
|
||||
.helper-text {
|
||||
margin: 0;
|
||||
margin-top: 0.3vh;
|
||||
|
||||
font-size: 1.2vh;
|
||||
|
||||
color: $color-primary-90;
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
padding-left: 1vw;
|
||||
|
||||
&.invalid {
|
||||
color: $color-critical;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user