From 3ac0a6cd85b4759b51a6cf3bc1ead8017dfbdbf8 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Tue, 20 Aug 2024 17:04:49 +0800 Subject: [PATCH] refactor: Rule::validate --- thaw/src/checkbox/checkbox_group.rs | 39 +++++++----- thaw/src/field/mod.rs | 2 +- thaw/src/field/rule.rs | 98 +++++++---------------------- thaw/src/input/mod.rs | 35 ++++++++--- 4 files changed, 73 insertions(+), 101 deletions(-) diff --git a/thaw/src/checkbox/checkbox_group.rs b/thaw/src/checkbox/checkbox_group.rs index b9007fb..5ea337e 100644 --- a/thaw/src/checkbox/checkbox_group.rs +++ b/thaw/src/checkbox/checkbox_group.rs @@ -1,4 +1,4 @@ -use crate::{FieldInjection, FieldValidationState, Rule, RuleValueIsEmpty}; +use crate::{FieldInjection, FieldValidationState, Rule}; use leptos::{context::Provider, prelude::*}; use std::{collections::HashSet, ops::Deref}; use thaw_utils::{class_list, Model}; @@ -63,26 +63,43 @@ pub struct CheckboxGroupRule(Rule, CheckboxGroupRuleTrigger>); impl CheckboxGroupRule { pub fn required(required: MaybeSignal) -> Self { - Self(Rule::required(required)) + Self::validator(move |value, name| { + if required.get_untracked() && value.is_empty() { + let message = name.get_untracked().map_or_else( + || String::from("Please select!"), + |name| format!("Please select {name}!"), + ); + Err(FieldValidationState::Error(message)) + } else { + Ok(()) + } + }) } pub fn required_with_message( required: MaybeSignal, message: MaybeSignal, ) -> Self { - Self(Rule::required_with_message(required, message)) + Self::validator(move |value, _| { + if required.get_untracked() && value.is_empty() { + Err(FieldValidationState::Error(message.get_untracked())) + } else { + Ok(()) + } + }) } pub fn validator( - f: impl Fn(&HashSet) -> Result<(), FieldValidationState> + Send + Sync + 'static, + f: impl Fn(&HashSet, Signal>) -> Result<(), FieldValidationState> + + Send + + Sync + + 'static, ) -> Self { Self(Rule::validator(f)) } - pub fn with_trigger(mut self, trigger: CheckboxGroupRuleTrigger) -> Self { - self.0.trigger = trigger; - - self + pub fn with_trigger(self, trigger: CheckboxGroupRuleTrigger) -> Self { + Self(Rule::with_trigger(self.0, trigger)) } } @@ -93,9 +110,3 @@ impl Deref for CheckboxGroupRule { &self.0 } } - -impl RuleValueIsEmpty for HashSet { - fn is_empty(&self) -> bool { - self.is_empty() - } -} diff --git a/thaw/src/field/mod.rs b/thaw/src/field/mod.rs index bceaa78..a1f1b45 100644 --- a/thaw/src/field/mod.rs +++ b/thaw/src/field/mod.rs @@ -4,4 +4,4 @@ mod rule; pub use field::*; pub use field_context_provider::*; -pub(crate) use rule::*; \ No newline at end of file +pub(crate) use rule::*; diff --git a/thaw/src/field/rule.rs b/thaw/src/field/rule.rs index 6c39bc3..c09e367 100644 --- a/thaw/src/field/rule.rs +++ b/thaw/src/field/rule.rs @@ -3,86 +3,40 @@ use leptos::prelude::*; use send_wrapper::SendWrapper; use std::ops::Deref; -enum RuleValidator { - Required(MaybeSignal), - RequiredMessage(MaybeSignal, MaybeSignal), - Validator(Box Result<(), FieldValidationState>>), -} +type RuleValidator = Box>) -> Result<(), FieldValidationState>>; pub struct Rule { validator: RuleValidator, - pub trigger: Trigger, -} - -impl Rule -where - Trigger: Default, -{ - pub fn required(required: MaybeSignal) -> Self { - Self { - trigger: Default::default(), - validator: RuleValidator::Required(required), - } - } - - pub fn required_with_message( - required: MaybeSignal, - message: MaybeSignal, - ) -> Self { - Self { - trigger: Default::default(), - validator: RuleValidator::RequiredMessage(required, message), - } - } - - pub fn validator( - f: impl Fn(&T) -> Result<(), FieldValidationState> + Send + Sync + 'static, - ) -> Self { - Self { - trigger: Default::default(), - validator: RuleValidator::Validator(Box::new(f)), - } - } + trigger: Trigger, } impl Rule { + pub fn validator( + f: impl Fn(&T, Signal>) -> Result<(), FieldValidationState> + + Send + + Sync + + 'static, + ) -> Self + where + Trigger: Default, + { + Self { + trigger: Default::default(), + validator: Box::new(f), + } + } + pub fn with_trigger(mut self, trigger: Trigger) -> Self { self.trigger = trigger; self } -} -impl Rule { - pub fn call_validator>( - &self, + pub fn validate( + rules: Vec, value: V, name: Signal>, - ) -> Result<(), FieldValidationState> { - value.with_untracked(|value| match &self.validator { - RuleValidator::Required(required) => { - if required.get_untracked() && RuleValueIsEmpty::is_empty(value) { - let message = name.get_untracked().map_or_else( - || String::from("Please input!"), - |name| format!("Please input {name}!"), - ); - Err(FieldValidationState::Error(message)) - } else { - Ok(()) - } - } - RuleValidator::RequiredMessage(required, message) => { - if required.get_untracked() && RuleValueIsEmpty::is_empty(value) { - Err(FieldValidationState::Error(message.get_untracked())) - } else { - Ok(()) - } - } - RuleValidator::Validator(f) => f(value), - }) - } - - pub fn validate(rules: Vec, value: V, name: Signal>) -> Callback, bool> + ) -> Callback, bool> where V: WithUntracked, V: Send + Sync + Copy + 'static, @@ -115,7 +69,7 @@ impl Rule { } call_count += 1; - let state = rule.call_validator(value, name); + let state = value.with_untracked(|value| (rule.validator)(value, name)); if state.is_err() { return Some(state); } @@ -139,13 +93,3 @@ impl Rule { validate } } - -pub trait RuleValueIsEmpty { - fn is_empty(&self) -> bool; -} - -impl RuleValueIsEmpty for String { - fn is_empty(&self) -> bool { - self.is_empty() - } -} \ No newline at end of file diff --git a/thaw/src/input/mod.rs b/thaw/src/input/mod.rs index b04bfd1..8933de2 100644 --- a/thaw/src/input/mod.rs +++ b/thaw/src/input/mod.rs @@ -1,6 +1,6 @@ -use std::ops::Deref; use crate::{FieldInjection, FieldValidationState, Rule}; use leptos::{ev, html, prelude::*}; +use std::ops::Deref; use thaw_utils::{ class_list, mount_style, ArcOneCallback, BoxOneCallback, ComponentRef, Model, OptionalProp, }; @@ -264,28 +264,45 @@ pub enum InputRuleTrigger { pub struct InputRule(Rule); -impl InputRule { +impl InputRule { pub fn required(required: MaybeSignal) -> Self { - Self(Rule::required(required)) + Self::validator(move |value, name| { + if required.get_untracked() && value.is_empty() { + let message = name.get_untracked().map_or_else( + || String::from("Please input!"), + |name| format!("Please input {name}!"), + ); + Err(FieldValidationState::Error(message)) + } else { + Ok(()) + } + }) } pub fn required_with_message( required: MaybeSignal, message: MaybeSignal, ) -> Self { - Self(Rule::required_with_message(required,message)) + Self::validator(move |value, _| { + if required.get_untracked() && value.is_empty() { + Err(FieldValidationState::Error(message.get_untracked())) + } else { + Ok(()) + } + }) } pub fn validator( - f: impl Fn(&String) -> Result<(), FieldValidationState> + Send + Sync + 'static, + f: impl Fn(&String, Signal>) -> Result<(), FieldValidationState> + + Send + + Sync + + 'static, ) -> Self { Self(Rule::validator(f)) } - pub fn with_trigger(mut self, trigger: InputRuleTrigger) -> Self { - self.0.trigger = trigger; - - self + pub fn with_trigger(self, trigger: InputRuleTrigger) -> Self { + Self(Rule::with_trigger(self.0, trigger)) } }