diff --git a/docs/pages/docs/checkbox.mdx b/docs/pages/docs/checkbox.mdx
index e9f719bec..7081675f0 100644
--- a/docs/pages/docs/checkbox.mdx
+++ b/docs/pages/docs/checkbox.mdx
@@ -8,7 +8,7 @@ On touch devices, it is recommended to use a [switch](/docs/switch) instead in m
-
+
```dart
@@ -25,6 +25,8 @@ On touch devices, it is recommended to use a [switch](/docs/switch) instead in m
FCheckbox(
enabled: true,
initialValue: true,
+ autofocus: true,
+ onChanged: (value) {},
);
```
@@ -33,25 +35,25 @@ FCheckbox(
### Disabled
-
-
-
-
- ```dart
- FCheckbox(
- enabled: false,
- );
- ```
-
+
+
+
+
+ ```dart
+ FCheckbox(
+ enabled: false,
+ );
+ ```
+
### Form
-
-
-
-
+
+
+
+
```dart
class LoginForm extends StatefulWidget {
const LoginForm({super.key});
@@ -96,12 +98,17 @@ FCheckbox(
const SizedBox(height: 30),
FButton(
label: const Text('Login'),
- onPress: () => _formKey.currentState!.validate(),
+ onPress: () {
+ if (!_formKey.currentState!.validate()) {
+ // Handle errors here.
+ return;
+ }
+ },
),
],
),
);
}
```
-
-
\ No newline at end of file
+
+
diff --git a/docs/pages/docs/switch.mdx b/docs/pages/docs/switch.mdx
index fd978942b..44013a4b1 100644
--- a/docs/pages/docs/switch.mdx
+++ b/docs/pages/docs/switch.mdx
@@ -2,23 +2,15 @@ import { Tabs } from 'nextra/components';
import { Widget } from "../../components/widget";
# Switch
-A switch that allows the user to toggle between checked and unchecked.
+A switch that allows the user to toggle between checked and unchecked. It can also be used in a form.
-
+
```dart
- final notifier = ValueNotifier(false);
-
- ValueListenableBuilder(
- valueListenable: notifier,
- builder: (context, value, __) => FSwitch(
- value: value,
- onChanged: (value) => notifier.value = value,
- ),
- );
+ FSwitch();
```
@@ -29,8 +21,92 @@ A switch that allows the user to toggle between checked and unchecked.
```dart
FSwitch(
- value: true,
+ enabled: true,
+ initialValue: true,
autofocus: true,
onChanged: (value) {},
);
```
+
+## Examples
+
+### Disabled
+
+
+
+
+
+
+ ```dart
+ FSwitch(
+ enabled: false,
+ );
+ ```
+
+
+
+### Form
+
+
+
+
+
+
+ ```dart
+ class LoginForm extends StatefulWidget {
+ const LoginForm({super.key});
+
+ @override
+ State createState() => _LoginFormState();
+ }
+
+ class _LoginFormState extends State {
+ final GlobalKey _formKey = GlobalKey();
+
+ @override
+ void initState() {
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) => Form(
+ key: _formKey,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ FTextField.email(
+ hint: 'janedoe@foruslabs.com',
+ help: const Text(''),
+ validator: (value) => (value?.contains('@') ?? false) ? null : 'Please enter a valid email.',
+ ),
+ const SizedBox(height: 4),
+ FTextField.password(
+ hint: '',
+ help: const Text(''),
+ validator: (value) => 8 <= (value?.length ?? 0) ? null : 'Password must be at least 8 characters long.',
+ ),
+ const SizedBox(height: 4),
+ Row(
+ children: [
+ const FSwitch(),
+ const SizedBox(width: 7),
+ Text('Remember password?', style: context.theme.typography.sm),
+ ],
+ ),
+ const SizedBox(height: 30),
+ FButton(
+ label: const Text('Login'),
+ onPress: () => {
+ if (!_formKey.currentState!.validate()) {
+ // Handle errors here.
+ return;
+ }
+ },
+ ),
+ ],
+ ),
+ );
+ }
+ ```
+
+
diff --git a/docs/pages/docs/text-field.mdx b/docs/pages/docs/text-field.mdx
index c2960d4f8..3af8a8d52 100644
--- a/docs/pages/docs/text-field.mdx
+++ b/docs/pages/docs/text-field.mdx
@@ -135,7 +135,7 @@ FTextField.multiline(
-
+
```dart
diff --git a/forui/CHANGELOG.md b/forui/CHANGELOG.md
index cbce83c65..ea9447369 100644
--- a/forui/CHANGELOG.md
+++ b/forui/CHANGELOG.md
@@ -1,3 +1,13 @@
+## Next
+
+### Enhancements
+* **Breaking** Change `FSwitch` to be usable in `Form`s.
+* **Breaking** Rename `FThemeData.checkBoxStyle` to `FThemeData.checkboxStyle` for consistency.
+
+### Fixes
+* Fix missing `style` parameter for `FCheckbox`.
+
+
## 0.2.0+3
### Fixes
diff --git a/forui/example/pubspec.lock b/forui/example/pubspec.lock
index aca3c7cab..26fa81a28 100644
--- a/forui/example/pubspec.lock
+++ b/forui/example/pubspec.lock
@@ -238,7 +238,7 @@ packages:
path: ".."
relative: true
source: path
- version: "0.1.0"
+ version: "0.2.0+3"
forui_assets:
dependency: "direct overridden"
description:
diff --git a/forui/lib/src/theme/theme_data.dart b/forui/lib/src/theme/theme_data.dart
index c00815fb9..6743e80fa 100644
--- a/forui/lib/src/theme/theme_data.dart
+++ b/forui/lib/src/theme/theme_data.dart
@@ -35,7 +35,7 @@ final class FThemeData with Diagnosticable {
final FCardStyle cardStyle;
/// The checkbox style.
- final FCheckboxStyle checkBoxStyle;
+ final FCheckboxStyle checkboxStyle;
/// The dialog style.
final FDialogStyle dialogStyle;
@@ -72,7 +72,7 @@ final class FThemeData with Diagnosticable {
required this.badgeStyles,
required this.buttonStyles,
required this.cardStyle,
- required this.checkBoxStyle,
+ required this.checkboxStyle,
required this.dialogStyle,
required this.headerStyle,
required this.progressStyle,
@@ -100,7 +100,7 @@ final class FThemeData with Diagnosticable {
badgeStyles: FBadgeStyles.inherit(colorScheme: colorScheme, typography: typography, style: style),
buttonStyles: FButtonStyles.inherit(colorScheme: colorScheme, typography: typography, style: style),
cardStyle: FCardStyle.inherit(colorScheme: colorScheme, typography: typography, style: style),
- checkBoxStyle: FCheckboxStyle.inherit(colorScheme: colorScheme),
+ checkboxStyle: FCheckboxStyle.inherit(colorScheme: colorScheme),
dialogStyle: FDialogStyle.inherit(colorScheme: colorScheme, typography: typography, style: style),
headerStyle: FHeaderStyles.inherit(colorScheme: colorScheme, typography: typography, style: style),
progressStyle: FProgressStyle.inherit(colorScheme: colorScheme, style: style),
@@ -136,7 +136,7 @@ final class FThemeData with Diagnosticable {
FBadgeStyles? badgeStyles,
FButtonStyles? buttonStyles,
FCardStyle? cardStyle,
- FCheckboxStyle? checkBoxStyle,
+ FCheckboxStyle? checkboxStyle,
FDialogStyle? dialogStyle,
FHeaderStyles? headerStyle,
FProgressStyle? progressStyle,
@@ -153,7 +153,7 @@ final class FThemeData with Diagnosticable {
badgeStyles: badgeStyles ?? this.badgeStyles,
buttonStyles: buttonStyles ?? this.buttonStyles,
cardStyle: cardStyle ?? this.cardStyle,
- checkBoxStyle: checkBoxStyle ?? this.checkBoxStyle,
+ checkboxStyle: checkboxStyle ?? this.checkboxStyle,
dialogStyle: dialogStyle ?? this.dialogStyle,
headerStyle: headerStyle ?? this.headerStyle,
progressStyle: progressStyle ?? this.progressStyle,
@@ -174,7 +174,7 @@ final class FThemeData with Diagnosticable {
..add(DiagnosticsProperty('badgeStyles', badgeStyles, level: DiagnosticLevel.debug))
..add(DiagnosticsProperty('buttonStyles', buttonStyles, level: DiagnosticLevel.debug))
..add(DiagnosticsProperty('cardStyle', cardStyle, level: DiagnosticLevel.debug))
- ..add(DiagnosticsProperty('checkBoxStyle', checkBoxStyle, level: DiagnosticLevel.debug))
+ ..add(DiagnosticsProperty('checkboxStyle', checkboxStyle, level: DiagnosticLevel.debug))
..add(DiagnosticsProperty('dialogStyle', dialogStyle, level: DiagnosticLevel.debug))
..add(DiagnosticsProperty('headerStyle', headerStyle, level: DiagnosticLevel.debug))
..add(DiagnosticsProperty('progressStyle', progressStyle))
@@ -196,7 +196,7 @@ final class FThemeData with Diagnosticable {
badgeStyles == other.badgeStyles &&
buttonStyles == other.buttonStyles &&
cardStyle == other.cardStyle &&
- checkBoxStyle == other.checkBoxStyle &&
+ checkboxStyle == other.checkboxStyle &&
dialogStyle == other.dialogStyle &&
headerStyle == other.headerStyle &&
progressStyle == other.progressStyle &&
@@ -214,7 +214,7 @@ final class FThemeData with Diagnosticable {
badgeStyles.hashCode ^
buttonStyles.hashCode ^
cardStyle.hashCode ^
- checkBoxStyle.hashCode ^
+ checkboxStyle.hashCode ^
dialogStyle.hashCode ^
headerStyle.hashCode ^
progressStyle.hashCode ^
diff --git a/forui/lib/src/widgets/checkbox.dart b/forui/lib/src/widgets/checkbox.dart
index 953c2815f..f9b153e3f 100644
--- a/forui/lib/src/widgets/checkbox.dart
+++ b/forui/lib/src/widgets/checkbox.dart
@@ -1,5 +1,4 @@
import 'package:flutter/foundation.dart';
-import 'package:flutter/semantics.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
@@ -7,18 +6,18 @@ import 'package:forui/forui.dart';
/// A checkbox control that allows the user to toggle between checked and not checked.
///
-/// On touch devices, it is recommended to use a [FSwitch] instead in most cases. A [FCheckbox] is internally a
-/// [FormField], therefore it can be used in a form.
+/// A [FCheckbox] is internally a [FormField], therefore it can be used in a form.
+///
+/// On touch devices, it is recommended to use a [FSwitch] instead of a [FCheckbox] in most cases.
///
/// See:
/// * https://forui.dev/docs/checkbox for working examples.
/// * [FCheckboxStyle] for customizing a checkbox's appearance.
class FCheckbox extends StatelessWidget {
- /// The semantic label of the dialog used by accessibility frameworks to announce screen transitions when the dialog
- /// is opened and closed.
- ///
- /// See also:
- /// * [SemanticsConfiguration.namesRoute], for a description of how this value is used.
+ /// The style. Defaults to [FThemeData.checkboxStyle].
+ final FCheckboxStyle? style;
+
+ /// The semantic label of the checkbox used by accessibility frameworks.
final String? semanticLabel;
/// Called when the user initiates a change to the FCheckBox's value: when they have checked or unchecked this box.
@@ -44,27 +43,27 @@ class FCheckbox extends StatelessWidget {
/// The returned value is exposed by the [FormFieldState.errorText] property.
final FormFieldValidator? validator;
- /// An optional value to initialize the form field to, or null otherwise.
+ /// An optional value to initialize the checkbox. Defaults to false.
final bool initialValue;
/// Whether the form is able to receive user input.
///
- /// Defaults to true. If [autovalidateMode] is not [AutovalidateMode.disabled], the field will be auto validated.
+ /// Defaults to true. If [autovalidateMode] is not [AutovalidateMode.disabled], the checkbox will be auto validated.
/// Likewise, if this field is false, the widget will not be validated regardless of [autovalidateMode].
final bool enabled;
- /// Used to enable/disable this form field auto validation and update its error text.
+ /// Used to enable/disable this checkbox auto validation and update its error text.
///
/// Defaults to [AutovalidateMode.disabled].
///
- /// If [AutovalidateMode.onUserInteraction], this FormField will only auto-validate after its content changes. If
+ /// If [AutovalidateMode.onUserInteraction], this checkbox will only auto-validate after its content changes. If
/// [AutovalidateMode.always], it will auto-validate even without user interaction. If [AutovalidateMode.disabled],
/// auto-validation will be disabled.
final AutovalidateMode? autovalidateMode;
- /// Restoration ID to save and restore the state of the form field.
+ /// Restoration ID to save and restore the state of the checkbox.
///
- /// Setting the restoration ID to a non-null value results in whether or not the form field validation persists.
+ /// Setting the restoration ID to a non-null value results in whether or not the checkbox validation persists.
///
/// The state of this widget is persisted in a [RestorationBucket] claimed from the surrounding [RestorationScope]
/// using the provided restoration ID.
@@ -75,6 +74,7 @@ class FCheckbox extends StatelessWidget {
/// Creates a [FCheckbox].
const FCheckbox({
+ this.style,
this.semanticLabel,
this.onChange,
this.autofocus = false,
@@ -91,7 +91,7 @@ class FCheckbox extends StatelessWidget {
@override
Widget build(BuildContext context) {
- final style = context.theme.checkBoxStyle;
+ final style = this.style ?? context.theme.checkboxStyle;
final stateStyle = enabled ? style.enabledStyle : style.disabledStyle;
return FocusableActionDetector(
@@ -160,6 +160,7 @@ class FCheckbox extends StatelessWidget {
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
+ ..add(DiagnosticsProperty('style', style))
..add(StringProperty('semanticLabel', semanticLabel))
..add(ObjectFlagProperty.has('onChange', onChange))
..add(DiagnosticsProperty('autofocus', autofocus))
diff --git a/forui/lib/src/widgets/switch.dart b/forui/lib/src/widgets/switch.dart
index 12b44e74c..2481bd265 100644
--- a/forui/lib/src/widgets/switch.dart
+++ b/forui/lib/src/widgets/switch.dart
@@ -1,6 +1,7 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
+import 'package:flutter/services.dart';
import 'package:meta/meta.dart';
@@ -8,7 +9,8 @@ import 'package:forui/forui.dart';
/// A control that allows the user to toggle between checked and unchecked.
///
-/// Typically used to toggle the on/off state of a single setting.
+/// Typically used to toggle the on/off state of a single setting. A [FSwitch] is internally a [FormField], therefore
+/// it can be used in a form.
///
/// See:
/// * https://forui.dev/docs/switch for working examples.
@@ -17,32 +19,14 @@ class FSwitch extends StatelessWidget {
/// The style. Defaults to [FThemeData.switchStyle].
final FSwitchStyle? style;
- /// True if this switch is checked, and false if unchecked.
- final bool value;
+ /// The semantic label of the switch used by accessibility frameworks.
+ final String? semanticLabel;
/// Called when the user toggles the switch on or off.
///
- /// The switch passes the new value to the callback but does not actually
- /// change state until the parent widget rebuilds the switch with the new
- /// value.
- ///
- /// If null, the switch will be displayed as disabled, which has a reduced opacity.
- ///
- /// The callback provided to onChanged should update the state of the parent
- /// [StatefulWidget] using the [State.setState] method, so that the parent
- /// gets rebuilt; for example:
- ///
- /// ```dart
- /// FSwitch(
- /// value: _giveVerse,
- /// onChanged: (bool newValue) {
- /// setState(() {
- /// _giveVerse = newValue;
- /// });
- /// },
- /// )
- /// ```
- final ValueChanged? onChanged;
+ /// The switch passes the new value to the callback but does not actually change state until the parent widget
+ /// rebuilds the switch with the new value.
+ final ValueChanged? onChange;
/// True if this widget will be selected as the initial focus when no other node in its scope is currently focused.
///
@@ -82,32 +66,91 @@ class FSwitch extends StatelessWidget {
/// By default, the drag start behavior is [DragStartBehavior.start].
final DragStartBehavior dragStartBehavior;
+ /// An optional method to call with the final value when the form is saved via [FormState.save].
+ final FormFieldSetter? onSave;
+
+ /// An optional method that validates an input. Returns an error string to display if the input is invalid, or null
+ /// otherwise.
+ ///
+ /// The returned value is exposed by the [FormFieldState.errorText] property.
+ final FormFieldValidator? validator;
+
+ /// An optional value to initialize the checkbox. Defaults to false.
+ final bool initialValue;
+
+ /// Whether the form is able to receive user input.
+ ///
+ /// Defaults to true. If [autovalidateMode] is not [AutovalidateMode.disabled], the checkbox will be auto validated.
+ /// Likewise, if this field is false, the widget will not be validated regardless of [autovalidateMode].
+ final bool enabled;
+
+ /// Used to enable/disable this switch auto validation and update its error text.
+ ///
+ /// Defaults to [AutovalidateMode.disabled].
+ ///
+ /// If [AutovalidateMode.onUserInteraction], this switch will only auto-validate after its content changes. If
+ /// [AutovalidateMode.always], it will auto-validate even without user interaction. If [AutovalidateMode.disabled],
+ /// auto-validation will be disabled.
+ final AutovalidateMode? autovalidateMode;
+
+ /// Restoration ID to save and restore the state of the switch.
+ ///
+ /// Setting the restoration ID to a non-null value results in whether or not the switch validation persists.
+ ///
+ /// The state of this widget is persisted in a [RestorationBucket] claimed from the surrounding [RestorationScope]
+ /// using the provided restoration ID.
+ ///
+ /// See also:
+ /// * [RestorationManager], which explains how state restoration works in Flutter.
+ final String? restorationId;
+
/// Creates a [FSwitch].
const FSwitch({
- required this.value,
- required this.onChanged,
this.style,
+ this.semanticLabel,
+ this.onChange,
this.autofocus = false,
this.focusNode,
this.onFocusChange,
this.dragStartBehavior = DragStartBehavior.start,
+ this.onSave,
+ this.validator,
+ this.initialValue = false,
+ this.enabled = true,
+ this.autovalidateMode,
+ this.restorationId,
super.key,
});
@override
Widget build(BuildContext context) {
final style = this.style ?? context.theme.switchStyle;
- return CupertinoSwitch(
- value: value,
- onChanged: onChanged,
- activeColor: style.checkedColor,
- trackColor: style.uncheckedColor,
- thumbColor: style.thumbColor,
- focusColor: style.focusColor,
- autofocus: autofocus,
- focusNode: focusNode,
- onFocusChange: onFocusChange,
- dragStartBehavior: dragStartBehavior,
+ return FormField(
+ builder: (state) {
+ final value = state.value ?? initialValue;
+ return Semantics(
+ label: semanticLabel,
+ enabled: enabled,
+ toggled: value,
+ child: CupertinoSwitch(
+ value: value,
+ onChanged: enabled
+ ? (value) {
+ state.didChange(value);
+ onChange?.call(!value);
+ }
+ : null,
+ activeColor: style.checkedColor,
+ trackColor: style.uncheckedColor,
+ thumbColor: style.thumbColor,
+ focusColor: style.focusColor,
+ autofocus: autofocus,
+ focusNode: focusNode,
+ onFocusChange: onFocusChange,
+ dragStartBehavior: dragStartBehavior,
+ ),
+ );
+ },
);
}
@@ -116,12 +159,18 @@ class FSwitch extends StatelessWidget {
super.debugFillProperties(properties);
properties
..add(DiagnosticsProperty('style', style))
- ..add(FlagProperty('value', value: value))
+ ..add(StringProperty('semanticLabel', semanticLabel))
..add(FlagProperty('autofocus', value: autofocus, defaultValue: false, ifTrue: 'autofocus'))
..add(EnumProperty('dragStartBehavior', dragStartBehavior, defaultValue: DragStartBehavior.start))
- ..add(DiagnosticsProperty('onChanged', onChanged))
+ ..add(DiagnosticsProperty('onChange', onChange))
..add(DiagnosticsProperty('focusNode', focusNode))
- ..add(DiagnosticsProperty('onFocusChange', onFocusChange));
+ ..add(DiagnosticsProperty('onFocusChange', onFocusChange))
+ ..add(ObjectFlagProperty.has('onSave', onSave))
+ ..add(ObjectFlagProperty.has('validator', validator))
+ ..add(DiagnosticsProperty('initialValue', initialValue))
+ ..add(DiagnosticsProperty('enabled', enabled))
+ ..add(EnumProperty('autovalidateMode', autovalidateMode))
+ ..add(StringProperty('restorationId', restorationId));
}
}
@@ -167,7 +216,7 @@ final class FSwitchStyle with Diagnosticable {
/// Returns a copy of this [FSwitchStyle] with the given properties replaced.
///
/// ```dart
- /// final style = FSwitch(
+ /// final style = FSwitchStyle(
/// checkedColor: Colors.black,
/// uncheckedColor: Colors.white,
/// // Other arguments omitted for brevity
diff --git a/forui/test/src/widgets/switch_golden_test.dart b/forui/test/src/widgets/switch_golden_test.dart
index 4c501c3b8..ab66a7600 100644
--- a/forui/test/src/widgets/switch_golden_test.dart
+++ b/forui/test/src/widgets/switch_golden_test.dart
@@ -18,8 +18,7 @@ void main() {
data: theme,
child: Center(
child: FSwitch(
- value: value,
- onChanged: (_) {},
+ initialValue: value,
),
),
),
@@ -37,9 +36,8 @@ void main() {
data: theme,
child: Center(
child: FSwitch(
- value: value,
+ initialValue: value,
autofocus: true,
- onChanged: (_) {},
),
),
),
@@ -57,9 +55,9 @@ void main() {
data: theme,
child: Center(
child: FSwitch(
- value: value,
+ enabled: false,
+ initialValue: value,
autofocus: true,
- onChanged: null,
),
),
),
diff --git a/samples/lib/main.dart b/samples/lib/main.dart
index 8896f9170..d377b51fb 100644
--- a/samples/lib/main.dart
+++ b/samples/lib/main.dart
@@ -115,5 +115,9 @@ class _AppRouter extends $_AppRouter {
path: '/switch/default',
page: SwitchRoute.page,
),
+ AutoRoute(
+ path: '/switch/form',
+ page: FormSwitchRoute.page,
+ ),
];
}
diff --git a/samples/lib/widgets/switch.dart b/samples/lib/widgets/switch.dart
index 1db81b25e..2ffa34768 100644
--- a/samples/lib/widgets/switch.dart
+++ b/samples/lib/widgets/switch.dart
@@ -7,22 +7,79 @@ import 'package:forui_samples/sample_scaffold.dart';
@RoutePage()
class SwitchPage extends SampleScaffold {
+ final bool enabled;
+
SwitchPage({
@queryParam super.theme,
+ @queryParam this.enabled = false,
});
@override
- Widget child(BuildContext context) {
- final notifier = ValueNotifier(false);
- return Padding(
- padding: const EdgeInsets.all(16),
- child: ValueListenableBuilder(
- valueListenable: notifier,
- builder: (context, value, __) => FSwitch(
- value: value,
- onChanged: (value) => notifier.value = value,
- ),
- ),
- );
+ Widget child(BuildContext context) => Padding(
+ padding: const EdgeInsets.all(16),
+ child: FSwitch(enabled: enabled),
+ );
+}
+
+@RoutePage()
+class FormSwitchPage extends SampleScaffold {
+ FormSwitchPage({
+ @queryParam super.theme,
+ });
+
+ @override
+ Widget child(BuildContext context) => const Padding(
+ padding: EdgeInsets.all(15.0),
+ child: LoginForm(),
+ );
+}
+
+class LoginForm extends StatefulWidget {
+ const LoginForm({super.key});
+
+ @override
+ State createState() => _LoginFormState();
+}
+
+class _LoginFormState extends State {
+ final GlobalKey _formKey = GlobalKey();
+
+ @override
+ void initState() {
+ super.initState();
}
+
+ @override
+ Widget build(BuildContext context) => Form(
+ key: _formKey,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ FTextField.email(
+ hint: 'janedoe@foruslabs.com',
+ help: const Text(''),
+ validator: (value) => (value?.contains('@') ?? false) ? null : 'Please enter a valid email.',
+ ),
+ const SizedBox(height: 4),
+ FTextField.password(
+ hint: '',
+ help: const Text(''),
+ validator: (value) => 8 <= (value?.length ?? 0) ? null : 'Password must be at least 8 characters long.',
+ ),
+ const SizedBox(height: 4),
+ Row(
+ children: [
+ const FSwitch(),
+ const SizedBox(width: 7),
+ Text('Remember password?', style: context.theme.typography.sm),
+ ],
+ ),
+ const SizedBox(height: 30),
+ FButton(
+ label: const Text('Login'),
+ onPress: () => _formKey.currentState!.validate(),
+ ),
+ ],
+ ),
+ );
}
diff --git a/samples/pubspec.lock b/samples/pubspec.lock
index 4d77f4b61..4fac45f3b 100644
--- a/samples/pubspec.lock
+++ b/samples/pubspec.lock
@@ -267,14 +267,14 @@ packages:
path: "../forui"
relative: true
source: path
- version: "0.1.0"
+ version: "0.2.0+3"
forui_assets:
dependency: "direct overridden"
description:
path: "../forui_assets"
relative: true
source: path
- version: "0.1.0"
+ version: "0.2.0"
frontend_server_client:
dependency: transitive
description: