diff --git a/docs/pages/docs/button.mdx b/docs/pages/docs/button.mdx index 59660b2f7..0ac98529c 100644 --- a/docs/pages/docs/button.mdx +++ b/docs/pages/docs/button.mdx @@ -109,7 +109,7 @@ FButton.raw( -### With Icon +### With Text and Icon @@ -123,4 +123,20 @@ FButton.raw( ), ``` - \ No newline at end of file + + +### With Only Icon + + + + + + ```dart {2} + FButton.icon( + icon: FButtonIcon(icon: FAssets.icons.chevronRight), + onPress: () {}, + ), + ``` + + + diff --git a/forui/lib/src/widgets/button/button.dart b/forui/lib/src/widgets/button/button.dart index ca326a73f..f1d6637b9 100644 --- a/forui/lib/src/widgets/button/button.dart +++ b/forui/lib/src/widgets/button/button.dart @@ -99,6 +99,18 @@ class FButton extends StatelessWidget { label: label, ); + /// Creates a [FButton] that contains only an icon. + FButton.icon({ + required this.onPress, + required Widget child, + this.style = Variant.outline, + this.onLongPress, + this.autofocus = false, + this.focusNode, + this.onFocusChange, + super.key, + }) : child = _FButtonIconContent(child: child); + /// Creates a [FButton] with custom content. const FButton.raw({ required this.onPress, @@ -200,12 +212,16 @@ class FButtonCustomStyle extends FButtonStyle with Diagnosticable { /// The icon's style. final FButtonIconStyle icon; + /// The icon content's style. + final FButtonIconContentStyle iconContent; + /// Creates a [FButtonCustomStyle]. FButtonCustomStyle({ required this.enabledBoxDecoration, required this.disabledBoxDecoration, required this.content, required this.icon, + this.iconContent = const FButtonIconContentStyle(), }); /// Returns a copy of this [FButtonCustomStyle] with the given properties replaced. @@ -230,12 +246,14 @@ class FButtonCustomStyle extends FButtonStyle with Diagnosticable { BoxDecoration? disabledBoxDecoration, FButtonContentStyle? content, FButtonIconStyle? icon, + FButtonIconContentStyle? iconContent, }) => FButtonCustomStyle( enabledBoxDecoration: enabledBoxDecoration ?? this.enabledBoxDecoration, disabledBoxDecoration: disabledBoxDecoration ?? this.disabledBoxDecoration, content: content ?? this.content, icon: icon ?? this.icon, + iconContent: iconContent ?? this.iconContent, ); @override @@ -245,7 +263,8 @@ class FButtonCustomStyle extends FButtonStyle with Diagnosticable { ..add(DiagnosticsProperty('enabledBoxDecoration', enabledBoxDecoration)) ..add(DiagnosticsProperty('disabledBoxDecoration', disabledBoxDecoration)) ..add(DiagnosticsProperty('content', content)) - ..add(DiagnosticsProperty('icon', icon)); + ..add(DiagnosticsProperty('icon', icon)) + ..add(DiagnosticsProperty('iconContent', iconContent)); } @override @@ -256,10 +275,16 @@ class FButtonCustomStyle extends FButtonStyle with Diagnosticable { enabledBoxDecoration == other.enabledBoxDecoration && disabledBoxDecoration == other.disabledBoxDecoration && content == other.content && - icon == other.icon; + icon == other.icon && + iconContent == other.iconContent; @override - int get hashCode => enabledBoxDecoration.hashCode ^ disabledBoxDecoration.hashCode ^ content.hashCode ^ icon.hashCode; + int get hashCode => + enabledBoxDecoration.hashCode ^ + disabledBoxDecoration.hashCode ^ + content.hashCode ^ + icon.hashCode ^ + iconContent.hashCode; } typedef _Data = ({FButtonCustomStyle style, bool enabled}); diff --git a/forui/lib/src/widgets/button/button_content.dart b/forui/lib/src/widgets/button/button_content.dart index 01be48609..ea9091d1c 100644 --- a/forui/lib/src/widgets/button/button_content.dart +++ b/forui/lib/src/widgets/button/button_content.dart @@ -37,6 +37,59 @@ final class _FButtonContent extends StatelessWidget { } } +final class _FButtonIconContent extends StatelessWidget { + final Widget child; + + const _FButtonIconContent({required this.child}); + + @override + Widget build(BuildContext context) { + final (:style, enabled: _) = FButton._of(context); + + return Padding( + padding: style.iconContent.padding, + child: child, + ); + } +} + +/// [FButton] icon content's style. +class FButtonIconContentStyle with Diagnosticable { + /// The padding. + final EdgeInsets padding; + + /// Creates a [FButtonIconContentStyle]. + const FButtonIconContentStyle({ + this.padding = const EdgeInsets.symmetric( + horizontal: 16, + vertical: 12.5, + ), + }); + + /// Returns a copy of this [FButtonIconContentStyle] with the given properties replaced. + @useResult + FButtonIconContentStyle copyWith({ + EdgeInsets? padding, + }) => + FButtonIconContentStyle( + padding: padding ?? this.padding, + ); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('padding', padding)); + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is FButtonIconContentStyle && runtimeType == other.runtimeType && padding == other.padding; + + @override + int get hashCode => padding.hashCode; +} + /// [FButton] content's style. class FButtonContentStyle with Diagnosticable { /// The [TextStyle] when this button is enabled. diff --git a/forui/test/golden/button/zinc-dark-Variant.destructive-icon-disabled-button.png b/forui/test/golden/button/zinc-dark-Variant.destructive-icon-disabled-button.png new file mode 100644 index 000000000..8ca016387 Binary files /dev/null and b/forui/test/golden/button/zinc-dark-Variant.destructive-icon-disabled-button.png differ diff --git a/forui/test/golden/button/zinc-dark-Variant.destructive-icon-enabled-button.png b/forui/test/golden/button/zinc-dark-Variant.destructive-icon-enabled-button.png new file mode 100644 index 000000000..f147f16ec Binary files /dev/null and b/forui/test/golden/button/zinc-dark-Variant.destructive-icon-enabled-button.png differ diff --git a/forui/test/golden/button/zinc-dark-Variant.outline-icon-disabled-button.png b/forui/test/golden/button/zinc-dark-Variant.outline-icon-disabled-button.png new file mode 100644 index 000000000..8c27e01cc Binary files /dev/null and b/forui/test/golden/button/zinc-dark-Variant.outline-icon-disabled-button.png differ diff --git a/forui/test/golden/button/zinc-dark-Variant.outline-icon-enabled-button.png b/forui/test/golden/button/zinc-dark-Variant.outline-icon-enabled-button.png new file mode 100644 index 000000000..5f3cdbe79 Binary files /dev/null and b/forui/test/golden/button/zinc-dark-Variant.outline-icon-enabled-button.png differ diff --git a/forui/test/golden/button/zinc-dark-Variant.primary-icon-disabled-button.png b/forui/test/golden/button/zinc-dark-Variant.primary-icon-disabled-button.png new file mode 100644 index 000000000..240e44905 Binary files /dev/null and b/forui/test/golden/button/zinc-dark-Variant.primary-icon-disabled-button.png differ diff --git a/forui/test/golden/button/zinc-dark-Variant.primary-icon-enabled-button.png b/forui/test/golden/button/zinc-dark-Variant.primary-icon-enabled-button.png new file mode 100644 index 000000000..acdd2c4a7 Binary files /dev/null and b/forui/test/golden/button/zinc-dark-Variant.primary-icon-enabled-button.png differ diff --git a/forui/test/golden/button/zinc-dark-Variant.secondary-icon-disabled-button.png b/forui/test/golden/button/zinc-dark-Variant.secondary-icon-disabled-button.png new file mode 100644 index 000000000..02f59e70e Binary files /dev/null and b/forui/test/golden/button/zinc-dark-Variant.secondary-icon-disabled-button.png differ diff --git a/forui/test/golden/button/zinc-dark-Variant.secondary-icon-enabled-button.png b/forui/test/golden/button/zinc-dark-Variant.secondary-icon-enabled-button.png new file mode 100644 index 000000000..912880786 Binary files /dev/null and b/forui/test/golden/button/zinc-dark-Variant.secondary-icon-enabled-button.png differ diff --git a/forui/test/golden/button/zinc-light-Variant.destructive-icon-disabled-button.png b/forui/test/golden/button/zinc-light-Variant.destructive-icon-disabled-button.png new file mode 100644 index 000000000..e6d980956 Binary files /dev/null and b/forui/test/golden/button/zinc-light-Variant.destructive-icon-disabled-button.png differ diff --git a/forui/test/golden/button/zinc-light-Variant.destructive-icon-enabled-button.png b/forui/test/golden/button/zinc-light-Variant.destructive-icon-enabled-button.png new file mode 100644 index 000000000..450410851 Binary files /dev/null and b/forui/test/golden/button/zinc-light-Variant.destructive-icon-enabled-button.png differ diff --git a/forui/test/golden/button/zinc-light-Variant.outline-icon-disabled-button.png b/forui/test/golden/button/zinc-light-Variant.outline-icon-disabled-button.png new file mode 100644 index 000000000..917a35b44 Binary files /dev/null and b/forui/test/golden/button/zinc-light-Variant.outline-icon-disabled-button.png differ diff --git a/forui/test/golden/button/zinc-light-Variant.outline-icon-enabled-button.png b/forui/test/golden/button/zinc-light-Variant.outline-icon-enabled-button.png new file mode 100644 index 000000000..780bc9959 Binary files /dev/null and b/forui/test/golden/button/zinc-light-Variant.outline-icon-enabled-button.png differ diff --git a/forui/test/golden/button/zinc-light-Variant.primary-icon-disabled-button.png b/forui/test/golden/button/zinc-light-Variant.primary-icon-disabled-button.png new file mode 100644 index 000000000..bf8cbf295 Binary files /dev/null and b/forui/test/golden/button/zinc-light-Variant.primary-icon-disabled-button.png differ diff --git a/forui/test/golden/button/zinc-light-Variant.primary-icon-enabled-button.png b/forui/test/golden/button/zinc-light-Variant.primary-icon-enabled-button.png new file mode 100644 index 000000000..f789c8b6c Binary files /dev/null and b/forui/test/golden/button/zinc-light-Variant.primary-icon-enabled-button.png differ diff --git a/forui/test/golden/button/zinc-light-Variant.secondary-icon-disabled-button.png b/forui/test/golden/button/zinc-light-Variant.secondary-icon-disabled-button.png new file mode 100644 index 000000000..ab26f2d4e Binary files /dev/null and b/forui/test/golden/button/zinc-light-Variant.secondary-icon-disabled-button.png differ diff --git a/forui/test/golden/button/zinc-light-Variant.secondary-icon-enabled-button.png b/forui/test/golden/button/zinc-light-Variant.secondary-icon-enabled-button.png new file mode 100644 index 000000000..f4a7109a9 Binary files /dev/null and b/forui/test/golden/button/zinc-light-Variant.secondary-icon-enabled-button.png differ diff --git a/forui/test/src/widgets/button/button_golden_test.dart b/forui/test/src/widgets/button/button_golden_test.dart index 9ed587cc9..cd162e6af 100644 --- a/forui/test/src/widgets/button/button_golden_test.dart +++ b/forui/test/src/widgets/button/button_golden_test.dart @@ -136,6 +136,56 @@ void main() { matchesGoldenFile('button/$name-$variant-disabled-raw-button.png'), ); }); + + testWidgets('$name with enabled icon', (tester) async { + await tester.pumpWidget( + TestScaffold( + data: theme, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: FButton.icon( + onPress: () {}, + style: variant, + child: FButtonIcon( + icon: FAssets.icons.chevronRight, + ), + ), + ), + ), + ); + + await expectLater( + find.byType(TestScaffold), + matchesGoldenFile( + 'button/$name-$variant-icon-enabled-button.png', + ), + ); + }); + + testWidgets('$name with disabled icon', (tester) async { + await tester.pumpWidget( + TestScaffold( + data: theme, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: FButton.icon( + onPress: null, + style: variant, + child: FButtonIcon( + icon: FAssets.icons.chevronRight, + ), + ), + ), + ), + ); + + await expectLater( + find.byType(TestScaffold), + matchesGoldenFile( + 'button/$name-$variant-icon-disabled-button.png', + ), + ); + }); } } }); diff --git a/samples/lib/main.dart b/samples/lib/main.dart index ab3a9f55d..38b8f45b6 100644 --- a/samples/lib/main.dart +++ b/samples/lib/main.dart @@ -71,6 +71,10 @@ class _AppRouter extends RootStackRouter { path: '/button/icon', page: ButtonIconRoute.page, ), + AutoRoute( + path: '/button/only-icon', + page: ButtonOnlyIconRoute.page, + ), AutoRoute( path: '/calendar/default', page: CalendarRoute.page, diff --git a/samples/lib/widgets/button.dart b/samples/lib/widgets/button.dart index 5ade2741e..fa5d6dc8b 100644 --- a/samples/lib/widgets/button.dart +++ b/samples/lib/widgets/button.dart @@ -52,3 +52,18 @@ class ButtonIconPage extends SampleScaffold { ), ); } + +@RoutePage() +class ButtonOnlyIconPage extends SampleScaffold { + ButtonOnlyIconPage({ + @queryParam super.theme, + }); + + @override + Widget child(BuildContext context) => IntrinsicWidth( + child: FButton.icon( + child: FButtonIcon(icon: FAssets.icons.chevronRight), + onPress: () {}, + ), + ); +} diff --git a/samples/pubspec.lock b/samples/pubspec.lock index c5a1244da..0c55bb373 100644 --- a/samples/pubspec.lock +++ b/samples/pubspec.lock @@ -367,18 +367,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "10.0.4" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.3" leak_tracker_testing: dependency: transitive description: @@ -407,18 +407,18 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.11.1" + version: "0.8.0" meta: dependency: transitive description: name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.12.0" mime: dependency: transitive description: @@ -652,10 +652,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.0" timing: dependency: transitive description: @@ -708,10 +708,10 @@ packages: dependency: transitive description: name: vm_service - sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc + sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" url: "https://pub.dev" source: hosted - version: "14.2.4" + version: "14.2.1" watcher: dependency: transitive description: