From 0c6ba1d356dd7a8b68f5001701d904108a124014 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 1 Jul 2024 23:18:41 +0800 Subject: [PATCH 1/7] Checkbox prototype --- samples/lib/main.dart | 85 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/samples/lib/main.dart b/samples/lib/main.dart index 90305cc4c..5b4651107 100644 --- a/samples/lib/main.dart +++ b/samples/lib/main.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart' hide DialogRoute; import 'package:auto_route/auto_route.dart'; import 'package:flutter_web_plugins/flutter_web_plugins.dart'; +import 'package:forui/forui.dart'; import 'package:forui_samples/main.gr.dart'; import 'package:forui_samples/sample_scaffold.dart'; @@ -28,9 +29,91 @@ class ForuiSamples extends StatelessWidget { @RoutePage() class EmptyPage extends SampleScaffold { @override - Widget child(BuildContext context) => const Placeholder(); + Widget child(BuildContext context) { + final notifier = ValueNotifier(true); + return Row( + children: [ + ValueListenableBuilder( + valueListenable: notifier, + builder: (context, value, __) => FCheckBox( + value: value, + // onChanged: (value) => notifier.value = value, + ), + ), + SizedBox(width: 10), + Text('I accept the terms and conditions'), + ], + ); + } } + +class FCheckBox extends StatefulWidget { + final String? semanticLabel; + final bool value; + final bool autofocus; + final FocusNode? focusNode; + final ValueChanged? onFocusChange; + + const FCheckBox({ + required this.value, + this.semanticLabel, + this.autofocus = false, + this.focusNode, + this.onFocusChange, + super.key, + }); + + @override + State createState() => _FCheckBoxState(); +} + +class _FCheckBoxState extends State { + @override + Widget build(BuildContext context) { + final FThemeData(:style, :colorScheme) = context.theme; + + return Semantics( + label: widget.semanticLabel, + checked: widget.value, + child: SizedBox.square( + dimension: 18, + child: FocusableActionDetector( + autofocus: widget.autofocus, + focusNode: widget.focusNode, + onFocusChange: widget.onFocusChange, + child: MouseRegion( + cursor: SystemMouseCursors.click, + child: DecoratedBox( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4), + border: Border.all( + color: colorScheme.foreground, + width: 0.6, + ), + color: widget.value ? colorScheme.foreground : colorScheme.background, + ), + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 100), + child: widget.value ? + FAssets.icons.check( + height: 14, + width: 14, + colorFilter: ColorFilter.mode( + colorScheme.background, + BlendMode.srcIn, + ), + ) : null, + ), + ), + ), + ), + ), + ); + } +} + + @AutoRouterConfig() class _AppRouter extends $_AppRouter { @override From 65cd13e5e8d46dddbb2f7501855a580d3b68bc73 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Tue, 2 Jul 2024 19:00:01 +0800 Subject: [PATCH 2/7] Add fleshed-out check-box --- docs/pages/docs/check-box.mdx | 45 +++ docs/pages/docs/text-field.mdx | 2 +- forui/lib/src/theme/theme_data.dart | 10 + forui/lib/src/widgets/checkbox.dart | 338 ++++++++++++++++++ .../src/widgets/text_field/text_field.dart | 2 +- forui/lib/widgets.dart | 1 + .../check-box/zinc-dark-disabled-value.png | Bin 0 -> 22742 bytes .../check-box/zinc-dark-enabled-no-value.png | Bin 0 -> 22202 bytes .../check-box/zinc-dark-enabled-value.png | Bin 0 -> 22348 bytes .../check-box/zinc-light-disabled-value.png | Bin 0 -> 22695 bytes .../check-box/zinc-light-enabled-no-value.png | Bin 0 -> 22196 bytes .../check-box/zinc-light-enabled-value.png | Bin 0 -> 22392 bytes .../src/widgets/checkbox_golden_test.dart | 38 ++ samples/lib/main.dart | 89 +---- samples/lib/widgets/check_box.dart | 27 ++ 15 files changed, 466 insertions(+), 86 deletions(-) create mode 100644 docs/pages/docs/check-box.mdx create mode 100644 forui/lib/src/widgets/checkbox.dart create mode 100644 forui/test/golden/check-box/zinc-dark-disabled-value.png create mode 100644 forui/test/golden/check-box/zinc-dark-enabled-no-value.png create mode 100644 forui/test/golden/check-box/zinc-dark-enabled-value.png create mode 100644 forui/test/golden/check-box/zinc-light-disabled-value.png create mode 100644 forui/test/golden/check-box/zinc-light-enabled-no-value.png create mode 100644 forui/test/golden/check-box/zinc-light-enabled-value.png create mode 100644 forui/test/src/widgets/checkbox_golden_test.dart create mode 100644 samples/lib/widgets/check_box.dart diff --git a/docs/pages/docs/check-box.mdx b/docs/pages/docs/check-box.mdx new file mode 100644 index 000000000..95c280904 --- /dev/null +++ b/docs/pages/docs/check-box.mdx @@ -0,0 +1,45 @@ +import { Tabs } from 'nextra/components'; +import { Widget } from "../../components/widget"; + +# Check box +A control that allows the user to toggle between checked and not checked. It can also be used in a form. + +On touch devices, it is recommended to use a [switch](/docs/switch) instead in most cases. + + + + + + + ```dart + FCheckBox(); + ``` + + + +## Usage + +### `FCheckBox(...)` + +```dart +FCheckBox( + enabled: true, + initialValue: true, +); +``` + +## Examples + +### Disabled + + + + + + + ```dart + FCheckBox(); + ``` + + + diff --git a/docs/pages/docs/text-field.mdx b/docs/pages/docs/text-field.mdx index 23d7e871b..c2960d4f8 100644 --- a/docs/pages/docs/text-field.mdx +++ b/docs/pages/docs/text-field.mdx @@ -1,7 +1,7 @@ import { Tabs } from 'nextra/components'; import { Widget } from '../../components/widget'; -# Text Fields +# Text Field A text field lets the user enter text, either with hardware keyboard or with an onscreen keyboard. It can also be used in a form. diff --git a/forui/lib/src/theme/theme_data.dart b/forui/lib/src/theme/theme_data.dart index 9a24dbea4..e78d28136 100644 --- a/forui/lib/src/theme/theme_data.dart +++ b/forui/lib/src/theme/theme_data.dart @@ -34,6 +34,9 @@ final class FThemeData with Diagnosticable { /// The card style. final FCardStyle cardStyle; + /// The check box style. + final FCheckBoxStyle checkBoxStyle; + /// The dialog style. final FDialogStyle dialogStyle; @@ -69,6 +72,7 @@ final class FThemeData with Diagnosticable { required this.badgeStyles, required this.buttonStyles, required this.cardStyle, + required this.checkBoxStyle, required this.dialogStyle, required this.headerStyle, required this.progressStyle, @@ -96,6 +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), 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), @@ -131,6 +136,7 @@ final class FThemeData with Diagnosticable { FBadgeStyles? badgeStyles, FButtonStyles? buttonStyles, FCardStyle? cardStyle, + FCheckBoxStyle? checkBoxStyle, FDialogStyle? dialogStyle, FHeaderStyles? headerStyle, FProgressStyle? progressStyle, @@ -147,6 +153,7 @@ final class FThemeData with Diagnosticable { badgeStyles: badgeStyles ?? this.badgeStyles, buttonStyles: buttonStyles ?? this.buttonStyles, cardStyle: cardStyle ?? this.cardStyle, + checkBoxStyle: checkBoxStyle ?? this.checkBoxStyle, dialogStyle: dialogStyle ?? this.dialogStyle, headerStyle: headerStyle ?? this.headerStyle, progressStyle: progressStyle ?? this.progressStyle, @@ -167,6 +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('dialogStyle', dialogStyle, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('headerStyle', headerStyle, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('progressStyle', progressStyle)) @@ -188,6 +196,7 @@ final class FThemeData with Diagnosticable { badgeStyles == other.badgeStyles && buttonStyles == other.buttonStyles && cardStyle == other.cardStyle && + checkBoxStyle == other.checkBoxStyle && dialogStyle == other.dialogStyle && headerStyle == other.headerStyle && progressStyle == other.progressStyle && @@ -205,6 +214,7 @@ final class FThemeData with Diagnosticable { badgeStyles.hashCode ^ buttonStyles.hashCode ^ cardStyle.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 new file mode 100644 index 000000000..54a883209 --- /dev/null +++ b/forui/lib/src/widgets/checkbox.dart @@ -0,0 +1,338 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/semantics.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +import 'package:forui/forui.dart'; + +/// A check box 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. +/// +/// See: +/// * https://forui.dev/docs/check-box for working examples. +/// * [FCheckBoxStyle] for customizing a check box'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. + final String? semanticLabel; + + /// Called when the user initiates a change to the FCheckBox's value: when they have checked or unchecked this box. + final ValueChanged? onChange; + + /// Whether this check box should focus itself if nothing else is already focused. Defaults to false. + final bool autofocus; + + /// Defines the [FocusNode] for this check box. + final FocusNode? focusNode; + + /// Handler called when the focus changes. + /// + /// Called with true if this widget's node gains focus, and false if it loses focus. + final ValueChanged? onFocusChange; + + /// 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 form field to, or null otherwise. + 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. + /// 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. + /// + /// Defaults to [AutovalidateMode.disabled]. + /// + /// If [AutovalidateMode.onUserInteraction], this FormField 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. + /// + /// Setting the restoration ID to a non-null value results in whether or not the form field 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 [FCheckBox]. + const FCheckBox({ + this.semanticLabel, + this.onChange, + this.autofocus = false, + this.focusNode, + this.onFocusChange, + this.onSave, + this.validator, + this.initialValue = false, + this.enabled = true, + this.autovalidateMode, + this.restorationId, + super.key, + }); + + @override + Widget build(BuildContext context) { + final style = context.theme.checkBoxStyle; + final stateStyle = enabled ? style.enabledStyle : style.disabledStyle; + + return FocusableActionDetector( + autofocus: autofocus, + focusNode: focusNode, + onFocusChange: onFocusChange, + child: MouseRegion( + cursor: enabled ? SystemMouseCursors.click : MouseCursor.defer, + child: FormField( + onSaved: onSave, + validator: validator, + initialValue: initialValue, + enabled: enabled, + autovalidateMode: autovalidateMode, + restorationId: restorationId, + builder: (state) { + final value = state.value ?? initialValue; + return Semantics( + label: semanticLabel, + enabled: enabled, + checked: value, + child: GestureDetector( + onTap: enabled ? () { + state.didChange(!value); + onChange?.call(!value); + } : null, + child: AnimatedSwitcher( + duration: style.animationDuration, + switchInCurve: style.curve, + child: SizedBox.square( + key: ValueKey(value), + dimension: 20, + child: DecoratedBox( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4), + border: Border.all( + color: stateStyle.borderColor, + width: 0.6, + ), + color: value ? stateStyle.checkedBackgroundColor : stateStyle.uncheckedBackgroundColor, + ), + child: value ? + FAssets.icons.check( + height: 15, + width: 15, + colorFilter: ColorFilter.mode( + stateStyle.iconColor, + BlendMode.srcIn, + ), + ) : const SizedBox(), + ), + ), + ), + ), + ); + }, + ), + ), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(StringProperty('semanticLabel', semanticLabel)) + ..add(ObjectFlagProperty.has('onChange', onChange)) + ..add(DiagnosticsProperty('autofocus', autofocus)) + ..add(DiagnosticsProperty('focusNode', focusNode)) + ..add(ObjectFlagProperty.has('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)); + } +} + +/// A [FCheckBox]'s style. +final class FCheckBoxStyle with Diagnosticable { + /// The duration of the animation when the check box's switches between checked and unchecked. + /// + /// Defaults to `const Duration(milliseconds: 100)`. + final Duration animationDuration; + /// The curve of the animation when the check box's switches between checked and unchecked. + /// + /// Defaults to [Curves.linear]. + final Curve curve; + + /// The check box's style when it's enabled. + final FCheckBoxStateStyle enabledStyle; + + /// The check box's style when it's disabled. + final FCheckBoxStateStyle disabledStyle; + + /// Creates a [FCheckBoxStyle]. + FCheckBoxStyle({ + required this.enabledStyle, + required this.disabledStyle, + this.animationDuration = const Duration(milliseconds: 100), + this.curve = Curves.linear, + }); + + /// Creates a [FCheckBoxStyle] that inherits its properties from the given [FColorScheme]. + FCheckBoxStyle.inherit({required FColorScheme colorScheme}): + animationDuration = const Duration(milliseconds: 100), + curve = Curves.linear, + enabledStyle = FCheckBoxStateStyle( + borderColor: colorScheme.foreground, + iconColor: colorScheme.background, + checkedBackgroundColor: colorScheme.foreground, + uncheckedBackgroundColor: colorScheme.background, + ), + disabledStyle = FCheckBoxStateStyle( + borderColor: colorScheme.foreground.withOpacity(0.5), + iconColor: colorScheme.background.withOpacity(0.5), + checkedBackgroundColor: colorScheme.foreground.withOpacity(0.5), + uncheckedBackgroundColor: colorScheme.background.withOpacity(0.5), + ); + + /// Returns a copy of this [FCheckBoxStyle] with the given properties replaced. + /// + /// ```dart + /// final style = FCheckBoxStyle( + /// animationDuration: const Duration(minutes: 1), + /// curve: Curves.linear, + /// // Other arguments omitted for brevity. + /// ); + /// + /// final copy = style.copyWith( + /// curve: Curves.bounceIn, + /// ); + /// + /// print(style.animationDuration); // const Duration(minutes: 1) + /// print(copy.curve); // Curves.bounceIn + /// ``` + FCheckBoxStyle copyWith({Duration? animationDuration, Curve? curve, FCheckBoxStateStyle? enabledStyle, FCheckBoxStateStyle? disabledStyle,}) => FCheckBoxStyle( + animationDuration: animationDuration ?? this.animationDuration, + curve: curve ?? this.curve, + enabledStyle: enabledStyle ?? this.enabledStyle, + disabledStyle: disabledStyle ?? this.disabledStyle, + ); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('animationDuration', animationDuration)) + ..add(DiagnosticsProperty('curve', curve)) + ..add(DiagnosticsProperty('enabledStyle', enabledStyle)) + ..add(DiagnosticsProperty('disabledStyle', disabledStyle)); + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is FCheckBoxStyle && + runtimeType == other.runtimeType && + animationDuration == other.animationDuration && + curve == other.curve && + enabledStyle == other.enabledStyle && + disabledStyle == other.disabledStyle; + + @override + int get hashCode => animationDuration.hashCode ^ curve.hashCode ^ enabledStyle.hashCode ^ disabledStyle.hashCode; +} + +/// A check box state's style. +final class FCheckBoxStateStyle with Diagnosticable { + /// The check box's border color. + final Color borderColor; + + /// The checked check box's icon's color. + final Color iconColor; + + /// The checked check box's background color. + final Color checkedBackgroundColor; + + /// The unchecked check box's background color. + final Color uncheckedBackgroundColor; + + /// Creates a [FCheckBoxStateStyle]. + const FCheckBoxStateStyle({ + required this.borderColor, + required this.iconColor, + required this.checkedBackgroundColor, + required this.uncheckedBackgroundColor, + }); + + /// Returns a copy of this [FCheckBoxStateStyle] with the given properties replaced. + /// + /// ```dart + /// final style = FCheckBoxStateStyle( + /// iconColor: ..., + /// checkedBackgroundColor: ..., + /// // Other arguments omitted for brevity. + /// ); + /// + /// final copy = style.copyWith( + /// checkedBackgroundColor: ..., + /// ); + /// + /// print(style.iconColor == copy.iconColor); // true + /// print(style.checkedBackgroundColor == copy.checkedBackgroundColor); // false + /// ``` + FCheckBoxStateStyle copyWith({ + Color? borderColor, + Color? iconColor, + Color? checkedBackgroundColor, + Color? uncheckedBackgroundColor, + }) => FCheckBoxStateStyle( + borderColor: borderColor ?? this.borderColor, + iconColor: iconColor ?? this.iconColor, + checkedBackgroundColor: checkedBackgroundColor ?? this.checkedBackgroundColor, + uncheckedBackgroundColor: uncheckedBackgroundColor ?? this.uncheckedBackgroundColor, + ); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(ColorProperty('borderColor', borderColor)) + ..add(ColorProperty('checkedIconColor', iconColor)) + ..add(ColorProperty('checkedBackgroundColor', checkedBackgroundColor)) + ..add(ColorProperty('uncheckedBackgroundColor', uncheckedBackgroundColor)); + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is FCheckBoxStateStyle && + runtimeType == other.runtimeType && + borderColor == other.borderColor && + iconColor == other.iconColor && + checkedBackgroundColor == other.checkedBackgroundColor && + uncheckedBackgroundColor == other.uncheckedBackgroundColor; + + @override + int get hashCode => + borderColor.hashCode ^ + iconColor.hashCode ^ + checkedBackgroundColor.hashCode ^ + uncheckedBackgroundColor.hashCode; +} diff --git a/forui/lib/src/widgets/text_field/text_field.dart b/forui/lib/src/widgets/text_field/text_field.dart index 31c1c04b1..927ac7f82 100644 --- a/forui/lib/src/widgets/text_field/text_field.dart +++ b/forui/lib/src/widgets/text_field/text_field.dart @@ -61,7 +61,7 @@ final class FTextField extends StatelessWidget { /// Controls the text being edited. If null, this widget will create its own [TextEditingController]. final TextEditingController? controller; - /// Defines the keyboard focus for this + /// Defines the keyboard focus for this [FTextField]. /// /// See [TextField.focusNode] for more information. final FocusNode? focusNode; diff --git a/forui/lib/widgets.dart b/forui/lib/widgets.dart index 2334cd26d..25e657a06 100644 --- a/forui/lib/widgets.dart +++ b/forui/lib/widgets.dart @@ -4,6 +4,7 @@ library forui.widgets; export 'src/widgets/badge/badge.dart' hide Variant; export 'src/widgets/button/button.dart' hide Variant; export 'src/widgets/card/card.dart'; +export 'src/widgets/checkbox.dart'; export 'src/widgets/dialog/dialog.dart'; export 'src/widgets/header/header.dart'; export 'src/widgets/progress.dart'; diff --git a/forui/test/golden/check-box/zinc-dark-disabled-value.png b/forui/test/golden/check-box/zinc-dark-disabled-value.png new file mode 100644 index 0000000000000000000000000000000000000000..964d8fee64199118b26b4bddcf579de0bfccf7f9 GIT binary patch literal 22742 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 LcX{zW!@mAE>wN~) literal 0 HcmV?d00001 diff --git a/forui/test/golden/check-box/zinc-dark-enabled-no-value.png b/forui/test/golden/check-box/zinc-dark-enabled-no-value.png new file mode 100644 index 0000000000000000000000000000000000000000..5e552fb69c7cfbf285b7a99b640996c7dcdf125c GIT binary patch literal 22202 zcmeHPYfw{X8b06+WP|lGutjidv1K}zi)?{K8bO8*S|Cts0J((@v>+_t5@IkQ#>GMz zs+3}Nj0lWal!TkcfS5pFd!e>UqPb840hB6+Y@$FyXn?ReC&|XyU;Cr8?#{mF5AQj7 zzjMCtInVpN-+9l+sfZzj<`;}u(0;;vb{LE57O7SYYqET$EEC47wLxW-53y~q`?KH0 zTTGb0k8mDEL?yf0&OvK0VEfag_#PFLt$!RrUJ~kU?OU!0!*Rd$-+zp zc;JHPP%{}82t)%!1A>4QfE0ifn3Vvc!3@OzRc<)_eddy7EdVxt&_vKg&_vKgBLW}= zAO#==FG#_4a#wrF5XE(1+#_9Gn?`tkYck#UUR0FqI_JvXZgx$WombBXVGnR!Z;c%( z_;|~vYt{Z|^HV~6C^c`%?S8Bz3f-ng&xVyz2#g<^qPixJ4*EX0L_SKWKI*=H?bw3q zvEz8}Y~ko)ac+-+?vZD?u${g24MwP~^&RIIh;A1Dj*L z6O+!jFQi|h4i0k~_Y{#)J9i-aa(T*Jq?^p=$INlU5yn)UAvTVC6`MICUHa} z=dfs*@{?zm_p?TrTH)^o@%1$vp;>d0R19ls(7x4&b3nDe0XXv6lo#l6rYd zJpJ&!@z$A{nFQ{ebqQAdicH?pXv{K1Z=Jhsi+d4L+*?|ruArz{Xc_rJYLX(adqP3kq(Y^Ij>4 ziWaw2{F!--=PS^u5=0`82wCA;H}F{W?6Z-ONwt%S$Vm!KM|$%hYRgdubk}| z^%~qGy!8U&H940Wz)PQB3g}DF&p5cGpo=|2674VsKiwA{9ew)D8EMcno=9`{5c#Pv z{&ZDU9FALK}+Q29Q`fI}*raOz;$aa$_YKH8? za7Rt#l}*-HJg30@KaGsAy1BWT5zOZ+US;PRmJE#A+CS6K^~i{)g(hi}<;oVelbCmG zj#1~EO~7l#2^|x6cfaF5rrCmeCWM;8DBQry$RiRx6FXZTzQLaQGQz8w$#fGkC#3Fa+o~x-6~_eXD>W1JCAw^olJtc`-bwX046g_CG+#6s_)?1 z17~P7T9*7a$LKxx)hb*&8X*myCdw52BI$ZlsmQ2jkp=j!T&}9KX{z?fR{zly2WPJq z59*%8MT7r+jVpQuOLqryM>Um<3m2M|ZQRb-wxnTA?dB&pe)3{vw{7PpNoP*g(D$dQM5=DIDZ{Nxt?uUhWina2Fj*y4T&+(DkRK!A zcg@m7Z0yPx+C*L?U5dyZ+p8CNABwqnqA*Q6KQI0E+c4E=H>)#mJS7^>X`ENfM>ISg z#qeuHR%Yfkv{Mfvg5$2%=D+V2n14ko*NbG=sV$0Q=$USsauNOKza7I<24p*x4y@R1 zb0;SHPRhETttc7dN8eQ{@BVSI>eoeiP0(~x>qwSH)rf0F)uBOU0=+nO=U`x?SI^Tl zZL@>(&}FuOxn_A;GBPrvX-SJD5TqB&9VJ`WIZD;%b>cQ>QtOnCFVSG>FoE!b0_gXd zavRz&ME3p*zkoJ?YC?j5)Csc$m_NZ((U=_}9Y8t&5A;8pq=Vl&9rW@4 zWxc8m(znA}ql>it=f7{kVIu+2?WJK-LfK+0G&x10-vz*W0=EQ%;U(S@xDCKT;2;E` znFEkJEkL}qBngTPiVTVjifj=ghz5uThz5uTBLW}=AO-(LQozX`z&^EDy3{(=!TpnM z>L%+t(l@Q2TZF@A)&eFbAb=1+2n6{}qM-?KFHGQs=k$A{knVqv5Y`r&`qzH|^P`P# literal 0 HcmV?d00001 diff --git a/forui/test/golden/check-box/zinc-dark-enabled-value.png b/forui/test/golden/check-box/zinc-dark-enabled-value.png new file mode 100644 index 0000000000000000000000000000000000000000..46e4f551035ff0db3f95f06c89af26fbee83346d GIT binary patch literal 22348 zcmeHPX;c$g7A{m2v@t427$7Yu+MF{gimcO$tcna0Xf==qS!@`gS!I{V60~hZr0sFk zD8WG6Z5V-&ARtNr;|j{&n9vBwu^ABv;F7S0W%BA(q>uAw`keVQ?W;d|^| z?^fNqCmHS(Cyk}LOEC=7aNgs%55v^`F>HyN+G0h|Ez#5>#g9tNJ|}yuxQRTVI9U{9 z?|eW_aU`h)p29E#%-PZIz|owcXLcHlt(Z_~qFQ=#`E;niu9&p;_I`JjYVl0fLd87% zU<61d$~MNhv&~;cdFHryld{REW2h?ID|GnECbn*&ma=UdC|saypZbKRY+`>`S*C0o zAmK_?AhjU0D6xQ?2yqL61w^?hSP)P^F%&&o5Kur*TD*)<#w-p*@_v)7F7ETxX}E?=h0-?ToHPS?jZ8=h^?otuhpD+LpSZ>N>_Ry0^x zgHk?5eC3fqhvDgG%)zUzG1=@@iKAIIqMQ1&Kl!q1S z;+e%1@lcqElu{$88Lta)bptugypwPvIp@>T(&)00;n4vX<1qS@t?{yx8!m-!EM?+3y z47IEx))hVVwSEZw-nqZ@mhES;!H}(s8vd=SzuvZO;l&oAaLE7<)I9m`glb7LAX^>D zyBXQ@#rF6v-zB6qVf5u--o^)mP#MCnSUEXGjVxZ_jC|aaDl%;z;wH=4T=P(|S=A?s zD;YOq@H$Jz>hS338;@!$sURYAnXmo~G*-hbk zkH1}f5tx|&Gu$KX3wrhQ93~jlAdxKj`06e|d<##ntpP^xzpjq!gSPU4Cy;Gs2em56 z;DOWN({QaGntniX%X)Zc?go5v-q%piUd~BChr(zBXzMsAYm+uHyo(ryQ1G|=K*a~o zC+wwAnpXO8d6XdL1VA%mLwV%@xFc59)B2;6WU!FOy?*_AK>_{UhLXA!*}Vx>O+_k+&XuOQnitXXK$_VbVEk7U?Z+gZc|_ zUy0kJ|5azw%*oGJj8{ERk~StLC-B-?hBdlH5efGAx@`j>G#Wa?E4n@OEW)h%CS@}3 z@~B=K`H-uttBB*;t1!W5pT)Pod2>Y84c5S4p`6nZ#4C)b*ni@L}!J#8vY*Xd>b9 zFHfntz!kCxgS$&J_)zy{S%fU6Bkk9XK>9Pn@K>!aE2nuAwl{Nda1ad)u?_F(7FHh{ zZ_@FL`&>ZS&>PxNOVr=rPiFEtk|~MJ_E#?pTU%SNT~Y^vS3*o=Mg#}{v$8v*cQ>up z)XIvcsVVS*5bMyyotVG=+w^p|qw12>>SL23fq{V;I9hEf5bo!6bae|TK?z*H)UhZV zeeyxSD^12sh(Zl`3zv}C*fRFfubNGm{8@#Js|us*dEqo;Z)RLqqf({mp>F>RN|NiK&naz-8u)c??^JOjHdL->R;t-C z{eYLv<_E4B+}ZizEcy%4RObsr*JfI5>ZJS-1b07+n3?=iPO`8*)EYiB)Uf*sp5^xy8)ctsOGJ0hpH~RF?DYfLHfN>zOH?vNNjf$s;c-rD;wqHt;*! z`kd&&MCS8u8Q>)B*-LG=xk?YN7nSLk-gv^%TE-0@Eitv}lAW(ht00LQd#dmF9-YbJ)@0 zfIxu40b&9a4p2ByXyEsRg9(x#9?!FEt?QvL7i5Aw0mFIzCH~T)`7F#IwOeBUT9L!m zdJg^<0K-0p9iv?WHvz}ThIM3lXm@1!_kTx%2oFL6Q32r^2oMMmC@?DH1o8&t4aggi zHz+iKr~pv`q5?z({}U?6iyy|TSN*@gGfIxvc2d;pt)DM#-Mip@^(*Qo5QlUE6@dVO e0D)n@(;HMw+)d5zuFA&iw4HZR9E}No~pPZq=*~SX^t7ww}Ua zXUYijfB>?DJt$RZF@S~y*@6Os1Or79NP&=fTVSR=bI!~;Gv~}qZ~n=BFZa9me!uVc zefN9cyC=8*;CNJHh3*Onf;5gFvpWSr%e^5;MOAefa;Ka>y%hOc6nyHaEyQZp8%8dc z2HPG#t%`h@s^@M&&_?LEoz3a6ly{vr8g;u?)fKX4hu5}f)W1*M+M&95V@qPwM9${iA<79isyxBwDSkU|qw08bX+fs3F5cn$@R z=L8i%VFA=z2rB&V78b%fO3$Jdv}l_-LGVitz1_7ifFsQZQRrV6C4LX2*ULN zApjvD;0?eVAP9s45DGvjAR+d2jRnB+!14$Jfc69p zKyHWw0SK``h@#M)egh}bEO_us@ztQ9XHQJLwX2q{?K*uy@0jx~lcut-&N&^X z1iO?uv`umzY^C^ZZF3eG9j3chGuHmzLY00(yYb@kj~vyFESB{@W$iQzZcemczcRqo z&v!QQ19DVWL3==&S<=rb;*)`L17d1Ob@{^K58K5HRot(jh4(z07S7)NGu`)gO0dy8 z$7U1Fq}@|#tl=1y5svT*r#aoyt^QHQuuFo@NC<<+CGkz&0`ns^t!bK(<7%ZrpFSLR zK}Act8$7*SUFqTIF+)f!xud;Bl*5r%O+PAb5xnSA7??>dPPCn8cfEQTmt?3;5Ad1n zYe{|XC?6amd&Nb`8B&HD+oD_@5stRd#*Q?s`gtl_kzYF@>o+IsII~Hf?0{a+4Ho{e z#s-q$ST;{m-Q?;{dyqIW#2D#n}}o;@#qf*Hl-cOs( zk<-}1o?1_|U7eo0y2QLwKes1hw7_btBKy)fg~D%aJl0dnpo)dTS7PtR@_D`Tq42?+ z?4&eofTohMbNB$Wvik|5s+0TwNTFDb)v!&nvvfU6KE3DURNC(}3>uJE)>%r3Yi6CENsIPl}U0(0-*zdzl+CEYK4CEDGT=V27+4kumA z&h`YvhBVNlKJJyQLA$x0k*CF@>nnug*Co(PtOSxTX`z03A!FrLFf3$_h;`L(CMaq~ z!?-C{q1M@$mCxX=AgIx(@r?8tOB2P$Q7L>=CnssQrWbtu`t=(LSicZY8&zcJy2_9b zYda%$*TQhpTd8Q&KXh+7s%*5>7Au_BRhkFwt`$WM6hFV)^ct0lTyd0|&Tohex5 z#g(c^CyUN%W|LCGEuAKGpS0YP_}=x0!2Rh;c!BjF{)c zT2%g3IL`XQ9k&XQOX&RPm^()cw7sxpufZqJH^F*m9LKeFwP#`sT1)qcmZ4*FI`XOSPQ|DK8t zvX{W=i<(FYjVqloynNt*Fkc=q^<=dGGlZ6xeo~qzzg-W7v944LH^UkEqw6||3e16G zHPR;@5!W{3z-iz}<$cjn5mmEGp4oJS*59u4$!#2Tf}goQ=0@Ac*P_!aU67K$>9H1W z3JV;2XAdoCjxRkf}s+nF$UP*CR~-^_#%Qm3jsGsIz65;%d0BFQ!&3A5jo1Gr?EJN=B5^ zul&)0CZEe7CTle!e#=eV)_u*q-LOq<-e4JriP1ufgXL;P{C9p7N@{wdw9^Jf!1Y4O zFiJsaRqC|p)Q#28HI6+3C}Z~aLN9jKFV>4)zk-u@Yer(em&UESUN!nh(gWCPK> zYghook?Aw;^$fK4e2{v7`()I^(axIO>Ehr^l15}Z$*W8^v^*745hbo36LyBQd;B7d zc2POU@#5GWrY=fWcU-dP|2o{*#UcQ6@kT&8`1Z5UBva9J{igv>mW*X2^78ZHk~8hf)x0TvQoyV*nCt1i5ROG&(}|+?g!uR*1Jr;AXY`nZiPOzq z)}F{7e`H^3Qc7h-fUvs4gcQgUes9N{*ue283g2i7B3MY@8H6&y-GG8Be%05KG!|StyRBvfCNw`ER7YK8%lb+~2=Tn;Fd| z%Xoq9`CV*M2^Or%2roFpQ_&QRkeN9`OJ=!a>VB7@=9HYD9~Gjxhxjf(D>(q>x|OwU z2@%7+GD$Y0#dnHit%j%(9gmNIVgy|~k~E(wL9Na>>Cqpee@#&I_J1Os`WLe=(EZ<( z#sVM#kQ)IB00{sIAV2~@0zd)?kN}VXkN^TC03`TFBzSe@<=>woUUXtHRx7yZz6Pl^ z=~$xw3xGZ;*KNW|YiJW9x}Z&P8$|*608DTk03mQ303iq*03iS&KzJlL0QO5I5MaN= zkpSTlghvn_l~DnB1Mmjm4Zs@^1VAVNq2T{I6r8RK*^ZicS7UGZ%BnlY3xAF2t+jB- s*96?g`~YA=gabeb90)*&|7t?4us59H6t0V?L|1wIu%jKz*8B6n0>wDvi~s-t literal 0 HcmV?d00001 diff --git a/forui/test/golden/check-box/zinc-light-enabled-no-value.png b/forui/test/golden/check-box/zinc-light-enabled-no-value.png new file mode 100644 index 0000000000000000000000000000000000000000..35233f59a46ca048c2d7d9878e33d193a3588d23 GIT binary patch literal 22196 zcmeI4dsGv57RLvn3T0V1?J1rj2x`yq?5a?u=u!cZsz_<5+cK<(0ZsuQi2|AjAv}^k zw$gURwXULK0i_!tArV#(36G6XL9p@=lSm*5TNDW4DTD~&u``*(wEyindrsXw-uY*K znfzuZx%YFwzu)i9O}^R}7VPk<%c}^2IE3uo^$~*D#UjWGTifN>kz3L^8*FDq`zSaF z5w*E$uopJ8ppbA|Y)iL|&q5FnBxKjlaMqO(#ZCvw+fI@)(Y)r3c8A8Nmww-EyUe5g z(xq3hlZ>0>uwmTXMz~RLmOX#5*4o+J4vd#9Gqv z+`HW8w{n7ugINd*04)$irdR-N0m(I?0D}dLq2>`1rWP>cGO+*?QJ6xTP=J*MEVxW4 zz&aF`=Oz>&u>koN6AJ&oi3L`7WgMPCKr|o-NC8LzNP$TSAR0`Dc-h8=3;XfM^F%EGXreh9UN#EA^Wb^R0)V{< z1DG2Uh5#TeK$NF&u4c*^uFdNAS00{kbKbK(x0!TUyykr3Vt29R_#l1nzHK%e>?t&# zbu|~gulcO`!u8vu5z9-;5+ay|r`Nh|ym_O9EToSWXNC1XYUnRtS5d9bX4Aw@pMTns zq{}(ovWZxPqOJaYoCGq#4bRSwra>OrRU?90> z+{k-0*Q{8`X&#o`Gf?UD3PrPm)c)>HK^3~Nu;4RZJ4H=?^0jzgK@}8LNvDk|WO47& z_7B6tw)*1_pSfexTKJjeme#J7ZN#)=27f=bTEXF79tWBkw+(Pu9xS;r1&%OTY0HmmLr; zwded@G0Hss7r!XO%%~u3Y&OBok5$Gl(#w?p%qa7${^@JpAf6TN_%mUlD-}Bye#%o+ zOkUvg#gk1*avrHlT5+_?C7N+E+kHp$s;$RLH$~kHN2S6PW#oo>T3n+5I~^I?y3F_m z!&)ca;}nmpCxpXVtzd=wJPGSvp$T!nD$%og z{a6rJ=vBLKgD3eQiuT;}kGPlPMP+rCZ1$@ai0aw9QS^A)p(Nd=i|UEB_#MS}G$v=H z_38_I_hM!56*c;iQ$Lkx{%HcDcT^LtU@)4stl0x~aD9q;~w>f>2va@lz1tA^bS^uZZP2=UbNA zQ(J;6ybA)|J$?<#6s!|Q2%4IjF6V82g6;Uy9ts<;LPp3zMr{fVo;#$I3a-~52+npr z%5MFeFMImP>FjLTNcWB0JR>VPW>)M2bQ(UNJzP?>DtZfJW~3Vnf&AKuhA(sQ3wCTG zLY)5C`*Uj)_1UuJ!Nj*EH&VvEF-+rQQyW9^UPI0VChwkXkwbwm zv5Go1unA{6w(MU%cxSr3iDX~e?Rjx}Y--)p)=w3;CNJ;?ubjlCqVbfYT+*@cyHwTs z%XzqP1?K!=bhf3Xg%^yU-{H2%=nEv%S`u_KJxTJL$InQgKDl=}kN*D1qw>NCQ7w;0 z%8lTxPUQtKWs#&0@vmDD$}(0(bF=UJ>3hWssu(O1`KW*@7bzXQ=K7dpt|A|5eI$xj zsZ*{$!)v^`=Lm)A`+lRLm7#0go_Vmpzn>vR|0EYPv{XEpBG(_sb~0g9%!Y{4(rqeM zVPc)OO*|hObBt{qF33$@wzyDc`PF5lDd%;lG(aZObfr->4-$OdnVxlVbuFEpYENRT z4D87}ITRM_7XC@r=civ&rBCfAF!Wxd4jbyjv%7Hj5S#e? z&))epg1~rN5Fe0b1Rwwi00NkxApikD01&`Z4VxOmoB-wo009gKFOd@T?HEy%eWH@Y09w0B+CX;uVO9yK2So-qa23D&nfUFuELEf*EPGx# rDuKfUD_|4C4gdsU2LyoluYs`IcFk3up(mD zZLFw4x)t2;NKhUE8eRwR#bd>Q!A&@dMFWHY5+y|9-nnxl+dccoo}SY`v~&Lmb2BsF z%=i0#-#2r=JK>wJsJl?fhKBn1H`heddib9?jBUQ&SXsw% z8GfV3@b=qoh+l^cBadO2HRiWz!}iqkBYhi88a_2`5R|==z1L~dJaKlV*igs1^X%EV zcqig&h*2xFWsJScLh$CsMt6y}>=oIdqb(nsAEGT{-_9}CmaRXd&(W4Q={stR?3?U2 zLzyDs2o{I{VheI2(ic!{K_Qo<0$ME48me6((bfX(xJWLbjVRhelT<)Y7U+SCqyl;l zMUUqs6;NUUel$e^(|XnGhA!j`)j&87%W&nD46MPEZxBTOI;h!CXf zBSIiTV8|PgH((eF1t=7tP(VfkaIoD4Pig|6G&FPt%&A#`~(3?&Bt(Y^L;{QLI7nlSr0OBvsoV?pE z>P(ptXg*&b?%RK)?xdAxc%`6gvSh(!g!!hb2aN!T~maI{wO!hI-T{aQNtx0^-I_19BoCdzA{T)C6S1#hRl{8h%@psh{r zk=F*yhoXm}%V@#DH>%RpB`G3`vOBC!+pvbvwqf@lLP9Rr)$e7@MD0)N4&sO^-4EQ? ztxxBzy+G{_0-|CUniJ#=z zwCgephe27J6+b5bRdBZ}6q3Hd5HB?RAb<6wXsADHftyFf7fR*JUWNfJo&`=(Vor~A z2z0Y2rtdiO)l)p)P`gT%$NK3zavU>qoS&Y)R3x&Rc&e6BD~bn^qUDU4X8;+Fx0U(N z_z}Ljt2`ot&oiV4l}!aTWOtoU2%`!1o4$iJYH2&e|YcL zS4&S?rd2JbNAl80y}$q>ie|z_I6S80?&I5D?x*vWssG_)ar+&9%-$C z7BnU6@60DRzt!gu`biB51BUFZm5lm^3x||G@zK$RM~Uf`_(J7-Ovc{>!ioc+-nG_3 zFuRLJusSsG5P0S76$G83B5w*Dg=O0r5t3t_VCR5EgeqNMK6b!su^t^bu~J(?7QGZ| z+O?9bHiOl7e)u`W4igqQR7EHFgHNBvCnp!dp@J(5WI!9NqQ5ZU+)#@-?Q&ydBhC>e zi?X)%YGF~)8M$j_W@g-<9;<>{ciP&z$KjWFJ>h^$n&%P}<%~$v6e?>WkJoo4%3m&a z)fBXGyb0ABLO&#q)Y5OQO6W^&iqO^7rL0-Abysy_*uAs^brM`AgTbJzTW14-ae=^a zMj8#Qcy7|vfs8h_S{<*DdhE-ftX>^*`t%}P1s|W3`*-hdnUsQ=3zkFl9L0~Cvx<9{ zm8w*#McidemtH=swhMG`8cM0FjOm>Ec%V2usRCDMp#5jPvc+O??Rcxy&$dLP(R3dd zyfJ4O#5aIs(jJa&lNk+w)n!M{Qnby+5!xuh7OE-!a3KdGy9x$7feqDO+ieHzw&U)| z$ex@NBden_Di0{QwVG+Ul?5&58-9u4>nTVvL0oi9OnhXdujSh0XFqo0SMRfD)H8fAN~{UwRWWXV zUgEVsPG$IqK+|mt3JNlD(#6}byX_$iqV|rCp0Tmbmg}Zic%YmfiWd#%)IzckC;zv4 zlF5u<<-N4FJT4f>%lI1METD}2k0oQw69mykpf=VB&MA9;Po_ygUmEEnO)E|HZ~5(1veKhGpqNMzP_&9(e1k9{@lZdDK4&}$@!ovvBrNbyXHEAV5Qbf#7Rf&L?~x@Bb*P071aqxPUX;(I z&+Ixp+~X|Tl_V77E8JZ3uFdt&}Dd0(AYp Lpl&MjrvLfhUF`5# literal 0 HcmV?d00001 diff --git a/forui/test/src/widgets/checkbox_golden_test.dart b/forui/test/src/widgets/checkbox_golden_test.dart new file mode 100644 index 000000000..ea7ffa5c5 --- /dev/null +++ b/forui/test/src/widgets/checkbox_golden_test.dart @@ -0,0 +1,38 @@ +@Tags(['golden']) +library; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:forui/forui.dart'; + +import '../test_scaffold.dart'; + +void main() { + group('FCheckBox', () { + for (final (name, theme, background) in TestScaffold.themes) { + for (final (enabled, initialValue) in [ + (true, true), + (true, false), + (false, true), + (true, true), + ]) { + testWidgets('$name with ${enabled ? 'enabled' : 'disabled'} & ${initialValue ? 'value' : 'no-value'}', (tester) async { + await tester.pumpWidget( + TestScaffold( + data: theme, + background: background, + child: FCheckBox( + enabled: enabled, + initialValue: initialValue, + ), + ), + ); + + await expectLater( + find.byType(TestScaffold), + matchesGoldenFile('check-box/$name-${enabled ? 'enabled' : 'disabled'}-${initialValue ? 'value' : 'no-value'}.png'), + ); + }); + } + } + }); +} diff --git a/samples/lib/main.dart b/samples/lib/main.dart index 5b4651107..38855872c 100644 --- a/samples/lib/main.dart +++ b/samples/lib/main.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart' hide DialogRoute; import 'package:auto_route/auto_route.dart'; import 'package:flutter_web_plugins/flutter_web_plugins.dart'; -import 'package:forui/forui.dart'; import 'package:forui_samples/main.gr.dart'; import 'package:forui_samples/sample_scaffold.dart'; @@ -29,91 +28,9 @@ class ForuiSamples extends StatelessWidget { @RoutePage() class EmptyPage extends SampleScaffold { @override - Widget child(BuildContext context) { - final notifier = ValueNotifier(true); - return Row( - children: [ - ValueListenableBuilder( - valueListenable: notifier, - builder: (context, value, __) => FCheckBox( - value: value, - // onChanged: (value) => notifier.value = value, - ), - ), - SizedBox(width: 10), - Text('I accept the terms and conditions'), - ], - ); - } + Widget child(BuildContext context) => const Placeholder(); } - -class FCheckBox extends StatefulWidget { - final String? semanticLabel; - final bool value; - final bool autofocus; - final FocusNode? focusNode; - final ValueChanged? onFocusChange; - - const FCheckBox({ - required this.value, - this.semanticLabel, - this.autofocus = false, - this.focusNode, - this.onFocusChange, - super.key, - }); - - @override - State createState() => _FCheckBoxState(); -} - -class _FCheckBoxState extends State { - @override - Widget build(BuildContext context) { - final FThemeData(:style, :colorScheme) = context.theme; - - return Semantics( - label: widget.semanticLabel, - checked: widget.value, - child: SizedBox.square( - dimension: 18, - child: FocusableActionDetector( - autofocus: widget.autofocus, - focusNode: widget.focusNode, - onFocusChange: widget.onFocusChange, - child: MouseRegion( - cursor: SystemMouseCursors.click, - child: DecoratedBox( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), - border: Border.all( - color: colorScheme.foreground, - width: 0.6, - ), - color: widget.value ? colorScheme.foreground : colorScheme.background, - ), - child: AnimatedSwitcher( - duration: const Duration(milliseconds: 100), - child: widget.value ? - FAssets.icons.check( - height: 14, - width: 14, - colorFilter: ColorFilter.mode( - colorScheme.background, - BlendMode.srcIn, - ), - ) : null, - ), - ), - ), - ), - ), - ); - } -} - - @AutoRouterConfig() class _AppRouter extends $_AppRouter { @override @@ -138,6 +55,10 @@ class _AppRouter extends $_AppRouter { path: '/card/default', page: CardRoute.page, ), + AutoRoute( + path: '/check-box/default', + page: CheckBoxRoute.page, + ), AutoRoute( path: '/dialog/default', page: DialogRoute.page, diff --git a/samples/lib/widgets/check_box.dart b/samples/lib/widgets/check_box.dart new file mode 100644 index 000000000..7bd86c989 --- /dev/null +++ b/samples/lib/widgets/check_box.dart @@ -0,0 +1,27 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/widgets.dart'; +import 'package:forui/forui.dart'; +import 'package:forui_samples/sample_scaffold.dart'; + +@RoutePage() +class CheckBoxPage extends SampleScaffold { + final bool enabled; + + CheckBoxPage({ + @queryParam super.theme, + @queryParam this.enabled = false, + }); + + @override + Widget child(BuildContext context) => Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 30), + child: FCheckBox( + enabled: enabled, + ), + ), + ], + ); +} From 5b04a2db91735cf5018ed2e3f8807f4668681f7b Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Tue, 2 Jul 2024 19:04:06 +0800 Subject: [PATCH 3/7] Update changelog --- forui/CHANGELOG.md | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/forui/CHANGELOG.md b/forui/CHANGELOG.md index e24a950ce..773b4dcec 100644 --- a/forui/CHANGELOG.md +++ b/forui/CHANGELOG.md @@ -1,17 +1,24 @@ ## Next -### Changes -* Add `FHeader.nested` widget. -* Add `FProgress` widget. +### Additions +* Add `FCheckbox`. +* Add `FHeader.nested`. +* Add `FProgress`. + +### Enhancements * **Breaking** Move `FHeaderStyle` to `FHeaderStyles.rootStyle`. * **Breaking** Move `FHeaderActionStyle.padding` to `FRootHeaderStyle.actionSpacing`. -* **Breaking** Suffix style parameters with `Style`, i.e. `FRootHeaderStyle.action` has been renamed to `FRootHeaderStyle.actionStyle`. -* **Breaking** Raw fields have been removed, wrap strings with the Text() widget. Eg. `Button(label: 'Hello')` or `Button(rawLabel: 'Hello')` should be replaced with `Button(label: Text('Hello'))`. +* **Breaking** Suffix style parameters with `Style`, i.e. `FRootHeaderStyle.action` has been renamed to + `FRootHeaderStyle.actionStyle`. +* **Breaking** Raw fields have been removed, wrap strings with the Text() widget. E.g. `FButton(label: 'Hello')` or + `FButton(rawLabel: 'Hello')` should be replaced with `FButton(label: Text('Hello'))`. * Change `FTextField` to be usable in `Form`s. * Change `FTextFieldStyle`'s default vertical content padding from `5` to `15`. +* Split exports in `forui.dart` into sub-libraries. + +### Fixes * Fix missing `key` parameter in `FTextField` constructors. * **Breaking** `FButton.prefixIcon` and `FButton.suffixIcon` have been renamed to `FButton.prefix` and `FButton.suffix`. -* Split exports in `forui.dart` into sub-libraries. * Fix padding inconsistencies in `FCard` and `FDialog`. ## 0.1.0 From a2e8cd16c9dfb6b6ddd50c75ce837f85ad6019b2 Mon Sep 17 00:00:00 2001 From: Pante Date: Tue, 2 Jul 2024 11:06:01 +0000 Subject: [PATCH 4/7] Commit from GitHub Actions (Forui Presubmit) --- forui/lib/src/widgets/checkbox.dart | 105 ++++++++++-------- .../src/widgets/checkbox_golden_test.dart | 9 +- 2 files changed, 63 insertions(+), 51 deletions(-) diff --git a/forui/lib/src/widgets/checkbox.dart b/forui/lib/src/widgets/checkbox.dart index 54a883209..b73498adb 100644 --- a/forui/lib/src/widgets/checkbox.dart +++ b/forui/lib/src/widgets/checkbox.dart @@ -2,6 +2,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/semantics.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; + import 'package:forui/forui.dart'; /// A check box control that allows the user to toggle between checked and not checked. @@ -113,10 +114,12 @@ class FCheckBox extends StatelessWidget { enabled: enabled, checked: value, child: GestureDetector( - onTap: enabled ? () { - state.didChange(!value); - onChange?.call(!value); - } : null, + onTap: enabled + ? () { + state.didChange(!value); + onChange?.call(!value); + } + : null, child: AnimatedSwitcher( duration: style.animationDuration, switchInCurve: style.curve, @@ -132,15 +135,16 @@ class FCheckBox extends StatelessWidget { ), color: value ? stateStyle.checkedBackgroundColor : stateStyle.uncheckedBackgroundColor, ), - child: value ? - FAssets.icons.check( - height: 15, - width: 15, - colorFilter: ColorFilter.mode( - stateStyle.iconColor, - BlendMode.srcIn, - ), - ) : const SizedBox(), + child: value + ? FAssets.icons.check( + height: 15, + width: 15, + colorFilter: ColorFilter.mode( + stateStyle.iconColor, + BlendMode.srcIn, + ), + ) + : const SizedBox(), ), ), ), @@ -176,6 +180,7 @@ final class FCheckBoxStyle with Diagnosticable { /// /// Defaults to `const Duration(milliseconds: 100)`. final Duration animationDuration; + /// The curve of the animation when the check box's switches between checked and unchecked. /// /// Defaults to [Curves.linear]. @@ -196,21 +201,21 @@ final class FCheckBoxStyle with Diagnosticable { }); /// Creates a [FCheckBoxStyle] that inherits its properties from the given [FColorScheme]. - FCheckBoxStyle.inherit({required FColorScheme colorScheme}): - animationDuration = const Duration(milliseconds: 100), - curve = Curves.linear, - enabledStyle = FCheckBoxStateStyle( - borderColor: colorScheme.foreground, - iconColor: colorScheme.background, - checkedBackgroundColor: colorScheme.foreground, - uncheckedBackgroundColor: colorScheme.background, - ), - disabledStyle = FCheckBoxStateStyle( - borderColor: colorScheme.foreground.withOpacity(0.5), - iconColor: colorScheme.background.withOpacity(0.5), - checkedBackgroundColor: colorScheme.foreground.withOpacity(0.5), - uncheckedBackgroundColor: colorScheme.background.withOpacity(0.5), - ); + FCheckBoxStyle.inherit({required FColorScheme colorScheme}) + : animationDuration = const Duration(milliseconds: 100), + curve = Curves.linear, + enabledStyle = FCheckBoxStateStyle( + borderColor: colorScheme.foreground, + iconColor: colorScheme.background, + checkedBackgroundColor: colorScheme.foreground, + uncheckedBackgroundColor: colorScheme.background, + ), + disabledStyle = FCheckBoxStateStyle( + borderColor: colorScheme.foreground.withOpacity(0.5), + iconColor: colorScheme.background.withOpacity(0.5), + checkedBackgroundColor: colorScheme.foreground.withOpacity(0.5), + uncheckedBackgroundColor: colorScheme.background.withOpacity(0.5), + ); /// Returns a copy of this [FCheckBoxStyle] with the given properties replaced. /// @@ -228,12 +233,18 @@ final class FCheckBoxStyle with Diagnosticable { /// print(style.animationDuration); // const Duration(minutes: 1) /// print(copy.curve); // Curves.bounceIn /// ``` - FCheckBoxStyle copyWith({Duration? animationDuration, Curve? curve, FCheckBoxStateStyle? enabledStyle, FCheckBoxStateStyle? disabledStyle,}) => FCheckBoxStyle( - animationDuration: animationDuration ?? this.animationDuration, - curve: curve ?? this.curve, - enabledStyle: enabledStyle ?? this.enabledStyle, - disabledStyle: disabledStyle ?? this.disabledStyle, - ); + FCheckBoxStyle copyWith({ + Duration? animationDuration, + Curve? curve, + FCheckBoxStateStyle? enabledStyle, + FCheckBoxStateStyle? disabledStyle, + }) => + FCheckBoxStyle( + animationDuration: animationDuration ?? this.animationDuration, + curve: curve ?? this.curve, + enabledStyle: enabledStyle ?? this.enabledStyle, + disabledStyle: disabledStyle ?? this.disabledStyle, + ); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { @@ -298,16 +309,17 @@ final class FCheckBoxStateStyle with Diagnosticable { /// print(style.checkedBackgroundColor == copy.checkedBackgroundColor); // false /// ``` FCheckBoxStateStyle copyWith({ - Color? borderColor, - Color? iconColor, - Color? checkedBackgroundColor, - Color? uncheckedBackgroundColor, - }) => FCheckBoxStateStyle( - borderColor: borderColor ?? this.borderColor, - iconColor: iconColor ?? this.iconColor, - checkedBackgroundColor: checkedBackgroundColor ?? this.checkedBackgroundColor, - uncheckedBackgroundColor: uncheckedBackgroundColor ?? this.uncheckedBackgroundColor, - ); + Color? borderColor, + Color? iconColor, + Color? checkedBackgroundColor, + Color? uncheckedBackgroundColor, + }) => + FCheckBoxStateStyle( + borderColor: borderColor ?? this.borderColor, + iconColor: iconColor ?? this.iconColor, + checkedBackgroundColor: checkedBackgroundColor ?? this.checkedBackgroundColor, + uncheckedBackgroundColor: uncheckedBackgroundColor ?? this.uncheckedBackgroundColor, + ); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { @@ -331,8 +343,5 @@ final class FCheckBoxStateStyle with Diagnosticable { @override int get hashCode => - borderColor.hashCode ^ - iconColor.hashCode ^ - checkedBackgroundColor.hashCode ^ - uncheckedBackgroundColor.hashCode; + borderColor.hashCode ^ iconColor.hashCode ^ checkedBackgroundColor.hashCode ^ uncheckedBackgroundColor.hashCode; } diff --git a/forui/test/src/widgets/checkbox_golden_test.dart b/forui/test/src/widgets/checkbox_golden_test.dart index ea7ffa5c5..f0d747649 100644 --- a/forui/test/src/widgets/checkbox_golden_test.dart +++ b/forui/test/src/widgets/checkbox_golden_test.dart @@ -2,8 +2,8 @@ library; import 'package:flutter_test/flutter_test.dart'; -import 'package:forui/forui.dart'; +import 'package:forui/forui.dart'; import '../test_scaffold.dart'; void main() { @@ -15,7 +15,8 @@ void main() { (false, true), (true, true), ]) { - testWidgets('$name with ${enabled ? 'enabled' : 'disabled'} & ${initialValue ? 'value' : 'no-value'}', (tester) async { + testWidgets('$name with ${enabled ? 'enabled' : 'disabled'} & ${initialValue ? 'value' : 'no-value'}', + (tester) async { await tester.pumpWidget( TestScaffold( data: theme, @@ -29,7 +30,9 @@ void main() { await expectLater( find.byType(TestScaffold), - matchesGoldenFile('check-box/$name-${enabled ? 'enabled' : 'disabled'}-${initialValue ? 'value' : 'no-value'}.png'), + matchesGoldenFile( + 'check-box/$name-${enabled ? 'enabled' : 'disabled'}-${initialValue ? 'value' : 'no-value'}.png', + ), ); }); } From 8246c7f622fd07435337f832f49d426b2683f5e8 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Tue, 2 Jul 2024 20:09:29 +0800 Subject: [PATCH 5/7] Update checkbox example --- docs/pages/docs/check-box.mdx | 45 -------- docs/pages/docs/checkbox.mdx | 107 ++++++++++++++++++ forui/lib/src/theme/theme_data.dart | 8 +- forui/lib/src/widgets/checkbox.dart | 92 +++++++-------- .../check-box/zinc-light-disabled-value.png | Bin 22695 -> 22710 bytes .../check-box/zinc-light-enabled-no-value.png | Bin 22196 -> 22195 bytes .../check-box/zinc-light-enabled-value.png | Bin 22392 -> 22374 bytes .../src/widgets/checkbox_golden_test.dart | 2 +- samples/lib/main.dart | 8 +- samples/lib/widgets/check_box.dart | 27 ----- samples/lib/widgets/checkbox.dart | 93 +++++++++++++++ 11 files changed, 257 insertions(+), 125 deletions(-) delete mode 100644 docs/pages/docs/check-box.mdx create mode 100644 docs/pages/docs/checkbox.mdx delete mode 100644 samples/lib/widgets/check_box.dart create mode 100644 samples/lib/widgets/checkbox.dart diff --git a/docs/pages/docs/check-box.mdx b/docs/pages/docs/check-box.mdx deleted file mode 100644 index 95c280904..000000000 --- a/docs/pages/docs/check-box.mdx +++ /dev/null @@ -1,45 +0,0 @@ -import { Tabs } from 'nextra/components'; -import { Widget } from "../../components/widget"; - -# Check box -A control that allows the user to toggle between checked and not checked. It can also be used in a form. - -On touch devices, it is recommended to use a [switch](/docs/switch) instead in most cases. - - - - - - - ```dart - FCheckBox(); - ``` - - - -## Usage - -### `FCheckBox(...)` - -```dart -FCheckBox( - enabled: true, - initialValue: true, -); -``` - -## Examples - -### Disabled - - - - - - - ```dart - FCheckBox(); - ``` - - - diff --git a/docs/pages/docs/checkbox.mdx b/docs/pages/docs/checkbox.mdx new file mode 100644 index 000000000..e9f719bec --- /dev/null +++ b/docs/pages/docs/checkbox.mdx @@ -0,0 +1,107 @@ +import { Tabs } from 'nextra/components'; +import { Widget } from "../../components/widget"; + +# Checkbox +A control that allows the user to toggle between checked and not checked. It can also be used in a form. + +On touch devices, it is recommended to use a [switch](/docs/switch) instead in most cases. + + + + + + + ```dart + FCheckBox(); + ``` + + + +## Usage + +### `FCheckbox(...)` + +```dart +FCheckbox( + enabled: true, + initialValue: true, +); +``` + +## Examples + +### Disabled + + + + + + + ```dart + FCheckbox( + 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 FCheckbox(), + 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(), + ), + ], + ), + ); + } + ``` + + \ No newline at end of file diff --git a/forui/lib/src/theme/theme_data.dart b/forui/lib/src/theme/theme_data.dart index e78d28136..c00815fb9 100644 --- a/forui/lib/src/theme/theme_data.dart +++ b/forui/lib/src/theme/theme_data.dart @@ -34,8 +34,8 @@ final class FThemeData with Diagnosticable { /// The card style. final FCardStyle cardStyle; - /// The check box style. - final FCheckBoxStyle checkBoxStyle; + /// The checkbox style. + final FCheckboxStyle checkBoxStyle; /// The dialog style. final FDialogStyle dialogStyle; @@ -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, diff --git a/forui/lib/src/widgets/checkbox.dart b/forui/lib/src/widgets/checkbox.dart index b73498adb..953c2815f 100644 --- a/forui/lib/src/widgets/checkbox.dart +++ b/forui/lib/src/widgets/checkbox.dart @@ -5,15 +5,15 @@ import 'package:flutter/widgets.dart'; import 'package:forui/forui.dart'; -/// A check box control that allows the user to toggle between checked and not checked. +/// 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 +/// 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. /// /// See: -/// * https://forui.dev/docs/check-box for working examples. -/// * [FCheckBoxStyle] for customizing a check box's appearance. -class FCheckBox extends StatelessWidget { +/// * 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. /// @@ -24,10 +24,10 @@ class FCheckBox extends StatelessWidget { /// Called when the user initiates a change to the FCheckBox's value: when they have checked or unchecked this box. final ValueChanged? onChange; - /// Whether this check box should focus itself if nothing else is already focused. Defaults to false. + /// Whether this checkbox should focus itself if nothing else is already focused. Defaults to false. final bool autofocus; - /// Defines the [FocusNode] for this check box. + /// Defines the [FocusNode] for this checkbox. final FocusNode? focusNode; /// Handler called when the focus changes. @@ -73,8 +73,8 @@ class FCheckBox extends StatelessWidget { /// * [RestorationManager], which explains how state restoration works in Flutter. final String? restorationId; - /// Creates a [FCheckBox]. - const FCheckBox({ + /// Creates a [FCheckbox]. + const FCheckbox({ this.semanticLabel, this.onChange, this.autofocus = false, @@ -174,53 +174,53 @@ class FCheckBox extends StatelessWidget { } } -/// A [FCheckBox]'s style. -final class FCheckBoxStyle with Diagnosticable { - /// The duration of the animation when the check box's switches between checked and unchecked. +/// A [FCheckbox]'s style. +final class FCheckboxStyle with Diagnosticable { + /// The duration of the animation when the checkbox's switches between checked and unchecked. /// /// Defaults to `const Duration(milliseconds: 100)`. final Duration animationDuration; - /// The curve of the animation when the check box's switches between checked and unchecked. + /// The curve of the animation when the checkbox's switches between checked and unchecked. /// /// Defaults to [Curves.linear]. final Curve curve; - /// The check box's style when it's enabled. - final FCheckBoxStateStyle enabledStyle; + /// The checkbox's style when it's enabled. + final FCheckboxStateStyle enabledStyle; - /// The check box's style when it's disabled. - final FCheckBoxStateStyle disabledStyle; + /// The checkbox's style when it's disabled. + final FCheckboxStateStyle disabledStyle; - /// Creates a [FCheckBoxStyle]. - FCheckBoxStyle({ + /// Creates a [FCheckboxStyle]. + FCheckboxStyle({ required this.enabledStyle, required this.disabledStyle, this.animationDuration = const Duration(milliseconds: 100), this.curve = Curves.linear, }); - /// Creates a [FCheckBoxStyle] that inherits its properties from the given [FColorScheme]. - FCheckBoxStyle.inherit({required FColorScheme colorScheme}) + /// Creates a [FCheckboxStyle] that inherits its properties from the given [FColorScheme]. + FCheckboxStyle.inherit({required FColorScheme colorScheme}) : animationDuration = const Duration(milliseconds: 100), curve = Curves.linear, - enabledStyle = FCheckBoxStateStyle( - borderColor: colorScheme.foreground, + enabledStyle = FCheckboxStateStyle( + borderColor: colorScheme.primary, iconColor: colorScheme.background, - checkedBackgroundColor: colorScheme.foreground, + checkedBackgroundColor: colorScheme.primary, uncheckedBackgroundColor: colorScheme.background, ), - disabledStyle = FCheckBoxStateStyle( - borderColor: colorScheme.foreground.withOpacity(0.5), + disabledStyle = FCheckboxStateStyle( + borderColor: colorScheme.primary.withOpacity(0.5), iconColor: colorScheme.background.withOpacity(0.5), - checkedBackgroundColor: colorScheme.foreground.withOpacity(0.5), + checkedBackgroundColor: colorScheme.primary.withOpacity(0.5), uncheckedBackgroundColor: colorScheme.background.withOpacity(0.5), ); - /// Returns a copy of this [FCheckBoxStyle] with the given properties replaced. + /// Returns a copy of this [FCheckboxStyle] with the given properties replaced. /// /// ```dart - /// final style = FCheckBoxStyle( + /// final style = FCheckboxStyle( /// animationDuration: const Duration(minutes: 1), /// curve: Curves.linear, /// // Other arguments omitted for brevity. @@ -233,13 +233,13 @@ final class FCheckBoxStyle with Diagnosticable { /// print(style.animationDuration); // const Duration(minutes: 1) /// print(copy.curve); // Curves.bounceIn /// ``` - FCheckBoxStyle copyWith({ + FCheckboxStyle copyWith({ Duration? animationDuration, Curve? curve, - FCheckBoxStateStyle? enabledStyle, - FCheckBoxStateStyle? disabledStyle, + FCheckboxStateStyle? enabledStyle, + FCheckboxStateStyle? disabledStyle, }) => - FCheckBoxStyle( + FCheckboxStyle( animationDuration: animationDuration ?? this.animationDuration, curve: curve ?? this.curve, enabledStyle: enabledStyle ?? this.enabledStyle, @@ -259,7 +259,7 @@ final class FCheckBoxStyle with Diagnosticable { @override bool operator ==(Object other) => identical(this, other) || - other is FCheckBoxStyle && + other is FCheckboxStyle && runtimeType == other.runtimeType && animationDuration == other.animationDuration && curve == other.curve && @@ -270,29 +270,29 @@ final class FCheckBoxStyle with Diagnosticable { int get hashCode => animationDuration.hashCode ^ curve.hashCode ^ enabledStyle.hashCode ^ disabledStyle.hashCode; } -/// A check box state's style. -final class FCheckBoxStateStyle with Diagnosticable { - /// The check box's border color. +/// A checkbox state's style. +final class FCheckboxStateStyle with Diagnosticable { + /// The checkbox's border color. final Color borderColor; - /// The checked check box's icon's color. + /// The checked checkbox's icon's color. final Color iconColor; - /// The checked check box's background color. + /// The checked checkbox's background color. final Color checkedBackgroundColor; - /// The unchecked check box's background color. + /// The unchecked checkbox's background color. final Color uncheckedBackgroundColor; - /// Creates a [FCheckBoxStateStyle]. - const FCheckBoxStateStyle({ + /// Creates a [FCheckboxStateStyle]. + const FCheckboxStateStyle({ required this.borderColor, required this.iconColor, required this.checkedBackgroundColor, required this.uncheckedBackgroundColor, }); - /// Returns a copy of this [FCheckBoxStateStyle] with the given properties replaced. + /// Returns a copy of this [FCheckboxStateStyle] with the given properties replaced. /// /// ```dart /// final style = FCheckBoxStateStyle( @@ -308,13 +308,13 @@ final class FCheckBoxStateStyle with Diagnosticable { /// print(style.iconColor == copy.iconColor); // true /// print(style.checkedBackgroundColor == copy.checkedBackgroundColor); // false /// ``` - FCheckBoxStateStyle copyWith({ + FCheckboxStateStyle copyWith({ Color? borderColor, Color? iconColor, Color? checkedBackgroundColor, Color? uncheckedBackgroundColor, }) => - FCheckBoxStateStyle( + FCheckboxStateStyle( borderColor: borderColor ?? this.borderColor, iconColor: iconColor ?? this.iconColor, checkedBackgroundColor: checkedBackgroundColor ?? this.checkedBackgroundColor, @@ -334,7 +334,7 @@ final class FCheckBoxStateStyle with Diagnosticable { @override bool operator ==(Object other) => identical(this, other) || - other is FCheckBoxStateStyle && + other is FCheckboxStateStyle && runtimeType == other.runtimeType && borderColor == other.borderColor && iconColor == other.iconColor && diff --git a/forui/test/golden/check-box/zinc-light-disabled-value.png b/forui/test/golden/check-box/zinc-light-disabled-value.png index 265ae390290042b69a9886028e71fa0d49cbe314..266d5ea3853dceacb501f9b38f5065a5aeaefa92 100644 GIT binary patch literal 22710 zcmeI4X;f257Jwfv2(4+i(};k8w1dY{TnVU%BBJOZ?hy@1fxJ97h2xEP(YE z9ECsc!a`JY(J5pFjlEslNNe)5SZ6%7L~v_r5p6AajF}qf1k(cm0(X4?1ONg8-T=G- zf0w|-R42T5~r5jTc$Y)rpHoTeTd6WN8BQ=Fb?aWT~DR)cNf+Z_oOEFZn^kMLGN}i zR&OdvlulUU?LtPzQzt)Mr%f&4{tQiR@+_M=c=x|#w-=9~wYT(lJaw&5KfOX^jE7eY z50@zFpSs!+?r_qS2B~599nNXI+vxqpEv(Ol^v?;)gGEVpoVxV?%)RXmZuT{c);9 zd0yyyGhgJKqDwN?ze^Tc?OgeL)?hB#ay6+$!b_A@6`pZ8mv{GdGWF!iUwbY}?9HwP z4|dd$1yK*BY3cbVSO-$WN-776w&lfFX`)2KNS}h18lW2Euei7A zxKm_*WoRZ(vH039B5Noh)hRYhew`~*sYS{LugcaDRI%hNzjHNcHLV`P*!;Nh)?p%1 z{NSIX&g8Le;}k^)kIPL+NQkENOQVBinM5LyB-8a3D(h)NqBCL+cG6i{@;amjvtjwW zOy!piEE0)SZlwwcy_*^u^-d07a{Usw93qi~TZbK$^8Kuq0UIQLiyOLnTYXv6$PG5+y8vV7=*QYMf&-oB#l^j2;w1~s`-|$IKX+@3 zl~oWey)@%Bi;~l(!`WRtLIjSdk%Bo_PU(gsNTk;x($;~SN}96JPm_auF>r7Oy7rv& zvbjXc<#IiJN*n|M8ec+zG_Jo8!KB(TNu7|8Sj0o#%c8 zpp3s{aZub{oUXcea^x2{Y4a74o0S87exy#WM7D+GAxX&DToGnh88c{-kBFC%i?tmR zwLv7JhwCaieUUt_ysx==qC3-FG1OH@ScB&4WzJj*=ZDN&*3^1=r743Y*Lw+hh;Wq5 zd6)`MydH_Rx}2ZK;aspl#9)hulZ=ro;p~|*uUTXLRcDxDt8WzzYUXqv{2Xcu@%C+04?k!e`AnkMmH47b&JLt){xKZx(6ttg?Wbr| zvlD)$OnN+Aqp#g)4W>;G%)vOH=NeK?V54vC7!t3$gBijZZ*T*3{s~;$3$gA~gNgH# zFwu)~nm^q%@?au|EnLj8*yX**aiPB0O01Y7Yny4qjnYoXs|9^&sTJp$M20U~raBat zqm2Az>|B(wLNsYvG1$e6(;a<<9N1=G!t_IzSj~~Yq}$|Bwc2oR_fO1TYxrBJWE)n0 z$@30Mc$-OyTATfS?I(GC%tLWaP0h-|+jXe+9>2oz8P}aXzc!mSAxXD)MtM3~ zGxNU~aF?+K5P#Lc3>;4NlE!I|D`yD~S&Ozb6*mTbI`-A+U@KmHN3 z!gm+pP(ShfSq!zQU!wl~u&3}CZCH2lQIcVN%kTsD;M%n;1=J@n8#Z z{*{trS7^n{Wk`?t1P1aPH;6_ARI^p98=tCX7lpSoD`MJN!535!^ys#U4oTI~bZss? z?#)F6Gr=O;yh)XsscB2s9!pgxO12INL<$n4O!AgXHHWJi3h$XN9994OzT88m-qlu4 z3*3PQ)F3B}KArKISV@N+9r=aFSl909iJ8X7?+^~x=xsWvU4@}=^8lNU0X_wt7i0I>aAUn_u zfB*sz00;mC5P$$c03d(>1ONg60R$ib5d7akP_27Jtwk0Pp?Gy}hQW?Z2r}J`{4YRv zLHR~>opiy}{)6q*FZn6pF}h*^0i9ra06<`R06^e+06+jBAm9za8{mykFj>Gb0Fwnw z4*&=-Hh{4KX8?ppy&^z(1mO{Q1Mmh|17ATXfX^bLf7xTG@)4e3oQIDwfz#GF`{4LJ jrU(E80OHU4)2zev!f6JS3pXqfBktL`&n?fD^7sD$e|?#C literal 22695 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 diff --git a/forui/test/golden/check-box/zinc-light-enabled-no-value.png b/forui/test/golden/check-box/zinc-light-enabled-no-value.png index 35233f59a46ca048c2d7d9878e33d193a3588d23..5e477dcc5c38a776310e75a98cc47143c2b46d9f 100644 GIT binary patch delta 1919 zcmeHH`BPI@6i!5?RuJog8U)5Vns!`hiwT>7AW~s8AccS=1gyvqWj6^Chy-ngGPE*6 zD}|5%E+{Vq&=7Wl3I#DLOGqMH06_voLKs#PNcvu|GyMblWADtHduQHvzH{#PopURB za6S)Sk%SD5ZFOLIOy^rxJ5bUd<+JRczhb*IdraN^!H7-#I;>Et zvcN2R66u}2=_?ba=B(HV1}-v_kMx#q_IAc66(rYfu|DoMIy#C%p(OLAzEm1bk|med zk>CG?Qs3;5{Sl(MK%>%7n9X2d3Yz}r?Z7~gc)x+h8+q`SOl7UVpR5;!u&>BvvH%Qb z(3I!cn4UgLQx8AWGw4)mPXIcq)IufXGRK`a)d&}e_-Ee%1Ln8ggoD`Or%Mqf))W>cVkeUQ#17 zePvmLuCEvgx0z&nrTNorG zx3`bBDeFX1Y4?NE5i|1JQxg;9#O^>8219al3y^i)JEd$7*y5-7sIbFq0s~Xf!y6An z3n_Wih75Ce~w^!5f?*hN38t*!0Twpg<`PjQWHWncD;p%>SGq>+dJdG%f{; zZK1#9?ffpAA~=)m86F;vJ9Fk3CRA?e;_O2rk#HRlpb)p_9oduaO}BK4FZIf|@0$NT zf%2}U-7!A0A@R=qF$`2n3VPpDgV_hHwJk_4F!dluCs${Ekf z!4)7rlmo!y$B$EUn6C;}wPt>JN#Au{Y7UgQ^XMnzFTNhe;_=f1wOo0Ef}JYMzXmp~ zfTAb^#lw8l`N_bWFvAFew^wqx8#T(`?6%0NqWW1JiZp7lj(5unLoiaN0g88-XbjZT zDd@O=4;#}gJ1w&(z*r`$pAi!4=`O*mtI9kM)&Ka?K zGR8H^DX0D_>DbuC!Pw?hX5W+doIEx=Dp9(J#b)!45LG3n7HBCkrqM7<1;RxUuEQYj z>#H}mLR>F&;T&F4On;ECudg6>D$vznM+^GnOrl?q9n6Ok(XeP+ma&U;jx6-MWE-&YXdpm?wMF#TD#r^2U z^_uA{azi;g$Gz;8$QWg4z1nzTBus=L7&@?iyP=`g!p6ntLznfO#)X#|Hc}QS=koGZ z91e%VD0hI}B)DH)eW$#p!k)noKf5z+!&X5=8`OQUpH_H^ihBEX{5V(Y`km`M`r<^*JfR)*%hTQKWZ8-HH~t2O C|1`Y- literal 22196 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 diff --git a/forui/test/src/widgets/checkbox_golden_test.dart b/forui/test/src/widgets/checkbox_golden_test.dart index f0d747649..522fe0678 100644 --- a/forui/test/src/widgets/checkbox_golden_test.dart +++ b/forui/test/src/widgets/checkbox_golden_test.dart @@ -21,7 +21,7 @@ void main() { TestScaffold( data: theme, background: background, - child: FCheckBox( + child: FCheckbox( enabled: enabled, initialValue: initialValue, ), diff --git a/samples/lib/main.dart b/samples/lib/main.dart index 38855872c..8896f9170 100644 --- a/samples/lib/main.dart +++ b/samples/lib/main.dart @@ -56,8 +56,12 @@ class _AppRouter extends $_AppRouter { page: CardRoute.page, ), AutoRoute( - path: '/check-box/default', - page: CheckBoxRoute.page, + path: '/checkbox/default', + page: CheckboxRoute.page, + ), + AutoRoute( + path: '/checkbox/form', + page: FormCheckboxRoute.page, ), AutoRoute( path: '/dialog/default', diff --git a/samples/lib/widgets/check_box.dart b/samples/lib/widgets/check_box.dart deleted file mode 100644 index 7bd86c989..000000000 --- a/samples/lib/widgets/check_box.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:auto_route/auto_route.dart'; -import 'package:flutter/widgets.dart'; -import 'package:forui/forui.dart'; -import 'package:forui_samples/sample_scaffold.dart'; - -@RoutePage() -class CheckBoxPage extends SampleScaffold { - final bool enabled; - - CheckBoxPage({ - @queryParam super.theme, - @queryParam this.enabled = false, - }); - - @override - Widget child(BuildContext context) => Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 30), - child: FCheckBox( - enabled: enabled, - ), - ), - ], - ); -} diff --git a/samples/lib/widgets/checkbox.dart b/samples/lib/widgets/checkbox.dart new file mode 100644 index 000000000..9b2d626a7 --- /dev/null +++ b/samples/lib/widgets/checkbox.dart @@ -0,0 +1,93 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/widgets.dart'; +import 'package:forui/forui.dart'; +import 'package:forui_samples/sample_scaffold.dart'; + +@RoutePage() +class CheckboxPage extends SampleScaffold { + final bool enabled; + + CheckboxPage({ + @queryParam super.theme, + @queryParam this.enabled = false, + }); + + @override + Widget child(BuildContext context) => Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 30), + child: FCheckbox( + enabled: enabled, + ), + ), + ], + ); +} + +@RoutePage() +class FormCheckboxPage extends SampleScaffold { + + FormCheckboxPage({ + @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 FCheckbox(), + 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(), + ), + ], + ), + ); +} + From c825e7599c479bc462813caa864f4bc21e2f4d6b Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Tue, 2 Jul 2024 20:12:20 +0800 Subject: [PATCH 6/7] Fix failing build --- samples/lib/widgets/checkbox.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/samples/lib/widgets/checkbox.dart b/samples/lib/widgets/checkbox.dart index 9b2d626a7..cc9340684 100644 --- a/samples/lib/widgets/checkbox.dart +++ b/samples/lib/widgets/checkbox.dart @@ -90,4 +90,3 @@ class _LoginFormState extends State { ), ); } - From cbad28333a999515b857db0777fe64b0d9913093 Mon Sep 17 00:00:00 2001 From: Pante Date: Tue, 2 Jul 2024 12:13:47 +0000 Subject: [PATCH 7/7] Commit from GitHub Actions (Forui Samples Presubmit) --- samples/lib/widgets/checkbox.dart | 88 +++++++++++++++---------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/samples/lib/widgets/checkbox.dart b/samples/lib/widgets/checkbox.dart index cc9340684..b3a46b631 100644 --- a/samples/lib/widgets/checkbox.dart +++ b/samples/lib/widgets/checkbox.dart @@ -1,6 +1,8 @@ -import 'package:auto_route/auto_route.dart'; import 'package:flutter/widgets.dart'; + +import 'package:auto_route/auto_route.dart'; import 'package:forui/forui.dart'; + import 'package:forui_samples/sample_scaffold.dart'; @RoutePage() @@ -14,31 +16,29 @@ class CheckboxPage extends SampleScaffold { @override Widget child(BuildContext context) => Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 30), - child: FCheckbox( - enabled: enabled, - ), - ), - ], - ); + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 30), + child: FCheckbox( + enabled: enabled, + ), + ), + ], + ); } @RoutePage() class FormCheckboxPage extends SampleScaffold { - FormCheckboxPage({ @queryParam super.theme, }); @override Widget child(BuildContext context) => const Padding( - padding: EdgeInsets.all(15.0), - child: LoginForm(), - ); - + padding: EdgeInsets.all(15.0), + child: LoginForm(), + ); } class LoginForm extends StatefulWidget { @@ -58,35 +58,35 @@ class _LoginFormState extends State { @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( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - const FCheckbox(), - const SizedBox(width: 7), - Text('Remember password?', style: context.theme.typography.sm), + 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 FCheckbox(), + 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(), + ), ], ), - const SizedBox(height: 30), - FButton( - label: const Text('Login'), - onPress: () => _formKey.currentState!.validate(), - ), - ], - ), - ); + ); }