feat: add metadata on inputs

This commit is contained in:
Hugo Pointcheval 2022-07-10 21:13:13 +02:00
parent 08ac6d8fda
commit d0f1d07363
Signed by: hugo
GPG Key ID: A9E8E9615379254F
20 changed files with 379 additions and 344 deletions

View File

@ -17,6 +17,7 @@
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';
@ -24,19 +25,19 @@ import 'package:wyatt_form_bloc/src/form/form.dart';
part 'form_data_state.dart';
abstract class FormDataCubit extends Cubit<FormDataState> {
FormDataCubit({required FormData entries})
: super(FormDataState(data: entries));
FormDataCubit({required FormData inputs})
: 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.
void dataChanged(String field, FormInput dirtyValue) {
/// - `dirtyValue`: The new value of the field. (Wrapped in a dirty validator)
void dataChanged(String field, FormInputValidator dirtyValue) {
final _form = state.data.clone();
if (_form.contains(field)) {
_form.update(field, dirtyValue);
_form.updateValidator(field, dirtyValue);
} else {
throw Exception('Form field $field not found');
}
@ -44,7 +45,7 @@ abstract class FormDataCubit extends Cubit<FormDataState> {
emit(
state.copyWith(
data: _form,
status: _form.selfValidate(),
status: _form.validate(),
),
);
}
@ -78,7 +79,7 @@ abstract class FormDataCubit extends Cubit<FormDataState> {
emit(
state.copyWith(
data: _form,
status: _form.selfValidate(),
status: _form.validate(),
),
);
}

View File

@ -17,7 +17,7 @@
part of 'form_data_cubit.dart';
@immutable
class FormDataState {
class FormDataState extends Equatable {
final FormStatus status;
final FormData data;
final String? errorMessage;
@ -41,23 +41,8 @@ class FormDataState {
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is FormDataState &&
other.status == status &&
other.data == data &&
other.errorMessage == errorMessage;
}
bool? get stringify => true;
@override
int get hashCode {
return status.hashCode ^ data.hashCode ^ errorMessage.hashCode;
}
@override
String toString() {
return 'FormDataState(status: $status, data: $data, '
'errorMessage: $errorMessage)';
}
List<Object?> get props => [status, data, errorMessage];
}

View File

@ -14,6 +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/>.
import 'package:wyatt_form_bloc/src/form/form.dart';
const Set<FormStatus> _validatedFormStatuses = <FormStatus>{
FormStatus.valid,
FormStatus.submissionInProgress,
FormStatus.submissionSuccess,
FormStatus.submissionFailure,
FormStatus.submissionCanceled,
};
/// Enum representing the status of a form at any given point in time.
enum FormStatus {
/// The form has not been touched.
@ -35,19 +45,8 @@ enum FormStatus {
submissionFailure,
/// The form submission has been canceled.
submissionCanceled
}
submissionCanceled;
const Set<FormStatus> _validatedFormStatuses = <FormStatus>{
FormStatus.valid,
FormStatus.submissionInProgress,
FormStatus.submissionSuccess,
FormStatus.submissionFailure,
FormStatus.submissionCanceled,
};
/// Useful extensions on [FormStatus]
extension FormStatusX on FormStatus {
/// Indicates whether the form is untouched.
bool get isPure => this == FormStatus.pure;
@ -76,4 +75,13 @@ extension FormStatusX on FormStatus {
/// Indicates whether the form submission has been canceled.
bool get isSubmissionCanceled => this == FormStatus.submissionCanceled;
/// Validate a list of inputs
static FormStatus validate(List<FormInput> inputs) {
return inputs.every((FormInput input) => input.validator.pure)
? FormStatus.pure
: inputs.any((FormInput input) => input.validator.valid == false)
? FormStatus.invalid
: FormStatus.valid;
}
}

View File

@ -1,19 +1,25 @@
// 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/>.
export 'form_data.dart';
export 'form_entry.dart';
export 'form_input.dart';
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';
part 'form_input.dart';
part 'form_input_metadata.dart';
part 'form_input_validator.dart';
part 'form_data.dart';

View File

@ -14,133 +14,164 @@
// 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: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/utils/list_equals.dart';
part of 'form.dart';
@immutable
class FormData {
const FormData(this._entries);
class FormData extends Equatable {
final List<FormInput> _inputs;
FormData.empty() : this(<FormEntry>[]);
const FormData(this._inputs);
const FormData.empty() : this(const <FormInput>[]);
final List<FormEntry> _entries;
List<FormEntry> get entries => _entries;
List<FormInput<T, ValidationError>> inputs<T>() {
return _entries
.map((FormEntry entry) => entry.input as FormInput<T, ValidationError>)
.toList();
}
static FormStatus validate(List<FormInput> inputs) {
return inputs.every((FormInput element) => element.pure)
? FormStatus.pure
: inputs.any((FormInput input) => input.valid == false)
? FormStatus.invalid
: FormStatus.valid;
}
FormStatus selfValidate() {
return validate(inputs<dynamic>());
}
FormInput<T, ValidationError> input<T>(String key) {
/// Returns the input for the associated key
FormInput inputByKey(String key) {
if (contains(key)) {
return _entries.firstWhere((FormEntry entry) => entry.key == key).input
as FormInput<T, ValidationError>;
return _inputs.firstWhere((FormInput input) => input.key == key);
} else {
throw Exception('FormInput with key `$key` does not exist in form');
}
}
bool contains(String key) {
return _entries.any((FormEntry entry) => entry.key == key);
}
FormData intersection(FormData other) {
final List<FormEntry> entries = <FormEntry>[];
for (final FormEntry entry in _entries) {
if (other.contains(entry.key)) {
entries.add(entry);
}
}
return FormData(entries);
}
FormData difference(FormData other) {
final List<FormEntry> entries = <FormEntry>[];
for (final FormEntry otherEntry in other._entries) {
if (!contains(otherEntry.key)) {
entries.add(otherEntry);
}
}
for (final FormEntry entry in _entries) {
if (!other.contains(entry.key)) {
entries.add(entry);
}
}
return FormData(entries);
}
FormData union(FormData other) {
final List<FormEntry> entries = <FormEntry>[];
for (final FormEntry entry in _entries) {
entries.add(entry);
}
for (final FormEntry otherEntry in other._entries) {
if (!contains(otherEntry.key)) {
entries.add(otherEntry);
}
}
return FormData(entries);
}
void update(String key, FormInput input) {
/// Updates a input (perform a replace at index).
void updateInput(String key, FormInput input) {
if (contains(key)) {
final index = _entries.indexOf(
_entries.firstWhere((FormEntry entry) => entry.key == key),
final index = _inputs.indexOf(
inputByKey(key),
);
_entries[index] = _entries[index].copyWith(input: input);
_inputs[index] = input;
}
}
/// Updates validator of a given input. (perform copyWith)
void updateValidator(String key, FormInputValidator dirtyValue) {
if (contains(key)) {
final index = _inputs.indexOf(
inputByKey(key),
);
_inputs[index] = _inputs[index].copyWith(validator: dirtyValue);
}
}
/// Updates metadata of a given input. (perform copyWith)
void updateMetadata(String key, FormInputMetadata meta) {
if (contains(key)) {
final index = _inputs.indexOf(
inputByKey(key),
);
_inputs[index] = _inputs[index].copyWith(metadata: meta);
}
}
/// 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 inputByKey(key).validator as T;
}
/// Returns a validation error if the [FormInputValidator] is invalid.
/// Returns null if the [FormInputValidator] is valid.
E? errorOf<V, E>(String key) {
return (inputByKey(key).validator as FormInputValidator<V, 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 (inputByKey(key).validator as FormInputValidator<V, E>).value;
}
/// Returns `true` if the [FormInputValidator] is not valid.
/// Same as `E? errorOf<V, E>(String key) != null`
bool isNotValid(String key) {
return !inputByKey(key).validator.valid;
}
/// Returns the metadata associated. With `M` the type of extra data.
FormInputMetadata<M> metadataOf<M>(String key) {
return inputByKey(key).metadata as FormInputMetadata<M>;
}
/// Validate self inputs.
FormStatus validate() {
return FormStatus.validate(_inputs);
}
/// Check if this contains an input with the given key.
bool contains(String key) {
return _inputs.any((FormInput input) => input.key == key);
}
/// Makes an intersection set operation and returns newly created [FormData]
FormData intersection(FormData other) {
final List<FormInput> inputs = <FormInput>[];
for (final FormInput i in _inputs) {
if (other.contains(i.key)) {
inputs.add(i);
}
}
return FormData(inputs);
}
/// Makes a difference set operation and returns newly created [FormData]
FormData difference(FormData other) {
final List<FormInput> inputs = <FormInput>[];
for (final FormInput i in other._inputs) {
if (!contains(i.key)) {
inputs.add(i);
}
}
for (final FormInput i in _inputs) {
if (!other.contains(i.key)) {
inputs.add(i);
}
}
return FormData(inputs);
}
/// Makes an union set operation and returns newly created [FormData]
FormData union(FormData other) {
final List<FormInput> inputs = <FormInput>[];
for (final FormInput i in _inputs) {
inputs.add(i);
}
for (final FormInput i in other._inputs) {
if (!contains(i.key)) {
inputs.add(i);
}
}
return FormData(inputs);
}
/// Deeply copy this.
FormData clone() {
return FormData(
_entries.map((FormEntry entry) => entry.clone()).toList(),
_inputs.map((FormInput input) => input.clone()).toList(),
);
}
/// Export this to [Map] format.
Map<String, dynamic> toMap() {
final map = <String, dynamic>{};
for (final entry in _entries) {
if (entry.export) {
map[entry.name] = entry.input.value;
for (final input in _inputs) {
if (input.metadata.export) {
map[input.name] = input.validator.value;
}
}
return map;
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is FormData && listEquals(other._entries, _entries);
}
bool? get stringify => true;
@override
int get hashCode => _entries.hashCode;
@override
String toString() => 'FormData(entries: $_entries)';
List<Object?> get props => _inputs;
}

View File

@ -1,79 +0,0 @@
// 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:meta/meta.dart';
import 'package:wyatt_form_bloc/src/form/form.dart';
@immutable
class FormEntry {
const FormEntry(this.key, this.input, {this.export = true, String? name})
: _field = name ?? key;
final String key;
final FormInput input;
final bool export;
final String _field;
String get name => _field;
FormEntry copyWith({
String? key,
FormInput? input,
bool? export,
String? name,
}) {
return FormEntry(
key ?? this.key,
input ?? this.input,
export: export ?? this.export,
name: name,
);
}
FormEntry clone() {
return FormEntry(
key,
input,
export: export,
name: name,
);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is FormEntry &&
other.key == key &&
other.input == input &&
other.export == export &&
other.name == name;
}
@override
int get hashCode {
return key.hashCode ^
input.hashCode ^
export.hashCode ^
name.hashCode;
}
@override
String toString() {
return 'FormEntry(key: $key, input: $input, '
'export: $export, name: $name)';
}
}

View File

@ -1,3 +1,4 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
// Copyright (C) 2022 WYATT GROUP
// Please see the AUTHORS file for details.
//
@ -14,98 +15,45 @@
// 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:meta/meta.dart';
import 'package:wyatt_form_bloc/src/enums/enums.dart';
part of 'form.dart';
/// {@template form_input}
/// A [FormInput] represents the value of a single form input field.
/// It contains information about the [FormInputStatus], [value], as well
/// as validation status.
///
/// [FormInput] should be extended to define custom [FormInput] instances.
///
/// ```dart
/// enum FirstNameError { empty }
/// class FirstName extends FormInput<String, FirstNameError> {
/// const FirstName.pure({String value = ''}) : super.pure(value);
/// const FirstName.dirty({String value = ''}) : super.dirty(value);
///
/// @override
/// FirstNameError? validator(String value) {
/// return value.isEmpty ? FirstNameError.empty : null;
/// }
/// }
/// ```
/// {@endtemplate}
@immutable
abstract class FormInput<T, E> {
const FormInput._(this.value, [this.pure = true]);
class FormInput extends Equatable {
final String key;
final FormInputValidator validator;
final FormInputMetadata metadata;
/// Constructor which create a `pure` [FormInput] with a given value.
const FormInput.pure(T value) : this._(value);
String get name => metadata._name ?? key;
/// Constructor which create a `dirty` [FormInput] with a given value.
const FormInput.dirty(T value) : this._(value, false);
/// The value of the given [FormInput].
/// For example, if you have a `FormInput` for `FirstName`,
/// the value could be 'Joe'.
final T value;
/// If the [FormInput] is pure (has been touched/modified).
/// Typically when the `FormInput` is initially created,
/// it is created using the `FormInput.pure` constructor to
/// signify that the user has not modified it.
///
/// For subsequent changes (in response to user input), the
/// `FormInput.dirty` constructor should be used to signify that
/// the `FormInput` has been manipulated.
final bool pure;
/// The [FormInputStatus] which can be one of the following:
/// * [FormInputStatus.pure]
/// - if the input has not been modified.
/// * [FormInputStatus.invalid]
/// - if the input has been modified and validation failed.
/// * [FormInputStatus.valid]
/// - if the input has been modified and validation succeeded.
FormInputStatus get status => pure
? FormInputStatus.pure
: valid
? FormInputStatus.valid
: FormInputStatus.invalid;
/// Returns a validation error if the [FormInput] is invalid.
/// Returns `null` if the [FormInput] is valid.
E? get error => validator(value);
/// Whether the [FormInput] value is valid according to the
/// overridden `validator`.
///
/// Returns `true` if `validator` returns `null` for the
/// current [FormInput] value and `false` otherwise.
bool get valid => validator(value) == null;
/// Whether the [FormInput] value is not valid.
/// A value is invalid when the overridden `validator`
/// returns an error (non-null value).
bool get invalid => status == FormInputStatus.invalid;
/// A function that must return a validation error if the provided
/// [value] is invalid and `null` otherwise.
E? validator(T value);
const FormInput(
this.key,
this.validator, {
// ignore: avoid_redundant_argument_values
this.metadata = const FormInputMetadata<void>(export: true),
});
@override
int get hashCode => value.hashCode ^ pure.hashCode;
bool? get stringify => true;
@override
bool operator ==(Object other) {
if (other.runtimeType != runtimeType) return false;
return other is FormInput<T, E> &&
other.value == value &&
other.pure == pure;
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,
);
}
@override
String toString() => 'FormInput<$runtimeType>(value: $value, pure: $pure)';
FormInput clone() {
return copyWith(
key: key,
validator: validator,
metadata: metadata,
);
}
}

View File

@ -0,0 +1,56 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
// 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';
class FormInputMetadata<T> extends Equatable {
final bool export;
final String? _name;
final T? extra;
const FormInputMetadata({
this.export = true,
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> clone() {
return copyWith(
export: export,
name: _name,
extra: extra,
);
}
}

View File

@ -0,0 +1,104 @@
// 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_input}
/// A [FormInputValidator] represents the value of a single form input field.
/// It contains information about the [FormInputStatus], [value], as well
/// as validation status.
///
/// [FormInputValidator] should be extended to define custom
/// [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);
///
/// @override
/// FirstNameError? validator(String value) {
/// return value.isEmpty ? FirstNameError.empty : null;
/// }
/// }
/// ```
/// {@endtemplate}
@immutable
abstract class FormInputValidator<V, E> 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
/// given value.
const FormInputValidator.dirty(V value) : this._(value, false);
/// The value of the given [FormInputValidator].
/// For example, if you have a `FormInputValidator` for `FirstName`,
/// the value could be 'Joe'.
final V value;
/// If the [FormInputValidator] is pure (has been touched/modified).
/// Typically when the `FormInputValidator` is initially created,
/// it is created using the `FormInputValidator.pure` constructor to
/// signify that the user has not modified it.
///
/// For subsequent changes (in response to user input), the
/// `FormInputValidator.dirty` constructor should be used to signify that
/// the `FormInputValidator` has been manipulated.
final bool pure;
/// The [FormInputStatus] which can be one of the following:
/// * [FormInputStatus.pure]
/// - if the input has not been modified.
/// * [FormInputStatus.invalid]
/// - if the input has been modified and validation failed.
/// * [FormInputStatus.valid]
/// - if the input has been modified and validation succeeded.
FormInputStatus get status => pure
? FormInputStatus.pure
: valid
? FormInputStatus.valid
: FormInputStatus.invalid;
/// Returns a validation error if the [FormInputValidator] is invalid.
/// Returns `null` if the [FormInputValidator] is valid.
E? get error => validator(value);
/// Whether the [FormInputValidator] value is valid according to the
/// overridden `validator`.
///
/// Returns `true` if `validator` returns `null` for the
/// current [FormInputValidator] value and `false` otherwise.
bool get valid => validator(value) == null;
/// Whether the [FormInputValidator] value is not valid.
/// A value is invalid when the overridden `validator`
/// returns an error (non-null value).
bool get invalid => status == FormInputStatus.invalid;
/// A function that must return a validation error if the provided
/// [value] is invalid and `null` otherwise.
E? validator(V value);
@override
bool? get stringify => true;
@override
List<Object?> get props => [value, pure];
}

View File

@ -1,25 +0,0 @@
// 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/>.
bool listEquals<T>(List<T>? a, List<T>? b) {
if (a == null) return b == null;
if (b == null || a.length != b.length) return false;
if (identical(a, b)) return true;
for (int index = 0; index < a.length; index += 1) {
if (a[index] != b[index]) return false;
}
return true;
}

View File

@ -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 FormInput<bool, ValidationError> {
class Boolean extends FormInputValidator<bool, ValidationError> {
/// {@macro boolean}
const Boolean.pure({bool? defaultValue = false})
: super.pure(defaultValue ?? false);

View File

@ -21,7 +21,7 @@ import 'package:wyatt_form_bloc/src/form/form.dart';
/// Form input for a confirmed password input.
/// {@endtemplate}
class ConfirmedPassword
extends FormInput<String, ValidationError> {
extends FormInputValidator<String, ValidationError> {
/// {@macro confirmed_password}
const ConfirmedPassword.pure({this.password = ''}) : super.pure('');

View File

@ -20,7 +20,7 @@ import 'package:wyatt_form_bloc/src/form/form.dart';
/// {@template email}
/// Form input for an email input.
/// {@endtemplate}
class Email extends FormInput<String, ValidationError> {
class Email extends FormInputValidator<String, ValidationError> {
/// {@macro email}
const Email.pure() : super.pure('');
@ -28,7 +28,7 @@ class Email extends FormInput<String, ValidationError> {
const Email.dirty([String value = '']) : super.dirty(value);
static final RegExp _emailRegExp = RegExp(
r'^[a-zA-Z0-9.!#$%&*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$',
r'[^@ \t\r\n]+@[^@ \t\r\n]+\.[^@ \t\r\n]+',
);
@override

View File

@ -20,7 +20,7 @@ import 'package:wyatt_form_bloc/src/form/form.dart';
/// {@template iban}
/// Form input for an IBAN input.
/// {@endtemplate}
class Iban extends FormInput<String, ValidationError> {
class Iban extends FormInputValidator<String, ValidationError> {
/// {@macro iban}
const Iban.pure() : super.pure('');

View File

@ -20,7 +20,7 @@ import 'package:wyatt_form_bloc/src/form/form.dart';
/// {@template list_option}
/// Form input for a list input
/// {@endtemplate}
class ListOption<T> extends FormInput<List<T>, ValidationError> {
class ListOption<T> extends FormInputValidator<List<T>, ValidationError> {
/// {@macro list_option}
const ListOption.pure({List<T>? defaultValue})
: super.pure(defaultValue ?? const []);

View File

@ -20,7 +20,7 @@ import 'package:wyatt_form_bloc/src/form/form.dart';
/// {@template name}
/// Form input for a name input.
/// {@endtemplate}
class Name extends FormInput<String, ValidationError> {
class Name extends FormInputValidator<String, ValidationError> {
/// {@macro name}
const Name.pure() : super.pure('');

View File

@ -20,7 +20,7 @@ import 'package:wyatt_form_bloc/src/form/form.dart';
/// {@template password}
/// Form input for a password input.
/// {@endtemplate}
class Password extends FormInput<String, ValidationError> {
class Password extends FormInputValidator<String, ValidationError> {
/// {@macro password}
const Password.pure() : super.pure('');

View File

@ -20,7 +20,7 @@ import 'package:wyatt_form_bloc/src/form/form.dart';
/// {@template phone}
/// Form input for a phone input.
/// {@endtemplate}
class Phone extends FormInput<String, ValidationError> {
class Phone extends FormInputValidator<String, ValidationError> {
/// {@macro phone}
const Phone.pure() : super.pure('');

View File

@ -20,7 +20,7 @@ import 'package:wyatt_form_bloc/src/form/form.dart';
/// {@template siren}
/// Form input for a SIREN input.
/// {@endtemplate}
class Siren extends FormInput<String, ValidationError> {
class Siren extends FormInputValidator<String, ValidationError> {
/// {@macro siren}
const Siren.pure() : super.pure('');

View File

@ -20,7 +20,7 @@ import 'package:wyatt_form_bloc/src/form/form.dart';
/// {@template text_string}
/// Form input for a text input
/// {@endtemplate}
class TextString extends FormInput<String, ValidationError> {
class TextString extends FormInputValidator<String, ValidationError> {
/// {@macro text_string}
const TextString.pure() : super.pure('');