refactor: Rule::validate

This commit is contained in:
luoxiao 2024-08-20 17:04:49 +08:00 committed by luoxiaozero
parent a50f8ff3bf
commit 3ac0a6cd85
4 changed files with 73 additions and 101 deletions

View file

@ -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<HashSet<String>, CheckboxGroupRuleTrigger>);
impl CheckboxGroupRule {
pub fn required(required: MaybeSignal<bool>) -> 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<bool>,
message: MaybeSignal<String>,
) -> 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<String>) -> Result<(), FieldValidationState> + Send + Sync + 'static,
f: impl Fn(&HashSet<String>, Signal<Option<String>>) -> 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<String> {
fn is_empty(&self) -> bool {
self.is_empty()
}
}

View file

@ -4,4 +4,4 @@ mod rule;
pub use field::*;
pub use field_context_provider::*;
pub(crate) use rule::*;
pub(crate) use rule::*;

View file

@ -3,86 +3,40 @@ use leptos::prelude::*;
use send_wrapper::SendWrapper;
use std::ops::Deref;
enum RuleValidator<T> {
Required(MaybeSignal<bool>),
RequiredMessage(MaybeSignal<bool>, MaybeSignal<String>),
Validator(Box<dyn Fn(&T) -> Result<(), FieldValidationState>>),
}
type RuleValidator<T> = Box<dyn Fn(&T, Signal<Option<String>>) -> Result<(), FieldValidationState>>;
pub struct Rule<T, Trigger> {
validator: RuleValidator<T>,
pub trigger: Trigger,
}
impl<T, Trigger> Rule<T, Trigger>
where
Trigger: Default,
{
pub fn required(required: MaybeSignal<bool>) -> Self {
Self {
trigger: Default::default(),
validator: RuleValidator::Required(required),
}
}
pub fn required_with_message(
required: MaybeSignal<bool>,
message: MaybeSignal<String>,
) -> 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<T, Trigger> Rule<T, Trigger> {
pub fn validator(
f: impl Fn(&T, Signal<Option<String>>) -> 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<T: RuleValueIsEmpty, Trigger> Rule<T, Trigger> {
pub fn call_validator<V: WithUntracked<Value = T>>(
&self,
pub fn validate<V, R>(
rules: Vec<R>,
value: V,
name: Signal<Option<String>>,
) -> 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<V, R>(rules: Vec<R>, value: V, name: Signal<Option<String>>) -> Callback<Option<Trigger>, bool>
) -> Callback<Option<Trigger>, bool>
where
V: WithUntracked<Value = T>,
V: Send + Sync + Copy + 'static,
@ -115,7 +69,7 @@ impl<T: RuleValueIsEmpty, Trigger> Rule<T, Trigger> {
}
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<T: RuleValueIsEmpty, Trigger> Rule<T, Trigger> {
validate
}
}
pub trait RuleValueIsEmpty {
fn is_empty(&self) -> bool;
}
impl RuleValueIsEmpty for String {
fn is_empty(&self) -> bool {
self.is_empty()
}
}

View file

@ -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<String, InputRuleTrigger>);
impl InputRule {
impl InputRule {
pub fn required(required: MaybeSignal<bool>) -> 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<bool>,
message: MaybeSignal<String>,
) -> 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<Option<String>>) -> 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))
}
}