feat(from): add form validator class with strategy design pattern
This commit is contained in:
parent
61c6e637ec
commit
607b986848
@ -1 +1,4 @@
|
||||
include: package:wyatt_analysis/analysis_options.yaml
|
||||
include: package:wyatt_analysis/analysis_options.yaml
|
||||
|
||||
analyzer:
|
||||
exclude: "!example/**"
|
@ -61,10 +61,10 @@ class App extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
FormDataCubit _formCubit = CustomFormCubit(inputs: getNormalFormData());
|
||||
FormDataCubit formCubit = CustomFormCubit(inputs: getNormalFormData());
|
||||
|
||||
return BlocProvider(
|
||||
create: (context) => _formCubit,
|
||||
create: (context) => formCubit,
|
||||
child: const WidgetTree(),
|
||||
);
|
||||
}
|
||||
|
@ -187,9 +187,9 @@ class _CheckListInput extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<FormDataCubit, FormDataState>(
|
||||
builder: (context, state) {
|
||||
final _input =
|
||||
final input =
|
||||
state.data.validatorOf<ListOption<String>>(formFieldList);
|
||||
final _options = _input.value;
|
||||
final options = input.value;
|
||||
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@ -197,33 +197,33 @@ class _CheckListInput extends StatelessWidget {
|
||||
ListTile(
|
||||
title: const Text('Checkbox1'),
|
||||
trailing: Checkbox(
|
||||
value: _options.contains('checkbox1'),
|
||||
value: options.contains('checkbox1'),
|
||||
onChanged: (_) {
|
||||
context.read<FormDataCubit>().dataChanged(
|
||||
formFieldList,
|
||||
_input.select('checkbox1'),
|
||||
input.select('checkbox1'),
|
||||
);
|
||||
}),
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('Checkbox2'),
|
||||
trailing: Checkbox(
|
||||
value: _options.contains('checkbox2'),
|
||||
value: options.contains('checkbox2'),
|
||||
onChanged: (_) {
|
||||
context.read<FormDataCubit>().dataChanged(
|
||||
formFieldList,
|
||||
_input.select('checkbox2'),
|
||||
input.select('checkbox2'),
|
||||
);
|
||||
}),
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('Checkbox3 (default)'),
|
||||
trailing: Checkbox(
|
||||
value: _options.contains('checkbox3'),
|
||||
value: options.contains('checkbox3'),
|
||||
onChanged: (_) {
|
||||
context.read<FormDataCubit>().dataChanged(
|
||||
formFieldList,
|
||||
_input.select('checkbox3'),
|
||||
input.select('checkbox3'),
|
||||
);
|
||||
}),
|
||||
),
|
||||
@ -239,7 +239,7 @@ class _RadioListInput extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<FormDataCubit, FormDataState>(
|
||||
builder: (context, state) {
|
||||
final _input = state.data.validatorOf<TextString>(formFieldRadio);
|
||||
final input = state.data.validatorOf<TextString>(formFieldRadio);
|
||||
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@ -248,7 +248,7 @@ class _RadioListInput extends StatelessWidget {
|
||||
title: const Text('Radio1'),
|
||||
trailing: Radio<bool>(
|
||||
groupValue: true,
|
||||
value: _input.value == 'radio1',
|
||||
value: input.value == 'radio1',
|
||||
onChanged: (_) {
|
||||
context.read<FormDataCubit>().dataChanged(
|
||||
formFieldRadio,
|
||||
@ -260,7 +260,7 @@ class _RadioListInput extends StatelessWidget {
|
||||
title: const Text('Radio2'),
|
||||
trailing: Radio<bool>(
|
||||
groupValue: true,
|
||||
value: _input.value == 'radio2',
|
||||
value: input.value == 'radio2',
|
||||
onChanged: (_) {
|
||||
context.read<FormDataCubit>().dataChanged(
|
||||
formFieldRadio,
|
||||
@ -272,7 +272,7 @@ class _RadioListInput extends StatelessWidget {
|
||||
title: const Text('Radio3'),
|
||||
trailing: Radio<bool>(
|
||||
groupValue: true,
|
||||
value: _input.value == 'radio3',
|
||||
value: input.value == 'radio3',
|
||||
onChanged: (_) {
|
||||
context.read<FormDataCubit>().dataChanged(
|
||||
formFieldRadio,
|
||||
@ -378,6 +378,20 @@ class _DebugButton extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _ResetButton extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<FormDataCubit, FormDataState>(
|
||||
builder: (context, state) {
|
||||
return ElevatedButton(
|
||||
onPressed: () => context.read<FormDataCubit>().resetForm(),
|
||||
child: const Text('RESET'),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SignUpForm extends StatelessWidget {
|
||||
const SignUpForm({Key? key}) : super(key: key);
|
||||
|
||||
@ -431,6 +445,8 @@ class SignUpForm extends StatelessWidget {
|
||||
_SignUpButton(),
|
||||
const SizedBox(height: 8),
|
||||
_DebugButton(),
|
||||
const SizedBox(height: 8),
|
||||
_ResetButton(),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -18,40 +18,56 @@ import 'dart:async';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:wyatt_form_bloc/src/enums/enums.dart';
|
||||
import 'package:wyatt_form_bloc/src/form/form.dart';
|
||||
import 'package:wyatt_form_bloc/src/validators/form/every_input_validator.dart';
|
||||
|
||||
part 'form_data_state.dart';
|
||||
|
||||
abstract class FormDataCubit extends Cubit<FormDataState> {
|
||||
FormDataCubit({required FormData inputs})
|
||||
: super(FormDataState(data: inputs));
|
||||
FormValidator validationStrategy;
|
||||
FormData formCopy;
|
||||
|
||||
FormDataCubit({
|
||||
required FormData inputs,
|
||||
FormValidator validator = const EveryInputValidator(),
|
||||
}) : formCopy = inputs.clone(),
|
||||
validationStrategy = validator,
|
||||
super(FormDataState(data: inputs));
|
||||
|
||||
/// Change value of a field.
|
||||
///
|
||||
///
|
||||
/// Inputs:
|
||||
/// - `field`: The key of the field to change.
|
||||
/// - `dirtyValue`: The new value of the field. (Wrapped in a dirty validator)
|
||||
void dataChanged(String field, FormInputValidator dirtyValue) {
|
||||
final _form = state.data.clone();
|
||||
void dataChanged<V>(
|
||||
String field,
|
||||
FormInputValidator<V, ValidationError> dirtyValue,
|
||||
) {
|
||||
final form = state.data.clone();
|
||||
|
||||
if (_form.contains(field)) {
|
||||
_form.updateValidator(field, dirtyValue);
|
||||
if (form.contains(field)) {
|
||||
form.updateValidator(field, dirtyValue);
|
||||
} else {
|
||||
throw Exception('Form field $field not found');
|
||||
}
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
data: _form,
|
||||
status: _form.validate(),
|
||||
data: form,
|
||||
status: validationStrategy.validate(form),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Just validate the form manually. (Useful if you just update the strategy)
|
||||
void validate() {
|
||||
final form = state.data;
|
||||
emit(state.copyWith(status: validationStrategy.validate(form)));
|
||||
}
|
||||
|
||||
/// Update entries list.
|
||||
///
|
||||
///
|
||||
/// Inputs:
|
||||
/// - `data`: The new entries list.
|
||||
/// - `operation`: The operation to perform on the entries set.
|
||||
@ -59,31 +75,36 @@ abstract class FormDataCubit extends Cubit<FormDataState> {
|
||||
FormData data, {
|
||||
SetOperation operation = SetOperation.replace,
|
||||
}) {
|
||||
FormData _form = data;
|
||||
FormData form = data;
|
||||
|
||||
switch (operation) {
|
||||
case SetOperation.replace:
|
||||
_form = data;
|
||||
form = data;
|
||||
break;
|
||||
case SetOperation.difference:
|
||||
_form = state.data.difference(data);
|
||||
form = state.data.difference(data);
|
||||
break;
|
||||
case SetOperation.intersection:
|
||||
_form = state.data.intersection(data);
|
||||
form = state.data.intersection(data);
|
||||
break;
|
||||
case SetOperation.union:
|
||||
_form = state.data.union(data);
|
||||
form = state.data.union(data);
|
||||
break;
|
||||
}
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
data: _form,
|
||||
status: _form.validate(),
|
||||
data: form,
|
||||
status: validationStrategy.validate(form),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Reset all form inputs
|
||||
void resetForm() {
|
||||
emit(FormDataState(data: formCopy));
|
||||
}
|
||||
|
||||
/// Submit the form.
|
||||
Future<void> submitForm();
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
part of 'form_data_cubit.dart';
|
||||
|
||||
@immutable
|
||||
class FormDataState extends Equatable {
|
||||
/// Global status of a form.
|
||||
final FormStatus status;
|
||||
@ -37,13 +36,11 @@ class FormDataState extends Equatable {
|
||||
FormStatus? status,
|
||||
FormData? data,
|
||||
String? errorMessage,
|
||||
}) {
|
||||
return FormDataState(
|
||||
}) => FormDataState(
|
||||
status: status ?? this.status,
|
||||
data: data ?? this.data,
|
||||
errorMessage: errorMessage ?? this.errorMessage,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool? get stringify => true;
|
||||
|
@ -14,8 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'package:wyatt_form_bloc/src/form/form.dart';
|
||||
|
||||
const Set<FormStatus> _validatedFormStatuses = <FormStatus>{
|
||||
FormStatus.valid,
|
||||
FormStatus.submissionInProgress,
|
||||
@ -51,6 +49,8 @@ enum FormStatus {
|
||||
bool get isPure => this == FormStatus.pure;
|
||||
|
||||
/// Indicates whether the form is completely validated.
|
||||
/// This means the [FormStatus] is strictly:
|
||||
/// * `FormStatus.valid`
|
||||
bool get isValid => this == FormStatus.valid;
|
||||
|
||||
/// Indicates whether the form has been validated successfully.
|
||||
@ -75,23 +75,4 @@ enum FormStatus {
|
||||
|
||||
/// Indicates whether the form submission has been canceled.
|
||||
bool get isSubmissionCanceled => this == FormStatus.submissionCanceled;
|
||||
|
||||
/// Validate a list of inputs by processing them in `validate` as validators.
|
||||
static FormStatus validateInputs(List<FormInput> inputs) {
|
||||
return validate(
|
||||
inputs
|
||||
.map<FormInputValidator>((FormInput input) => input.validator)
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Validate a list of validators.
|
||||
static FormStatus validate(List<FormInputValidator> validators) {
|
||||
return validators.every((FormInputValidator validator) => validator.pure)
|
||||
? FormStatus.pure
|
||||
: validators
|
||||
.any((FormInputValidator validator) => validator.valid == false)
|
||||
? FormStatus.invalid
|
||||
: FormStatus.valid;
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,14 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
enum ValidationError {
|
||||
/// Generic invalid error.
|
||||
invalid
|
||||
// enum ValidationError {
|
||||
// /// Generic invalid error.
|
||||
// invalid
|
||||
// }
|
||||
|
||||
abstract class ValidationError {}
|
||||
|
||||
enum ValidationStandardError implements ValidationError {
|
||||
invalid,
|
||||
empty
|
||||
}
|
||||
|
@ -14,12 +14,15 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:wyatt_form_bloc/src/enums/form_input_status.dart';
|
||||
import 'package:wyatt_form_bloc/src/enums/form_status.dart';
|
||||
import 'package:wyatt_form_bloc/src/enums/validation_error.dart';
|
||||
|
||||
part 'form_data.dart';
|
||||
part 'form_input.dart';
|
||||
part 'form_input_metadata.dart';
|
||||
part 'form_input_validator.dart';
|
||||
part 'form_data.dart';
|
||||
part 'form_validator.dart';
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
part of 'form.dart';
|
||||
|
||||
@immutable
|
||||
class FormData extends Equatable {
|
||||
final List<FormInput> _inputs;
|
||||
|
||||
@ -29,7 +28,7 @@ class FormData extends Equatable {
|
||||
/// Returns the input for the associated key
|
||||
FormInput inputOf(String key) {
|
||||
if (contains(key)) {
|
||||
return _inputs.firstWhere((FormInput input) => input.key == key);
|
||||
return _inputs.firstWhere((input) => input.key == key);
|
||||
} else {
|
||||
throw Exception('FormInput with key `$key` does not exist in form');
|
||||
}
|
||||
@ -46,23 +45,23 @@ class FormData extends Equatable {
|
||||
}
|
||||
|
||||
/// Returns all associated validators as a list
|
||||
List<FormInputValidator<V, E>> validators<V, E>() {
|
||||
return _inputs
|
||||
.map<FormInputValidator<V, E>>(
|
||||
(FormInput input) => input.validator as FormInputValidator<V, E>,
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
List<FormInputValidator<V, E>> validators<V, E extends ValidationError>() =>
|
||||
_inputs
|
||||
.map<FormInputValidator<V, E>>(
|
||||
(input) => input.validator as FormInputValidator<V, E>,
|
||||
)
|
||||
.toList();
|
||||
|
||||
/// A [FormInputValidator] represents the value of a single form input field.
|
||||
/// It contains information about the [FormInputStatus], value, as well
|
||||
/// as validation status.
|
||||
T validatorOf<T>(String key) {
|
||||
return inputOf(key).validator as T;
|
||||
}
|
||||
T validatorOf<T>(String key) => inputOf(key).validator as T;
|
||||
|
||||
/// Updates validator of a given input. (perform copyWith)
|
||||
void updateValidator(String key, FormInputValidator dirtyValue) {
|
||||
void updateValidator<V>(
|
||||
String key,
|
||||
FormInputValidator<V, ValidationError> dirtyValue,
|
||||
) {
|
||||
if (contains(key)) {
|
||||
final index = _inputs.indexOf(
|
||||
inputOf(key),
|
||||
@ -73,38 +72,31 @@ class FormData extends Equatable {
|
||||
|
||||
/// Returns a validation error if the [FormInputValidator] is invalid.
|
||||
/// Returns null if the [FormInputValidator] is valid.
|
||||
E? errorOf<V, E>(String key) {
|
||||
return (inputOf(key).validator as FormInputValidator<V, E>).error;
|
||||
}
|
||||
E? errorOf<E extends ValidationError>(String key) =>
|
||||
(inputOf(key).validator as FormInputValidator<dynamic, E>).error;
|
||||
|
||||
/// The value of the associated [FormInputValidator]. For example,
|
||||
/// if you have a FormInputValidator for FirstName, the value could be 'Joe'.
|
||||
V valueOf<V, E>(String key) {
|
||||
return (inputOf(key).validator as FormInputValidator<V, E>).value;
|
||||
}
|
||||
V valueOf<V>(String key) =>
|
||||
(inputOf(key).validator as FormInputValidator<V, dynamic>).value;
|
||||
|
||||
/// Returns `true` if the [FormInputValidator] is not valid.
|
||||
/// Same as `E? errorOf<V, E>(String key) != null`
|
||||
bool isNotValid(String key) {
|
||||
return !inputOf(key).validator.valid;
|
||||
}
|
||||
bool isNotValid(String key) => !inputOf(key).validator.valid;
|
||||
|
||||
/// Returns all associated metadata as a list
|
||||
List<FormInputMetadata<M>> metadata<M>() {
|
||||
return _inputs
|
||||
.map<FormInputMetadata<M>>(
|
||||
(FormInput input) => input.metadata as FormInputMetadata<M>,
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
List<FormInputMetadata<M>> metadata<M>() => _inputs
|
||||
.map<FormInputMetadata<M>>(
|
||||
(input) => input.metadata as FormInputMetadata<M>,
|
||||
)
|
||||
.toList();
|
||||
|
||||
/// Returns the metadata associated. With `M` the type of extra data.
|
||||
FormInputMetadata<M> metadataOf<M>(String key) {
|
||||
return inputOf(key).metadata as FormInputMetadata<M>;
|
||||
}
|
||||
FormInputMetadata<M> metadataOf<M>(String key) =>
|
||||
inputOf(key).metadata as FormInputMetadata<M>;
|
||||
|
||||
/// Updates metadata of a given input. (perform copyWith)
|
||||
void updateMetadata(String key, FormInputMetadata meta) {
|
||||
void updateMetadata<M>(String key, FormInputMetadata<M> meta) {
|
||||
if (contains(key)) {
|
||||
final index = _inputs.indexOf(
|
||||
inputOf(key),
|
||||
@ -113,15 +105,8 @@ class FormData extends Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
/// Validate self inputs.
|
||||
FormStatus validate() {
|
||||
return FormStatus.validateInputs(_inputs);
|
||||
}
|
||||
|
||||
/// Check if this contains an input with the given key.
|
||||
bool contains(String key) {
|
||||
return _inputs.any((FormInput input) => input.key == key);
|
||||
}
|
||||
bool contains(String key) => _inputs.any((input) => input.key == key);
|
||||
|
||||
/// Makes an intersection set operation and returns newly created [FormData]
|
||||
FormData intersection(FormData other) {
|
||||
@ -173,11 +158,9 @@ class FormData extends Equatable {
|
||||
}
|
||||
|
||||
/// Deeply copy this.
|
||||
FormData clone() {
|
||||
return FormData(
|
||||
_inputs.map((FormInput input) => input.clone()).toList(),
|
||||
);
|
||||
}
|
||||
FormData clone() => FormData(
|
||||
_inputs.map((input) => input.clone()).toList(),
|
||||
);
|
||||
|
||||
/// Export this to [Map] format.
|
||||
Map<String, dynamic> toMap() {
|
||||
@ -190,6 +173,9 @@ class FormData extends Equatable {
|
||||
return map;
|
||||
}
|
||||
|
||||
/// Export this to [String] format.
|
||||
String toJson() => jsonEncode(toMap());
|
||||
|
||||
@override
|
||||
bool? get stringify => true;
|
||||
|
||||
|
@ -17,10 +17,11 @@
|
||||
|
||||
part of 'form.dart';
|
||||
|
||||
class FormInput extends Equatable {
|
||||
class FormInput<Validator extends FormInputValidator<dynamic, ValidationError>>
|
||||
extends Equatable {
|
||||
final String key;
|
||||
final FormInputValidator validator;
|
||||
final FormInputMetadata metadata;
|
||||
final Validator validator;
|
||||
final FormInputMetadata<dynamic> metadata;
|
||||
|
||||
String get name => metadata._name ?? key;
|
||||
|
||||
@ -31,29 +32,25 @@ class FormInput extends Equatable {
|
||||
this.metadata = const FormInputMetadata<void>(export: true),
|
||||
});
|
||||
|
||||
FormInput copyWith({
|
||||
String? key,
|
||||
Validator? validator,
|
||||
FormInputMetadata? metadata,
|
||||
}) =>
|
||||
FormInput(
|
||||
key ?? this.key,
|
||||
validator ?? this.validator,
|
||||
metadata: metadata ?? this.metadata,
|
||||
);
|
||||
|
||||
FormInput clone() => copyWith(
|
||||
key: key,
|
||||
validator: validator,
|
||||
metadata: metadata,
|
||||
);
|
||||
@override
|
||||
bool? get stringify => true;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [key, validator, metadata];
|
||||
|
||||
FormInput copyWith({
|
||||
String? key,
|
||||
FormInputValidator? validator,
|
||||
FormInputMetadata? metadata,
|
||||
}) {
|
||||
return FormInput(
|
||||
key ?? this.key,
|
||||
validator ?? this.validator,
|
||||
metadata: metadata ?? this.metadata,
|
||||
);
|
||||
}
|
||||
|
||||
FormInput clone() {
|
||||
return copyWith(
|
||||
key: key,
|
||||
validator: validator,
|
||||
metadata: metadata,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
part of 'form.dart';
|
||||
|
||||
class FormInputMetadata<T> extends Equatable {
|
||||
class FormInputMetadata<T extends Object?> extends Equatable {
|
||||
final bool export;
|
||||
final String? _name;
|
||||
final T? extra;
|
||||
@ -27,30 +27,27 @@ class FormInputMetadata<T> extends Equatable {
|
||||
this.extra,
|
||||
String? name,
|
||||
}) : _name = name;
|
||||
|
||||
@override
|
||||
bool? get stringify => true;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [export, _name, extra];
|
||||
|
||||
FormInputMetadata<T> copyWith({
|
||||
bool? export,
|
||||
String? name,
|
||||
T? extra,
|
||||
}) {
|
||||
return FormInputMetadata<T>(
|
||||
export: export ?? this.export,
|
||||
name: name ?? _name,
|
||||
extra: extra ?? this.extra,
|
||||
);
|
||||
}
|
||||
}) =>
|
||||
FormInputMetadata<T>(
|
||||
export: export ?? this.export,
|
||||
name: name ?? _name,
|
||||
extra: extra ?? this.extra,
|
||||
);
|
||||
|
||||
FormInputMetadata<T> clone() {
|
||||
return copyWith(
|
||||
export: export,
|
||||
name: _name,
|
||||
extra: extra,
|
||||
);
|
||||
}
|
||||
FormInputMetadata<T> clone() => copyWith(
|
||||
export: export,
|
||||
name: _name,
|
||||
extra: extra,
|
||||
);
|
||||
|
||||
@override
|
||||
bool? get stringify => true;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [export, _name, extra];
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
part of 'form.dart';
|
||||
|
||||
/// {@template form_input}
|
||||
/// {@template form_input_validator}
|
||||
/// A [FormInputValidator] represents the value of a single form input field.
|
||||
/// It contains information about the [FormInputStatus], [value], as well
|
||||
/// as validation status.
|
||||
@ -25,26 +25,28 @@ part of 'form.dart';
|
||||
/// [FormInputValidator] instances.
|
||||
///
|
||||
/// ```dart
|
||||
/// enum FirstNameError { empty }
|
||||
/// class FirstName extends FormInputValidator<String, FirstNameError> {
|
||||
/// const FirstName.pure({String value = ''}) : super.pure(value);
|
||||
/// const FirstName.dirty({String value = ''}) : super.dirty(value);
|
||||
/// class Name extends FormInputValidator<String, ValidationStandardError> {
|
||||
/// const Name.pure({String value = ''}) : super.pure(value);
|
||||
/// const Name.dirty({String value = ''}) : super.dirty(value);
|
||||
///
|
||||
/// @override
|
||||
/// FirstNameError? validator(String value) {
|
||||
/// return value.isEmpty ? FirstNameError.empty : null;
|
||||
/// ValidationStandardError? validator(String? value) {
|
||||
/// if (value?.isEmpty ?? false) {
|
||||
/// return ValidationStandardError.empty
|
||||
/// }
|
||||
/// return value == null ? ValidationStandardError.invalid : null;
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// {@endtemplate}
|
||||
@immutable
|
||||
abstract class FormInputValidator<V, E> extends Equatable {
|
||||
abstract class FormInputValidator<V, E extends ValidationError>
|
||||
extends Equatable {
|
||||
const FormInputValidator._(this.value, [this.pure = true]);
|
||||
|
||||
/// Constructor which create a `pure` [FormInputValidator] with a given value.
|
||||
const FormInputValidator.pure(V value) : this._(value);
|
||||
|
||||
/// Constructor which create a `dirty` [FormInputValidator] with a
|
||||
/// Constructor which create a `dirty` [FormInputValidator] with a
|
||||
/// given value.
|
||||
const FormInputValidator.dirty(V value) : this._(value, false);
|
||||
|
||||
|
31
packages/wyatt_form_bloc/lib/src/form/form_validator.dart
Normal file
31
packages/wyatt_form_bloc/lib/src/form/form_validator.dart
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
part of 'form.dart';
|
||||
|
||||
/// {@template form_validator}
|
||||
/// A [FormValidator] represents the global validaton state of a Form.
|
||||
/// {@endtemplate}
|
||||
abstract class FormValidator {
|
||||
/// {@macro form_validator}
|
||||
const FormValidator();
|
||||
|
||||
bool isPure(FormData form) => form
|
||||
.validators<dynamic, ValidationError>()
|
||||
.every((validator) => validator.pure);
|
||||
|
||||
FormStatus validate(FormData form);
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
||||
|
||||
/// {@template every}
|
||||
/// Check and validate every input of a form
|
||||
/// {@endtemplate}
|
||||
class EveryInputValidator extends FormValidator {
|
||||
/// {@macro every}
|
||||
const EveryInputValidator() : super();
|
||||
|
||||
@override
|
||||
FormStatus validate(FormData form) {
|
||||
if (isPure(form)) {
|
||||
return FormStatus.pure;
|
||||
}
|
||||
|
||||
if (form
|
||||
.validators<dynamic, ValidationError>()
|
||||
.any((validator) => validator.valid == false)) {
|
||||
return FormStatus.invalid;
|
||||
}
|
||||
|
||||
return FormStatus.valid;
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'package:wyatt_form_bloc/src/enums/validation_error.dart';
|
||||
import 'package:wyatt_form_bloc/src/form/form.dart';
|
||||
|
||||
/// {@template regex_validator}
|
||||
/// Abstract regex validator for form input.
|
||||
/// {@endtemplate}
|
||||
abstract class RegexValidator<E extends ValidationError>
|
||||
extends FormInputValidator<String, E> {
|
||||
const RegexValidator.pure() : super.pure('');
|
||||
const RegexValidator.dirty([super.value = '']) : super.dirty();
|
||||
|
||||
RegExp get regex;
|
||||
/// If the value is **not** null, but empty.
|
||||
E get onEmpty;
|
||||
/// If value does not conform to regex.
|
||||
E get onError;
|
||||
|
||||
@override
|
||||
E? validator(String? value) {
|
||||
if (value?.isEmpty ?? false) {
|
||||
return onEmpty;
|
||||
}
|
||||
return regex.hasMatch(value ?? '') ? null : onError;
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'package:wyatt_form_bloc/src/enums/validation_error.dart';
|
||||
import 'package:wyatt_form_bloc/src/form/form.dart';
|
||||
|
||||
abstract class TextValidator<E extends ValidationError>
|
||||
extends FormInputValidator<String, E> {
|
||||
const TextValidator.pure() : super.pure('');
|
||||
const TextValidator.dirty([super.value = '']) : super.dirty();
|
||||
|
||||
/// If the value is **not** null, but empty.
|
||||
E get onEmpty;
|
||||
|
||||
/// If value is null.
|
||||
E get onNull;
|
||||
|
||||
@override
|
||||
E? validator(String? value) {
|
||||
if (value?.isEmpty ?? false) {
|
||||
return onEmpty;
|
||||
}
|
||||
return value != null ? null : onNull;
|
||||
}
|
||||
}
|
@ -20,7 +20,7 @@ import 'package:wyatt_form_bloc/src/form/form.dart';
|
||||
/// {@template boolean}
|
||||
/// Form input for a bool input
|
||||
/// {@endtemplate}
|
||||
class Boolean extends FormInputValidator<bool, ValidationError> {
|
||||
class Boolean extends FormInputValidator<bool, ValidationStandardError> {
|
||||
/// {@macro boolean}
|
||||
const Boolean.pure({bool? defaultValue = false})
|
||||
: super.pure(defaultValue ?? false);
|
||||
@ -29,7 +29,6 @@ class Boolean extends FormInputValidator<bool, ValidationError> {
|
||||
const Boolean.dirty({bool value = false}) : super.dirty(value);
|
||||
|
||||
@override
|
||||
ValidationError? validator(bool? value) {
|
||||
return value != null ? null : ValidationError.invalid;
|
||||
}
|
||||
ValidationStandardError? validator(bool? value) =>
|
||||
value != null ? null : ValidationStandardError.invalid;
|
||||
}
|
@ -21,7 +21,7 @@ import 'package:wyatt_form_bloc/src/form/form.dart';
|
||||
/// Form input for a confirmed password input.
|
||||
/// {@endtemplate}
|
||||
class ConfirmedPassword
|
||||
extends FormInputValidator<String, ValidationError> {
|
||||
extends FormInputValidator<String, ValidationStandardError> {
|
||||
/// {@macro confirmed_password}
|
||||
const ConfirmedPassword.pure({this.password = ''}) : super.pure('');
|
||||
|
||||
@ -33,7 +33,6 @@ class ConfirmedPassword
|
||||
final String password;
|
||||
|
||||
@override
|
||||
ValidationError? validator(String? value) {
|
||||
return password == value ? null : ValidationError.invalid;
|
||||
}
|
||||
ValidationStandardError? validator(String? value) =>
|
||||
password == value ? null : ValidationStandardError.invalid;
|
||||
}
|
@ -15,24 +15,25 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'package:wyatt_form_bloc/src/enums/enums.dart';
|
||||
import 'package:wyatt_form_bloc/src/form/form.dart';
|
||||
import 'package:wyatt_form_bloc/src/validators/inputs/base/regex_validator.dart';
|
||||
|
||||
/// {@template email}
|
||||
/// Form input for an email input.
|
||||
/// {@endtemplate}
|
||||
class Email extends FormInputValidator<String, ValidationError> {
|
||||
class Email extends RegexValidator<ValidationStandardError> {
|
||||
/// {@macro email}
|
||||
const Email.pure() : super.pure('');
|
||||
const Email.pure() : super.pure();
|
||||
|
||||
/// {@macro email}
|
||||
const Email.dirty([String value = '']) : super.dirty(value);
|
||||
|
||||
static final RegExp _emailRegExp = RegExp(
|
||||
r'[^@ \t\r\n]+@[^@ \t\r\n]+\.[^@ \t\r\n]+',
|
||||
);
|
||||
const Email.dirty([super.value = '']) : super.dirty();
|
||||
|
||||
@override
|
||||
ValidationError? validator(String? value) {
|
||||
return _emailRegExp.hasMatch(value ?? '') ? null : ValidationError.invalid;
|
||||
}
|
||||
ValidationStandardError get onEmpty => ValidationStandardError.empty;
|
||||
@override
|
||||
ValidationStandardError get onError => ValidationStandardError.invalid;
|
||||
|
||||
@override
|
||||
RegExp get regex => RegExp(
|
||||
r'[^@ \t\r\n]+@[^@ \t\r\n]+\.[^@ \t\r\n]+',
|
||||
);
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'package:wyatt_form_bloc/src/enums/validation_error.dart';
|
||||
import 'package:wyatt_form_bloc/src/validators/inputs/base/text_validator.dart';
|
||||
|
||||
class EnumValidator<E> extends TextValidator<ValidationStandardError> {
|
||||
/// {@macro text_string}
|
||||
const EnumValidator.pure() : super.pure();
|
||||
|
||||
/// {@macro text_string}
|
||||
EnumValidator.dirty(E value) : super.dirty(value.toString());
|
||||
|
||||
@override
|
||||
ValidationStandardError get onEmpty => ValidationStandardError.empty;
|
||||
|
||||
@override
|
||||
ValidationStandardError get onNull => ValidationStandardError.invalid;
|
||||
}
|
@ -15,24 +15,25 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'package:wyatt_form_bloc/src/enums/enums.dart';
|
||||
import 'package:wyatt_form_bloc/src/form/form.dart';
|
||||
import 'package:wyatt_form_bloc/src/validators/inputs/base/regex_validator.dart';
|
||||
|
||||
/// {@template iban}
|
||||
/// Form input for an IBAN input.
|
||||
/// {@endtemplate}
|
||||
class Iban extends FormInputValidator<String, ValidationError> {
|
||||
class Iban extends RegexValidator<ValidationStandardError> {
|
||||
/// {@macro iban}
|
||||
const Iban.pure() : super.pure('');
|
||||
const Iban.pure() : super.pure();
|
||||
|
||||
/// {@macro iban}
|
||||
const Iban.dirty([String value = '']) : super.dirty(value);
|
||||
|
||||
static final RegExp _regExp = RegExp(
|
||||
r'^(?:((?:IT|SM)\d{2}[A-Z]{1}\d{22})|(NL\d{2}[A-Z]{4}\d{10})|(LV\d{2}[A-Z]{4}\d{13})|((?:BG|GB|IE)\d{2}[A-Z]{4}\d{14})|(GI\d{2}[A-Z]{4}\d{15})|(RO\d{2}[A-Z]{4}\d{16})|(MT\d{2}[A-Z]{4}\d{23})|(NO\d{13})|((?:DK|FI)\d{16})|((?:SI)\d{17})|((?:AT|EE|LU|LT)\d{18})|((?:HR|LI|CH)\d{19})|((?:DE|VA)\d{20})|((?:AD|CZ|ES|MD|SK|SE)\d{22})|(PT\d{23})|((?:IS)\d{24})|((?:BE)\d{14})|((?:FR|MC|GR)\d{25})|((?:PL|HU|CY)\d{26}))$',
|
||||
);
|
||||
const Iban.dirty([super.value = '']) : super.dirty();
|
||||
|
||||
@override
|
||||
ValidationError? validator(String? value) {
|
||||
return _regExp.hasMatch(value ?? '') ? null : ValidationError.invalid;
|
||||
}
|
||||
ValidationStandardError get onEmpty => ValidationStandardError.empty;
|
||||
@override
|
||||
ValidationStandardError get onError => ValidationStandardError.invalid;
|
||||
|
||||
@override
|
||||
RegExp get regex => RegExp(
|
||||
r'^(?:((?:IT|SM)\d{2}[A-Z]{1}\d{22})|(NL\d{2}[A-Z]{4}\d{10})|(LV\d{2}[A-Z]{4}\d{13})|((?:BG|GB|IE)\d{2}[A-Z]{4}\d{14})|(GI\d{2}[A-Z]{4}\d{15})|(RO\d{2}[A-Z]{4}\d{16})|(MT\d{2}[A-Z]{4}\d{23})|(NO\d{13})|((?:DK|FI)\d{16})|((?:SI)\d{17})|((?:AT|EE|LU|LT)\d{18})|((?:HR|LI|CH)\d{19})|((?:DE|VA)\d{20})|((?:AD|CZ|ES|MD|SK|SE)\d{22})|(PT\d{23})|((?:IS)\d{24})|((?:BE)\d{14})|((?:FR|MC|GR)\d{25})|((?:PL|HU|CY)\d{26}))$',
|
||||
);
|
||||
}
|
@ -20,7 +20,8 @@ import 'package:wyatt_form_bloc/src/form/form.dart';
|
||||
/// {@template list_option}
|
||||
/// Form input for a list input
|
||||
/// {@endtemplate}
|
||||
class ListOption<T> extends FormInputValidator<List<T>, ValidationError> {
|
||||
class ListOption<T>
|
||||
extends FormInputValidator<List<T>, ValidationStandardError> {
|
||||
/// {@macro list_option}
|
||||
const ListOption.pure({List<T>? defaultValue})
|
||||
: super.pure(defaultValue ?? const []);
|
||||
@ -28,7 +29,7 @@ class ListOption<T> extends FormInputValidator<List<T>, ValidationError> {
|
||||
/// {@macro list_option}
|
||||
const ListOption.dirty({List<T>? value}) : super.dirty(value ?? const []);
|
||||
|
||||
ListOption select(T? v) {
|
||||
ListOption<T> select(T? v) {
|
||||
if (v == null) {
|
||||
return this;
|
||||
}
|
||||
@ -42,7 +43,8 @@ class ListOption<T> extends FormInputValidator<List<T>, ValidationError> {
|
||||
}
|
||||
|
||||
@override
|
||||
ValidationError? validator(List<T>? value) {
|
||||
return value?.isNotEmpty == true ? null : ValidationError.invalid;
|
||||
}
|
||||
ValidationStandardError? validator(List<T>? value) =>
|
||||
value?.isNotEmpty ?? false == true
|
||||
? null
|
||||
: ValidationStandardError.invalid;
|
||||
}
|
@ -15,22 +15,23 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'package:wyatt_form_bloc/src/enums/enums.dart';
|
||||
import 'package:wyatt_form_bloc/src/form/form.dart';
|
||||
import 'package:wyatt_form_bloc/src/validators/inputs/base/regex_validator.dart';
|
||||
|
||||
/// {@template name}
|
||||
/// Form input for a name input.
|
||||
/// {@endtemplate}
|
||||
class Name extends FormInputValidator<String, ValidationError> {
|
||||
class Name extends RegexValidator<ValidationStandardError> {
|
||||
/// {@macro name}
|
||||
const Name.pure() : super.pure('');
|
||||
const Name.pure() : super.pure();
|
||||
|
||||
/// {@macro name}
|
||||
const Name.dirty([String value = '']) : super.dirty(value);
|
||||
|
||||
static final RegExp _nameRegExp = RegExp(r"^([ \u00c0-\u01ffa-zA-Z'\-])+$");
|
||||
const Name.dirty([super.value = '']) : super.dirty();
|
||||
|
||||
@override
|
||||
ValidationError? validator(String? value) {
|
||||
return _nameRegExp.hasMatch(value ?? '') ? null : ValidationError.invalid;
|
||||
}
|
||||
ValidationStandardError get onEmpty => ValidationStandardError.empty;
|
||||
@override
|
||||
ValidationStandardError get onError => ValidationStandardError.invalid;
|
||||
|
||||
@override
|
||||
RegExp get regex => RegExp(r"^([ \u00c0-\u01ffa-zA-Z'\-])+$");
|
||||
}
|
@ -15,25 +15,23 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'package:wyatt_form_bloc/src/enums/enums.dart';
|
||||
import 'package:wyatt_form_bloc/src/form/form.dart';
|
||||
import 'package:wyatt_form_bloc/src/validators/inputs/base/regex_validator.dart';
|
||||
|
||||
/// {@template password}
|
||||
/// Form input for a password input.
|
||||
/// {@endtemplate}
|
||||
class Password extends FormInputValidator<String, ValidationError> {
|
||||
class Password extends RegexValidator<ValidationStandardError> {
|
||||
/// {@macro password}
|
||||
const Password.pure() : super.pure('');
|
||||
const Password.pure() : super.pure();
|
||||
|
||||
/// {@macro password}
|
||||
const Password.dirty([String value = '']) : super.dirty(value);
|
||||
|
||||
static final RegExp _passwordRegExp =
|
||||
RegExp(r'^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$');
|
||||
const Password.dirty([super.value = '']) : super.dirty();
|
||||
|
||||
@override
|
||||
ValidationError? validator(String? value) {
|
||||
return _passwordRegExp.hasMatch(value ?? '')
|
||||
? null
|
||||
: ValidationError.invalid;
|
||||
}
|
||||
ValidationStandardError get onEmpty => ValidationStandardError.empty;
|
||||
@override
|
||||
ValidationStandardError get onError => ValidationStandardError.invalid;
|
||||
|
||||
@override
|
||||
RegExp get regex => RegExp(r'^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$');
|
||||
}
|
@ -15,23 +15,24 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'package:wyatt_form_bloc/src/enums/enums.dart';
|
||||
import 'package:wyatt_form_bloc/src/form/form.dart';
|
||||
import 'package:wyatt_form_bloc/src/validators/inputs/base/regex_validator.dart';
|
||||
|
||||
/// {@template phone}
|
||||
/// Form input for a phone input.
|
||||
/// {@endtemplate}
|
||||
class Phone extends FormInputValidator<String, ValidationError> {
|
||||
class Phone extends RegexValidator<ValidationStandardError> {
|
||||
/// {@macro phone}
|
||||
const Phone.pure() : super.pure('');
|
||||
const Phone.pure() : super.pure();
|
||||
|
||||
/// {@macro phone}
|
||||
const Phone.dirty([String value = '']) : super.dirty(value);
|
||||
|
||||
static final RegExp _phoneRegExp =
|
||||
RegExp(r'^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$');
|
||||
const Phone.dirty([super.value = '']) : super.dirty();
|
||||
|
||||
@override
|
||||
ValidationError? validator(String? value) {
|
||||
return _phoneRegExp.hasMatch(value ?? '') ? null : ValidationError.invalid;
|
||||
}
|
||||
ValidationStandardError get onEmpty => ValidationStandardError.empty;
|
||||
@override
|
||||
ValidationStandardError get onError => ValidationStandardError.invalid;
|
||||
|
||||
@override
|
||||
RegExp get regex =>
|
||||
RegExp(r'^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$');
|
||||
}
|
@ -15,22 +15,23 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'package:wyatt_form_bloc/src/enums/enums.dart';
|
||||
import 'package:wyatt_form_bloc/src/form/form.dart';
|
||||
import 'package:wyatt_form_bloc/src/validators/inputs/base/regex_validator.dart';
|
||||
|
||||
/// {@template siren}
|
||||
/// Form input for a SIREN input.
|
||||
/// {@endtemplate}
|
||||
class Siren extends FormInputValidator<String, ValidationError> {
|
||||
class Siren extends RegexValidator<ValidationStandardError> {
|
||||
/// {@macro siren}
|
||||
const Siren.pure() : super.pure('');
|
||||
const Siren.pure() : super.pure();
|
||||
|
||||
/// {@macro siren}
|
||||
const Siren.dirty([String value = '']) : super.dirty(value);
|
||||
|
||||
static final RegExp _regExp = RegExp(r'(\d{9}|\d{3}[ ]\d{3}[ ]\d{3})$');
|
||||
const Siren.dirty([super.value = '']) : super.dirty();
|
||||
|
||||
@override
|
||||
ValidationError? validator(String? value) {
|
||||
return _regExp.hasMatch(value ?? '') ? null : ValidationError.invalid;
|
||||
}
|
||||
ValidationStandardError get onEmpty => ValidationStandardError.empty;
|
||||
@override
|
||||
ValidationStandardError get onError => ValidationStandardError.invalid;
|
||||
|
||||
@override
|
||||
RegExp get regex => RegExp(r'(\d{9}|\d{3}[ ]\d{3}[ ]\d{3})$');
|
||||
}
|
@ -15,20 +15,21 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'package:wyatt_form_bloc/src/enums/enums.dart';
|
||||
import 'package:wyatt_form_bloc/src/form/form.dart';
|
||||
import 'package:wyatt_form_bloc/src/validators/inputs/base/text_validator.dart';
|
||||
|
||||
/// {@template text_string}
|
||||
/// Form input for a text input
|
||||
/// {@endtemplate}
|
||||
class TextString extends FormInputValidator<String, ValidationError> {
|
||||
class TextString extends TextValidator<ValidationStandardError> {
|
||||
/// {@macro text_string}
|
||||
const TextString.pure() : super.pure('');
|
||||
const TextString.pure() : super.pure();
|
||||
|
||||
/// {@macro text_string}
|
||||
const TextString.dirty([String value = '']) : super.dirty(value);
|
||||
const TextString.dirty([super.value = '']) : super.dirty();
|
||||
|
||||
@override
|
||||
ValidationError? validator(String? value) {
|
||||
return (value?.isNotEmpty ?? false) ? null : ValidationError.invalid;
|
||||
}
|
||||
ValidationStandardError get onEmpty => ValidationStandardError.empty;
|
||||
|
||||
@override
|
||||
ValidationStandardError get onNull => ValidationStandardError.invalid;
|
||||
}
|
@ -14,13 +14,16 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
export 'boolean.dart';
|
||||
export 'confirmed_password.dart';
|
||||
export 'email.dart';
|
||||
export 'iban.dart';
|
||||
export 'list_option.dart';
|
||||
export 'name.dart';
|
||||
export 'password.dart';
|
||||
export 'phone.dart';
|
||||
export 'siren.dart';
|
||||
export 'text_string.dart';
|
||||
export 'inputs/base/regex_validator.dart';
|
||||
export 'inputs/base/text_validator.dart';
|
||||
export 'inputs/boolean.dart';
|
||||
export 'inputs/confirmed_password.dart';
|
||||
export 'inputs/email.dart';
|
||||
export 'inputs/enum_validator.dart';
|
||||
export 'inputs/iban.dart';
|
||||
export 'inputs/list_option.dart';
|
||||
export 'inputs/name.dart';
|
||||
export 'inputs/password.dart';
|
||||
export 'inputs/phone.dart';
|
||||
export 'inputs/siren.dart';
|
||||
export 'inputs/text_string.dart';
|
||||
|
@ -9,7 +9,6 @@ environment:
|
||||
dependencies:
|
||||
bloc: ^8.0.3
|
||||
equatable: ^2.0.3
|
||||
meta: ^1.7.0
|
||||
|
||||
dev_dependencies:
|
||||
test: ^1.21.4
|
||||
|
Loading…
x
Reference in New Issue
Block a user