mirror of
https://github.com/adoyle0/thaw.git
synced 2025-01-22 22:09:22 -05:00
fix: Input validate
This commit is contained in:
parent
615c33a5c8
commit
c0bd42ad60
5 changed files with 59 additions and 18 deletions
|
@ -27,8 +27,11 @@ view! {
|
|||
view! {
|
||||
<form>
|
||||
<FieldContextProvider>
|
||||
<Field label="Example field">
|
||||
<Input />
|
||||
<Field label="Username" name="username">
|
||||
<Input rules=vec![InputRule::required(true.into())]/>
|
||||
</Field>
|
||||
<Field label="Password" name="password">
|
||||
<Input input_type=InputType::Password rules=vec![InputRule::required(true.into())]/>
|
||||
</Field>
|
||||
<button
|
||||
type="submit"
|
||||
|
|
|
@ -37,6 +37,10 @@
|
|||
line-height: var(--lineHeightBase200);
|
||||
}
|
||||
|
||||
.thaw-field--error > .thaw-field__validation-message {
|
||||
color: var(--colorPaletteRedForeground1);
|
||||
}
|
||||
|
||||
.thaw-field__validation-message-icon {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
|
|
|
@ -25,6 +25,15 @@ pub fn Field(
|
|||
move || {
|
||||
format!("thaw-field--{}", orientation.get().as_str())
|
||||
},
|
||||
move || {
|
||||
validation_state.with(|state| {
|
||||
if let Some(state) = state {
|
||||
Some(format!("thaw-field--{}", state.as_str()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
},
|
||||
class
|
||||
]>
|
||||
{
|
||||
|
@ -201,3 +210,13 @@ pub enum FieldValidationState {
|
|||
Success(String),
|
||||
Warning(String),
|
||||
}
|
||||
|
||||
impl FieldValidationState {
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Error(_) => "error",
|
||||
Self::Success(_) => "success",
|
||||
Self::Warning(_) => "warning",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,11 +26,18 @@ impl FieldContextInjection {
|
|||
use_context()
|
||||
}
|
||||
|
||||
pub(crate) fn register_field(&self, name: Signal<Option<String>>, validate: impl Fn() -> bool + Send + Sync + 'static) {
|
||||
pub(crate) fn register_field(
|
||||
&self,
|
||||
name: Signal<Option<String>>,
|
||||
validate: impl Fn() -> bool + Send + Sync + 'static,
|
||||
) {
|
||||
let mut key = None;
|
||||
self.0
|
||||
.update_value(|map| key = Some(map.insert((name, Callback::from(move |_| validate())))));
|
||||
|
||||
let validate = Callback::from(move |_| validate());
|
||||
self.0.update_value(|map| {
|
||||
key = Some(map.insert((name, validate)));
|
||||
()
|
||||
});
|
||||
|
||||
let map = self.0.clone();
|
||||
Owner::on_cleanup(move || {
|
||||
map.update_value(|map| map.remove(key.unwrap()));
|
||||
|
@ -39,12 +46,13 @@ impl FieldContextInjection {
|
|||
|
||||
pub fn validate(&self) -> bool {
|
||||
self.0.with_value(|map| {
|
||||
let mut rt = true;
|
||||
for (_, (_, validate)) in map.iter() {
|
||||
if !validate.run(()) {
|
||||
return false;
|
||||
rt = false;
|
||||
}
|
||||
}
|
||||
true
|
||||
rt
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -68,24 +68,24 @@ pub fn Input(
|
|||
if rules.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
||||
let mut rules_iter = rules.iter();
|
||||
loop {
|
||||
let Some(rule) = rules_iter.next() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
if let Err(state) = rule.call_validator(trigger, value) {
|
||||
|
||||
if let Err(state) = rule.call_validator(trigger, value, name) {
|
||||
return Some(state);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let rt = state.is_some();
|
||||
if let Some(field_injection) = field_injection.as_ref() {
|
||||
field_injection.update_validation_state(state);
|
||||
};
|
||||
rt
|
||||
let rt = state.is_none();
|
||||
if let Some(field_injection) = field_injection.as_ref() {
|
||||
field_injection.update_validation_state(state);
|
||||
};
|
||||
rt
|
||||
});
|
||||
if let Some(field_context) = FieldContextInjection::use_context() {
|
||||
field_context.register_field(name, move || validate.run(None));
|
||||
|
@ -318,7 +318,9 @@ impl InputRule {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn validator(f: impl Fn(&String) -> Result<(), FieldValidationState> + Send + Sync + 'static) -> Self {
|
||||
pub fn validator(
|
||||
f: impl Fn(&String) -> Result<(), FieldValidationState> + Send + Sync + 'static,
|
||||
) -> Self {
|
||||
Self {
|
||||
trigger: Default::default(),
|
||||
validator: InputRuleValidator::Validator(Callback::from(move |v| f(&v))),
|
||||
|
@ -335,6 +337,7 @@ impl InputRule {
|
|||
&self,
|
||||
trigger: Option<InputRuleTrigger>,
|
||||
value: Model<String>,
|
||||
name: Signal<Option<String>>,
|
||||
) -> Result<(), FieldValidationState> {
|
||||
if let Some(trigger) = trigger {
|
||||
if self.trigger != trigger {
|
||||
|
@ -345,7 +348,11 @@ impl InputRule {
|
|||
value.with_untracked(|value| match &self.validator {
|
||||
InputRuleValidator::Required(required) => {
|
||||
if required.get_untracked() && value.is_empty() {
|
||||
Err(FieldValidationState::Error(String::from("")))
|
||||
let message = name.get_untracked().map_or_else(
|
||||
|| String::from("Please input!"),
|
||||
|name| format!("Please input {name}!"),
|
||||
);
|
||||
Err(FieldValidationState::Error(message))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue