gmana_form 0.0.1
gmana_form: ^0.0.1 copied to clipboard
Flutter form fields, validators, and submit controls for the Gmana ecosystem.
gmana_form #
Production-ready Flutter form building blocks for the Gmana ecosystem.
import 'package:gmana_form/gmana_form.dart';
What You Get #
- One generic text-field surface:
GTextField+GTextFieldConfig. - Friendly presets for common inputs: text, email, number, password, and confirm password.
- Typed validation powered by
gmana_validation. - A loading submit button that accepts either plain text or any custom child.
Quick Start #
final form = GFormController();
GForm(
controller: form,
autovalidateMode: AutovalidateMode.onUserInteraction,
child: Column(
children: [
GTextField.email(name: 'email'),
const SizedBox(height: 12),
GTextField.password(
name: 'password',
validationConfig: PasswordValidationConfig.strong(),
),
const SizedBox(height: 20),
GSubmitButton.text(
label: 'Sign in',
loading: isSubmitting,
onPressed: () {
if (form.validateAndSave()) {
submit(form.textValues());
}
},
),
],
),
)
Or let the package handle validate/save/loading:
GFormSubmitButton.text(
label: 'Sign in',
onSubmit: (values) async {
await auth.signIn(
email: values['email']!,
password: values['password']!,
);
},
)
Dispose the controller from your State:
@override
void dispose() {
form.dispose();
super.dispose();
}
Form Controller #
GFormController owns a GlobalKey<FormState> and lazily creates named text
controllers.
final form = GFormController();
GForm(
controller: form,
child: GTextField.email(name: 'email'),
);
if (form.validateAndSave()) {
await repository.save(form.textValues());
}
form.reset();
form.dispose();
You can still request a controller directly when another widget needs it:
final password = form.textController('password');
GTextField.password(controller: password)
Fields #
Use GTextFieldConfig for anything custom:
GTextField(
config: GTextFieldConfig(
controller: notesController,
label: 'Notes',
hint: 'Optional',
minLines: 3,
maxLines: 6,
textCapitalization: TextCapitalization.sentences,
prefixIcon: Icons.notes,
validator: (value) =>
value == null || value.trim().isEmpty ? 'Required' : null,
),
)
Use preset constructors when the intent is common:
GTextField.text(
name: 'name',
label: 'Full name',
validationConfig: const TextValidationConfig(minLength: 2),
)
GTextField.email(
name: 'email',
validationConfig: EmailValidationConfig.strict(),
)
GTextField.number(
name: 'age',
label: 'Age',
validationConfig: NumberValidationConfig.positiveInteger(min: 13, max: 120),
)
GTextField.password(
name: 'password',
textInputAction: TextInputAction.next,
)
GTextField.confirmPassword(
name: 'confirmPassword',
passwordName: 'password',
)
The preset widgets GEmailField, GNumberField, GPasswordField, and
GConfirmPasswordField are still exported for discoverability. They delegate to
the same GTextField preset constructors.
Advanced Customization #
Every preset accepts a configure hook so teams can keep the built-in defaults
and still modify config that is not exposed as a top-level constructor argument:
GTextField.email(
controller: email,
configure: (config) => config.copyWith(
suffixIcon: IconButton(
icon: const Icon(Icons.clear),
onPressed: email.clear,
),
),
)
For custom validation, pass validator. It runs after the package validator:
GTextField.email(
controller: email,
validator: (value) {
final domainAllowed = value?.endsWith('@company.com') ?? false;
return domainAllowed ? null : 'Use your company email';
},
)
Submit Button #
Use GFormSubmitButton inside a GForm when you want validation, saving,
loading state, and duplicate-submit protection handled for you:
GFormSubmitButton.text(
label: 'Create account',
onSubmit: (values) async {
await repository.createAccount(values);
},
)
For manual loading state, use GSubmitButton:
GSubmitButton.text(
label: 'Create account',
loading: isSubmitting,
onPressed: isSubmitting ? null : submit,
)
For richer button content:
GSubmitButton(
loading: isUploading,
onPressed: upload,
child: const Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.cloud_upload),
SizedBox(width: 8),
Text('Upload'),
],
),
)
GElevatedButton remains available as a compatibility wrapper.
Validator Adapter #
asFormValidator adapts any gmana_validation validator to Flutter's
FormField.validator signature:
final validator = asFormValidator(
validate: const EmailValidator().validate,
resolve: resolveEmailValidationIssue,
);
TextFormField(validator: validator)
Breaking Changes In This Refactor #
GFieldConfighas been replaced byGTextFieldConfig.- Field labels use
labeland hints usehint. validatorOverridehas been renamed tovalidator.GTextField.text,.email,.number,.password, and.confirmPasswordare now the preferred high-level API.GSubmitButtonis the preferred submit button API.