diff --git a/forui/example/lib/main.dart b/forui/example/lib/main.dart index af9511083..746c93cf0 100644 --- a/forui/example/lib/main.dart +++ b/forui/example/lib/main.dart @@ -50,21 +50,22 @@ class _ExampleWidgetState extends State { Widget build(BuildContext context) => Padding( padding: const EdgeInsets.all(8.0), child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ FButton( design: FButtonVariant.destructive, - text: 'Delete?', + labelText: 'Delete?', onPress: () => showAdaptiveDialog( context: context, builder: (context) => FDialog( alignment: FDialogAlignment.horizontal, title: 'Are you absolutely sure?', - subtitle: 'This action cannot be undone. This will permanently delete your account and remove your data from our servers.', + body: 'This action cannot be undone. This will permanently delete your account and remove your data from our servers.', actions: [ - FButton(design: FButtonVariant.outlined, text: 'Cancel', onPress: () { + FButton(design: FButtonVariant.outlined, labelText: 'Cancel', onPress: () { Navigator.of(context).pop(); }), - FButton(text: 'Continue', onPress: () {}), + FButton(labelText: 'Continue', onPress: () {}), ], ), ), diff --git a/forui/lib/src/widgets/badge/badge.dart b/forui/lib/src/widgets/badge/badge.dart index d6658af3d..da4eb8ea8 100644 --- a/forui/lib/src/widgets/badge/badge.dart +++ b/forui/lib/src/widgets/badge/badge.dart @@ -18,10 +18,13 @@ class FBadge extends StatelessWidget { /// Creates a [FBadge]. FBadge({ - required String label, + String? label, + Widget? rawLabel, this.design = FBadgeVariant.primary, super.key, - }) : builder = ((context, style) => FBadgeContent(label: label, style: style)); + }) : + assert((label == null) ^ (rawLabel == null), 'Either "label" or "rawLabel" must be provided, but not both.'), + builder = ((context, style) => FBadgeContent(rawLabel: rawLabel, label: label, style: style)); /// Creates a [FBadge]. const FBadge.raw({required this.design, required this.builder, super.key}); @@ -143,9 +146,9 @@ final class FBadgeStyle with Diagnosticable implements FBadgeDesign { properties ..add(ColorProperty('background', background)) ..add(ColorProperty('border', border)) - ..add(DiagnosticsProperty('borderRadius', borderRadius, defaultValue: BorderRadius.circular(100))) + ..add(DiagnosticsProperty('borderRadius', borderRadius, defaultValue: BorderRadius.circular(100))) ..add(DoubleProperty('borderWidth', borderWidth)) - ..add(DiagnosticsProperty('content', content)); + ..add(DiagnosticsProperty('content', content)); } @override diff --git a/forui/lib/src/widgets/badge/badge_content.dart b/forui/lib/src/widgets/badge/badge_content.dart index a4892633c..3e7b6b01c 100644 --- a/forui/lib/src/widgets/badge/badge_content.dart +++ b/forui/lib/src/widgets/badge/badge_content.dart @@ -2,15 +2,28 @@ part of 'badge.dart'; @internal final class FBadgeContent extends StatelessWidget { final FBadgeStyle style; - final String label; + final String? label; + final Widget? rawLabel; - const FBadgeContent({required this.style, required this.label, super.key}); + const FBadgeContent({ + required this.style, + this.label, + this.rawLabel, + super.key, + }); @override Widget build(BuildContext context) => Center( child: Padding( padding: style.content.padding, - child: Text(label, style: style.content.label.scale(context.theme.typography)), + child: DefaultTextStyle.merge( + style: style.content.label.scale(context.theme.typography), + child: switch ((label, rawLabel)) { + (final String label, _) => Text(label), + (_, final Widget label) => label, + _ => const Placeholder(), + }, + ), ), ); @@ -19,7 +32,7 @@ part of 'badge.dart'; super.debugFillProperties(properties); properties ..add(DiagnosticsProperty('style', style)) - ..add(StringProperty('label', label)); + ..add(StringProperty('labelText', label)); } } diff --git a/forui/lib/src/widgets/button/button.dart b/forui/lib/src/widgets/button/button.dart index 42a4cf681..3e009704d 100644 --- a/forui/lib/src/widgets/button/button.dart +++ b/forui/lib/src/widgets/button/button.dart @@ -2,15 +2,25 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:meta/meta.dart'; +import 'package:sugar/collection.dart'; import 'package:forui/forui.dart'; import 'package:forui/src/foundation/tappable.dart'; part 'button_content.dart'; + +part 'button_icon.dart'; + part 'button_styles.dart'; /// A button. class FButton extends StatelessWidget { + @useResult + static _Data _of(BuildContext context) { + final theme = context.dependOnInheritedWidgetOfExactType<_InheritedData>(); + return theme?.data ?? (style: context.theme.buttonStyles.primary, enabled: true); + } + /// The design. Defaults to [FBadgeVariant.primary]. final FButtonDesign design; @@ -44,8 +54,8 @@ class FButton extends StatelessWidget { /// Called with true if this widget's node gains focus, and false if it loses focus. final ValueChanged? onFocusChange; - /// The builder. - final Widget Function(BuildContext, FButtonStyle) builder; + /// The child. + final Widget child; /// Creates a [FButton]. FButton({ @@ -55,21 +65,24 @@ class FButton extends StatelessWidget { this.autofocus = false, this.focusNode, this.onFocusChange, - String? text, - SvgAsset? icon, + Widget? prefixIcon, + Widget? suffixIcon, + Widget? label, + String? labelText, super.key, - }) : builder = ((context, style) => FButtonContent( - text: text, - icon: icon, - style: style, - enabled: onPress != null, - )); + }) : assert((label != null) ^ (labelText != null), 'Either label or labelText must be provided, but not both.'), + child = FButtonContent( + prefixIcon: prefixIcon, + suffixIcon: suffixIcon, + label: label, + labelText: labelText, + ); /// Creates a [FButton]. const FButton.raw({ required this.design, required this.onPress, - required this.builder, + required this.child, this.onLongPress, this.autofocus = false, this.focusNode, @@ -87,20 +100,25 @@ class FButton extends StatelessWidget { FButtonVariant.destructive => context.theme.buttonStyles.destructive, }; - return Semantics( - container: true, - button: true, - enabled: onPress != null || onLongPress != null, - child: FocusableActionDetector( - autofocus: autofocus, - focusNode: focusNode, - onFocusChange: onFocusChange, - child: FTappable( - onTap: onPress, - onLongPress: onLongPress, - child: DecoratedBox( - decoration: onPress == null ? style.disabledBoxDecoration : style.enabledBoxDecoration, - child: builder(context, style), + final enabled = onPress != null || onLongPress != null; + + return _InheritedData( + data: (style: style, enabled: enabled), + child: Semantics( + container: true, + button: true, + enabled: enabled, + child: FocusableActionDetector( + autofocus: autofocus, + focusNode: focusNode, + onFocusChange: onFocusChange, + child: FTappable( + onTap: onPress, + onLongPress: onLongPress, + child: DecoratedBox( + decoration: onPress == null ? style.disabledBoxDecoration : style.enabledBoxDecoration, + child: child, + ), ), ), ), @@ -114,10 +132,10 @@ class FButton extends StatelessWidget { ..add(DiagnosticsProperty('design', design)) ..add(DiagnosticsProperty('onPress', onPress)) ..add(DiagnosticsProperty('onLongPress', onLongPress)) - ..add(FlagProperty('autofocus', value: autofocus, defaultValue: 'autofocus')) + ..add(FlagProperty('autofocus', value: autofocus, defaultValue: false, ifTrue: 'autofocus')) ..add(DiagnosticsProperty('focusNode', focusNode)) ..add(DiagnosticsProperty('onFocusChange', onFocusChange)) - ..add(DiagnosticsProperty('builder', builder)); + ..add(DiagnosticsProperty('builder', child)); } } @@ -125,7 +143,7 @@ class FButton extends StatelessWidget { sealed class FButtonDesign {} /// A pre-defined button variant. -enum FButtonVariant implements FButtonDesign { +enum FButtonVariant implements FButtonDesign { /// A primary-styled button. primary, @@ -140,40 +158,83 @@ enum FButtonVariant implements FButtonDesign { } /// Represents the theme data that is inherited by [FButtonStyle] and used by child [FButton]. -class FButtonStyle extends FButtonDesign with Diagnosticable{ - /// The content. - final FButtonContentStyle content; - +class FButtonStyle extends FButtonDesign with Diagnosticable { /// The box decoration for an enabled button. final BoxDecoration enabledBoxDecoration; /// The box decoration for a disabled button. final BoxDecoration disabledBoxDecoration; + /// The content. + final FButtonContentStyle content; + + /// The icon. + final FButtonIconStyle icon; + /// Creates a [FButtonStyle]. FButtonStyle({ - required this.content, required this.enabledBoxDecoration, required this.disabledBoxDecoration, + required this.content, + required this.icon, }); /// Creates a copy of this [FButtonStyle] with the given properties replaced. FButtonStyle copyWith({ - FButtonContentStyle? content, BoxDecoration? enabledBoxDecoration, BoxDecoration? disabledBoxDecoration, + FButtonContentStyle? content, + FButtonIconStyle? icon, }) => FButtonStyle( - content: content ?? this.content, enabledBoxDecoration: enabledBoxDecoration ?? this.enabledBoxDecoration, disabledBoxDecoration: disabledBoxDecoration ?? this.disabledBoxDecoration, + content: content ?? this.content, + icon: icon ?? this.icon, ); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties..add(DiagnosticsProperty('content', content)) + properties ..add(DiagnosticsProperty('enabledBoxDecoration', enabledBoxDecoration)) - ..add(DiagnosticsProperty('disabledBoxDecoration', disabledBoxDecoration)); + ..add(DiagnosticsProperty('disabledBoxDecoration', disabledBoxDecoration)) + ..add(DiagnosticsProperty('content', content)) + ..add(DiagnosticsProperty('icon', icon)); + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is FButtonStyle && + runtimeType == other.runtimeType && + enabledBoxDecoration == other.enabledBoxDecoration && + disabledBoxDecoration == other.disabledBoxDecoration && + content == other.content && + icon == other.icon; + + @override + int get hashCode => enabledBoxDecoration.hashCode ^ disabledBoxDecoration.hashCode ^ content.hashCode ^ icon.hashCode; +} + +typedef _Data = ({FButtonStyle style, bool enabled}); + +class _InheritedData extends InheritedWidget { + final _Data data; + + const _InheritedData({ + required this.data, + required super.child, + }); + + @override + bool updateShouldNotify(covariant _InheritedData old) => data != old.data; + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('style', data.style)) + ..add(FlagProperty('enabled', value: data.enabled, ifTrue: 'enabled')); } } diff --git a/forui/lib/src/widgets/button/button_content.dart b/forui/lib/src/widgets/button/button_content.dart index e1e0a53dc..9bc7668e3 100644 --- a/forui/lib/src/widgets/button/button_content.dart +++ b/forui/lib/src/widgets/button/button_content.dart @@ -1,51 +1,50 @@ part of 'button.dart'; -@internal final class FButtonContent extends StatelessWidget { - final FButtonStyle style; - final bool enabled; - final String? text; - final SvgAsset? icon; // TODO: We should allow for custom heading and trailing widgets. - final Widget? child; +@internal +final class FButtonContent extends StatelessWidget { + final Widget? prefixIcon; + final Widget? suffixIcon; + final Widget? label; + final String? labelText; const FButtonContent({ - required this.style, - this.enabled = true, - this.text, - this.icon, - this.child, + this.prefixIcon, + this.suffixIcon, + this.label, + this.labelText, super.key, }); @override Widget build(BuildContext context) { - final style = this.style.content; + final typography = context.theme.typography; + final (:style, :enabled) = FButton._of(context); + return Padding( - padding: style.padding, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (icon != null) ...[ - icon!( - height: 20, // TODO: Icon size should be configurable. - colorFilter: ColorFilter.mode(enabled ? style.enabledIcon : style.disabledIcon, BlendMode.srcIn), - ), - const SizedBox(width: 10) - ], - if (text != null) Flexible(child: Text(text!, style: enabled ? style.enabledText : style.disabledText)), - if (child != null) child! - ], - ), - ); + padding: style.content.padding, + child: DefaultTextStyle.merge( + style: enabled ? style.content.enabledText.scale(typography) : style.content.disabledText.scale(typography), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: separate([ + if (prefixIcon != null) prefixIcon!, + switch ((label, labelText)) { + (final Widget label, _) => label, + (_, final String label) => Text(label), + _ => const Placeholder(), + }, + if (suffixIcon != null) suffixIcon!, + ], by: [ + const SizedBox(width: 10), + ]), + ), + )); } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('style', style)) - ..add(FlagProperty('enabled', value: enabled, defaultValue: true)) - ..add(StringProperty('text', text)) - ..add(DiagnosticsProperty('icon', icon)); + properties.add(StringProperty('labelText', labelText)); } } @@ -57,12 +56,6 @@ class FButtonContentStyle with Diagnosticable { /// The [TextStyle] when this button is disabled. final TextStyle disabledText; - /// The icon's color when this button is enabled. - final Color enabledIcon; - - /// The icon's color when this button is disabled. - final Color disabledIcon; - /// The padding. final EdgeInsets padding; @@ -70,17 +63,18 @@ class FButtonContentStyle with Diagnosticable { FButtonContentStyle({ required this.enabledText, required this.disabledText, - required this.enabledIcon, - required this.disabledIcon, required this.padding, }); /// Creates a [FButtonContentStyle] that inherits its properties from the given [foreground] and [disabledForeground]. - FButtonContentStyle.inherit({required FTypography typography, required Color foreground, required Color disabledForeground}) - : padding = const EdgeInsets.symmetric( - horizontal: 16, - vertical: 12.5, - ), + FButtonContentStyle.inherit({ + required FTypography typography, + required Color foreground, + required Color disabledForeground, + }) : padding = const EdgeInsets.symmetric( + horizontal: 16, + vertical: 12.5, + ), enabledText = TextStyle( fontSize: typography.base, fontWeight: FontWeight.w500, @@ -90,9 +84,7 @@ class FButtonContentStyle with Diagnosticable { fontSize: typography.base, fontWeight: FontWeight.w500, color: disabledForeground, - ), - enabledIcon = foreground, - disabledIcon = disabledForeground; + ); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { @@ -100,8 +92,18 @@ class FButtonContentStyle with Diagnosticable { properties ..add(DiagnosticsProperty('enabledText', enabledText)) ..add(DiagnosticsProperty('disabledText', disabledText)) - ..add(DiagnosticsProperty('enabledIcon', enabledIcon)) - ..add(DiagnosticsProperty('disabledIcon', disabledIcon)) ..add(DiagnosticsProperty('padding', padding)); } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is FButtonContentStyle && + runtimeType == other.runtimeType && + enabledText == other.enabledText && + disabledText == other.disabledText && + padding == other.padding; + + @override + int get hashCode => enabledText.hashCode ^ disabledText.hashCode ^ padding.hashCode; } diff --git a/forui/lib/src/widgets/button/button_icon.dart b/forui/lib/src/widgets/button/button_icon.dart new file mode 100644 index 000000000..463a00dfe --- /dev/null +++ b/forui/lib/src/widgets/button/button_icon.dart @@ -0,0 +1,73 @@ +part of 'button.dart'; + +/// Represents an icon that is used in a [FButton]. +class FButtonIcon extends StatelessWidget { + /// The icon. + final SvgAsset icon; + + /// Creates a [FButtonIcon]. + const FButtonIcon({required this.icon, super.key}); + + @override + Widget build(BuildContext context) { + final (:style, :enabled) = FButton._of(context); + + return icon( + height: 20, + colorFilter: ColorFilter.mode(enabled ? style.icon.enabled : style.icon.disabled, BlendMode.srcIn), + ); + } + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('icon', icon)); + } +} + +/// [FButtonIcon]'s style. +final class FButtonIconStyle with Diagnosticable { + /// The icon's color when this button is enabled. + final Color enabled; + + /// The icon's color when this button is disabled. + final Color disabled; + + /// The icon's height. Defaults to 20. + final double height; + + /// Creates a [FButtonIconStyle]. + FButtonIconStyle({ + required this.enabled, + required this.disabled, + required this.height, + }); + + /// Creates a [FButtonIconStyle] that inherits its properties from the given [foreground] and [disabledForeground]. + FButtonIconStyle.inherit({ + required Color foreground, + required Color disabledForeground, + }) : enabled = foreground, + disabled = disabledForeground, + height = 20; + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(ColorProperty('enabled', enabled)) + ..add(ColorProperty('disabled', disabled)) + ..add(DoubleProperty('height', height)); + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is FButtonIconStyle && + runtimeType == other.runtimeType && + enabled == other.enabled && + disabled == other.disabled && + height == other.height; + + @override + int get hashCode => enabled.hashCode ^ disabled.hashCode ^ height.hashCode; +} diff --git a/forui/lib/src/widgets/button/button_styles.dart b/forui/lib/src/widgets/button/button_styles.dart index ebb569af0..c90303c3f 100644 --- a/forui/lib/src/widgets/button/button_styles.dart +++ b/forui/lib/src/widgets/button/button_styles.dart @@ -1,7 +1,7 @@ part of 'button.dart'; /// [FButtonStyle]'s style. -class FButtonStyles with Diagnosticable{ +class FButtonStyles with Diagnosticable { /// The primary style. final FButtonStyle primary; @@ -38,6 +38,10 @@ class FButtonStyles with Diagnosticable{ foreground: colorScheme.primaryForeground, disabledForeground: colorScheme.primaryForeground.withOpacity(0.5), ), + icon: FButtonIconStyle.inherit( + foreground: colorScheme.primaryForeground, + disabledForeground: colorScheme.primaryForeground.withOpacity(0.5), + ), ), secondary = FButtonStyle( enabledBoxDecoration: BoxDecoration( @@ -53,6 +57,10 @@ class FButtonStyles with Diagnosticable{ foreground: colorScheme.secondaryForeground, disabledForeground: colorScheme.secondaryForeground.withOpacity(0.5), ), + icon: FButtonIconStyle.inherit( + foreground: colorScheme.secondaryForeground, + disabledForeground: colorScheme.secondaryForeground.withOpacity(0.5), + ), ), destructive = FButtonStyle( enabledBoxDecoration: BoxDecoration( @@ -68,6 +76,10 @@ class FButtonStyles with Diagnosticable{ foreground: colorScheme.destructiveForeground, disabledForeground: colorScheme.destructiveForeground.withOpacity(0.5), ), + icon: FButtonIconStyle.inherit( + foreground: colorScheme.destructiveForeground, + disabledForeground: colorScheme.destructiveForeground.withOpacity(0.5), + ), ), outlined = FButtonStyle( enabledBoxDecoration: BoxDecoration( @@ -87,6 +99,10 @@ class FButtonStyles with Diagnosticable{ foreground: colorScheme.secondaryForeground, disabledForeground: colorScheme.secondaryForeground.withOpacity(0.5), ), + icon: FButtonIconStyle.inherit( + foreground: colorScheme.secondaryForeground, + disabledForeground: colorScheme.secondaryForeground.withOpacity(0.5), + ), ); @override @@ -98,4 +114,17 @@ class FButtonStyles with Diagnosticable{ ..add(DiagnosticsProperty('destructive', destructive)) ..add(DiagnosticsProperty('outlined', outlined)); } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is FButtonStyles && + runtimeType == other.runtimeType && + primary == other.primary && + secondary == other.secondary && + destructive == other.destructive && + outlined == other.outlined; + + @override + int get hashCode => primary.hashCode ^ secondary.hashCode ^ destructive.hashCode ^ outlined.hashCode; } diff --git a/forui/lib/src/widgets/card/card.dart b/forui/lib/src/widgets/card/card.dart index 667c8ee08..2fa0d6323 100644 --- a/forui/lib/src/widgets/card/card.dart +++ b/forui/lib/src/widgets/card/card.dart @@ -18,13 +18,20 @@ final class FCard extends StatelessWidget { /// Creates a [FCard] with a tile and subtitle. FCard({ String? title, + Widget? rawTitle, String? subtitle, + Widget? rawSubtitle, Widget? child, this.style, super.key, - }) : child = FCardContent( + }) : + assert(title == null || rawTitle == null, 'Cannot provide both a title and a rawTitle.'), + assert(subtitle == null || rawSubtitle == null, 'Cannot provide both a subtitle and a rawSubtitle.'), + child = FCardContent( title: title, + rawTitle: rawTitle, subtitle: subtitle, + rawSubtitle: rawSubtitle, style: style?.content, child: child, ); @@ -33,14 +40,10 @@ final class FCard extends StatelessWidget { const FCard.raw({required this.child, this.style, super.key}); @override - Widget build(BuildContext context) { - final style = this.style ?? context.theme.cardStyle; - - return DecoratedBox( - decoration: style.decoration, - child: child, - ); - } + Widget build(BuildContext context) => DecoratedBox( + decoration: (style ?? context.theme.cardStyle).decoration, + child: child, + ); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { diff --git a/forui/lib/src/widgets/card/card_content.dart b/forui/lib/src/widgets/card/card_content.dart index fd6367a27..fda26f712 100644 --- a/forui/lib/src/widgets/card/card_content.dart +++ b/forui/lib/src/widgets/card/card_content.dart @@ -2,23 +2,56 @@ part of 'card.dart'; @internal final class FCardContent extends StatelessWidget { final String? title; + final Widget? rawTitle; final String? subtitle; + final Widget? rawSubtitle; final Widget? child; final FCardContentStyle? style; - const FCardContent({this.title, this.subtitle, this.child, this.style, super.key}); + const FCardContent({ + this.title, + this.rawTitle, + this.subtitle, + this.rawSubtitle, + this.child, + this.style, + super.key, + }); @override Widget build(BuildContext context) { final typography = context.theme.typography; final style = this.style ?? context.theme.cardStyle.content; + + final title = switch ((this.title, rawTitle)) { + (final String title, _) => Text(title), + (_, final Widget title) => title, + _ => null, + }; + + final subtitle = switch ((this.subtitle, rawSubtitle)) { + (final String subtitle, _) => Text(subtitle), + (_, final Widget subtitle) => subtitle, + _ => null, + }; + return Padding( padding: style.padding, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (title != null) Text(title!, style: style.title.scale(typography)), - if (subtitle != null) Text(subtitle!, style: style.subtitle.scale(typography)), + if (title != null) + DefaultTextStyle.merge( + style: style.title.scale(typography), + child: title, + ), + + if (subtitle != null) + DefaultTextStyle.merge( + style: style.subtitle.scale(typography), + child: subtitle, + ), + if (child != null) Padding( padding: (title == null && subtitle == null) ? const EdgeInsets.only(top: 4) : const EdgeInsets.only(top: 10), diff --git a/forui/lib/src/widgets/dialog/dialog.dart b/forui/lib/src/widgets/dialog/dialog.dart index 41a90fde2..711199bf7 100644 --- a/forui/lib/src/widgets/dialog/dialog.dart +++ b/forui/lib/src/widgets/dialog/dialog.dart @@ -53,22 +53,30 @@ class FDialog extends StatelessWidget { this.insetAnimationCurve = Curves.decelerate, String? semanticLabel, String? title, - String? subtitle, + Widget? rawTitle, + String? body, + Widget? rawBody, FDialogAlignment alignment = FDialogAlignment.vertical, super.key, }): - semanticLabel = semanticLabel ?? title ?? subtitle, + assert(title == null || rawTitle == null, 'Cannot provide both a title and a rawTitle.'), + assert(body == null || rawBody == null, 'Cannot provide both a body and a rawBody.'), + semanticLabel = semanticLabel ?? title, builder = switch (alignment) { FDialogAlignment.horizontal => (context, style) => FHorizontalDialogContent( style: style.horizontal, title: title, - subtitle: subtitle, + rawTitle: rawTitle, + body: body, + rawBody: rawBody, actions: actions, ), FDialogAlignment.vertical => (context, style) => FVerticalDialogContent( style: style.vertical, title: title, - subtitle: subtitle, + rawTitle: rawTitle, + body: body, + rawBody: rawBody, actions: actions, ), }; @@ -100,7 +108,7 @@ class FDialog extends StatelessWidget { removeBottom: true, context: context, child: Align( - child: DefaultTextStyle( + child: DefaultTextStyle.merge( style: context.theme.typography.toTextStyle( fontSize: typography.base, color: context.theme.colorScheme.foreground, diff --git a/forui/lib/src/widgets/dialog/dialog_content.dart b/forui/lib/src/widgets/dialog/dialog_content.dart index 5c414fd13..f43be3562 100644 --- a/forui/lib/src/widgets/dialog/dialog_content.dart +++ b/forui/lib/src/widgets/dialog/dialog_content.dart @@ -5,24 +5,41 @@ part of 'dialog.dart'; final CrossAxisAlignment alignment; final String? title; final TextAlign titleTextAlign; - final String? subtitle; - final TextAlign subtitleTextAlign; + final Widget? rawTitle; + final String? body; + final TextAlign bodyTextAlign; + final Widget? rawBody; final List actions; const FDialogContent({ required this.style, - required this.alignment, - required this.titleTextAlign, - required this.subtitleTextAlign, - required this.actions, - this.title, - this.subtitle, + required this.alignment, + required this.title, + required this.titleTextAlign, + required this.rawTitle, + required this.body, + required this.bodyTextAlign, + required this.rawBody, + required this.actions, super.key, }); @override Widget build(BuildContext context) { final typography = context.theme.typography; + + final title = switch ((this.title, rawTitle)) { + (final String title, _) => Text(title), + (_, final Widget title) => title, + _ => null, + }; + + final body = switch ((this.body, rawBody)) { + (final String body, _) => Text(body), + (_, final Widget body) => body, + _ => null, + }; + return IntrinsicWidth( child: Padding( padding: style.padding, @@ -35,22 +52,22 @@ part of 'dialog.dart'; padding: const EdgeInsets.only(bottom: 12), child: Semantics( container: true, - child: Text( - title!, - style: style.title.scale(typography), + child: DefaultTextStyle.merge( textAlign: titleTextAlign, + style: style.title.scale(typography), + child: title, ), ), ), - if (subtitle != null) + if (body != null) Padding( padding: const EdgeInsets.only(bottom: 16), child: Semantics( container: true, - child: Text( - subtitle!, - style: style.subtitle.scale(typography), - textAlign: subtitleTextAlign, + child: DefaultTextStyle.merge( + textAlign: bodyTextAlign, + style: style.body.scale(typography), + child: body, ), ), ), @@ -71,8 +88,8 @@ part of 'dialog.dart'; ..add(DiagnosticsProperty('alignment', alignment)) ..add(StringProperty('title', title)) ..add(DiagnosticsProperty('titleTextAlign', titleTextAlign)) - ..add(StringProperty('subtitle', subtitle)) - ..add(DiagnosticsProperty('subtitleTextAlign', subtitleTextAlign)) + ..add(StringProperty('body', body)) + ..add(DiagnosticsProperty('bodyTextAlign', bodyTextAlign)) ..add(IterableProperty('actions', actions)); } } @@ -81,12 +98,14 @@ part of 'dialog.dart'; const FHorizontalDialogContent({ required super.style, required super.title, - required super.subtitle, + required super.rawTitle, + required super.body, + required super.rawBody, required super.actions, }): super( alignment: CrossAxisAlignment.start, titleTextAlign: TextAlign.start, - subtitleTextAlign: TextAlign.start + bodyTextAlign: TextAlign.start ); @override @@ -109,12 +128,14 @@ part of 'dialog.dart'; const FVerticalDialogContent({ required super.style, required super.title, - required super.subtitle, + required super.rawTitle, + required super.body, + required super.rawBody, required super.actions, }): super( alignment: CrossAxisAlignment.center, titleTextAlign: TextAlign.center, - subtitleTextAlign: TextAlign.center + bodyTextAlign: TextAlign.center ); @override @@ -135,8 +156,8 @@ final class FDialogContentStyle with Diagnosticable { /// The title style. final TextStyle title; - /// The subtitle style. - final TextStyle subtitle; + /// The body style. + final TextStyle body; /// The padding between actions. final double actionPadding; @@ -145,7 +166,7 @@ final class FDialogContentStyle with Diagnosticable { FDialogContentStyle({ required this.padding, required this.title, - required this.subtitle, + required this.body, required this.actionPadding, }); @@ -161,7 +182,7 @@ final class FDialogContentStyle with Diagnosticable { fontWeight: FontWeight.w600, color: colorScheme.foreground, ), - subtitle = TextStyle( + body = TextStyle( fontSize: typography.sm, color: colorScheme.mutedForeground, ); @@ -172,7 +193,7 @@ final class FDialogContentStyle with Diagnosticable { properties ..add(DiagnosticsProperty('padding', padding)) ..add(DiagnosticsProperty('title', title)) - ..add(DiagnosticsProperty('subtitle', subtitle)) + ..add(DiagnosticsProperty('subtitle', body)) ..add(DoubleProperty('actionPadding', actionPadding)); } } diff --git a/forui/lib/src/widgets/header/header.dart b/forui/lib/src/widgets/header/header.dart index 8f658de34..b1960784f 100644 --- a/forui/lib/src/widgets/header/header.dart +++ b/forui/lib/src/widgets/header/header.dart @@ -11,7 +11,10 @@ part 'header_action.dart'; /// Typically used on pages at the root of the navigation stack. final class FHeader extends StatelessWidget { /// The title displayed on the left side of the [FHeader]. - final String title; + final String? title; + + /// The title displayed on the left side of the [FHeader]. + final Widget? rawTitle; /// The actions displayed on the right side of the [FHeader]. final List actions; @@ -21,27 +24,35 @@ final class FHeader extends StatelessWidget { /// Creates a [FHeader]. const FHeader({ - required this.title, + this.title, + this.rawTitle, this.actions = const [], this.style, super.key, - }); + }): + assert((title != null) ^ (rawTitle != null), 'title or rawTitle must be provided, but not both.'); @override Widget build(BuildContext context) { final style = this.style ?? context.theme.headerStyle; final typography = context.theme.typography; + final title = switch ((this.title, rawTitle)) { + (final String title, _) => Text(title), + (_, final Widget title) => title, + _ => const Placeholder(), + }; + return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( - child: Text( - title, + child: DefaultTextStyle.merge( overflow: TextOverflow.fade, maxLines: 1, softWrap: false, style: style.title.scale(typography), + child: title, ), ), Row(children: actions), diff --git a/forui/lib/src/widgets/text_field/text_field.dart b/forui/lib/src/widgets/text_field/text_field.dart index 41aec15c1..11e26a31d 100644 --- a/forui/lib/src/widgets/text_field/text_field.dart +++ b/forui/lib/src/widgets/text_field/text_field.dart @@ -20,15 +20,18 @@ final class FTextField extends StatelessWidget { /// The style. final FTextFieldStyle? style; - /// The label text. - final String? labelText; + /// The label. + final String? label; + + /// The raw label. + final Widget? rawLabel; /// The text to display when the text field is empty. /// /// See [InputDecoration.hintText] for more information. - final String? hintText; + final String? hint; - /// The maximum number of lines the [hintText] can occupy. Defaults to the value of [TextField.maxLines] attribute. + /// The maximum number of lines the [hint] can occupy. Defaults to the value of [TextField.maxLines] attribute. /// /// See [InputDecoration.hintMaxLines] for more information. final int? hintMaxLines; @@ -36,9 +39,12 @@ final class FTextField extends StatelessWidget { /// The help text. /// /// See [InputDecoration.helperText] for more information. - final String? helpText; + final String? help; + + /// The raw help text. + final Widget? rawHelp; - /// The maximum number of lines the [helpText] can occupy. Defaults to the value of [TextField.maxLines] attribute. + /// The maximum number of lines the [help] can occupy. Defaults to the value of [TextField.maxLines] attribute. /// /// See [InputDecoration.helperMaxLines] for more information. final int? helpMaxLines; @@ -46,9 +52,12 @@ final class FTextField extends StatelessWidget { /// The error text. /// /// See [InputDecoration.errorText] for more information. - final String? errorText; + final String? error; + + /// The raw error text. + final Widget? rawError; - /// The maximum number of lines the [errorText] can occupy. Defaults to the value of [TextField.maxLines] attribute. + /// The maximum number of lines the [error] can occupy. Defaults to the value of [TextField.maxLines] attribute. /// /// See [InputDecoration.errorMaxLines] for more information. final int? errorMaxLines; @@ -456,12 +465,15 @@ final class FTextField extends StatelessWidget { /// Creates a [FTextField]. const FTextField({ this.style, - this.labelText, - this.hintText, + this.label, + this.rawLabel, + this.hint, this.hintMaxLines, - this.helpText, + this.help, + this.rawHelp, this.helpMaxLines, - this.errorText, + this.error, + this.rawError, this.errorMaxLines, this.magnifierConfiguration, this.controller, @@ -507,17 +519,23 @@ final class FTextField extends StatelessWidget { this.undoController, this.spellCheckConfiguration, this.suffixIcon, - }); + }): + assert(label == null || rawLabel == null, 'Cannot provide both a label and a rawLabel.'), + assert(help == null || rawHelp == null, 'Cannot provide both a help and a rawHelp.'), + assert(error == null || rawError == null, 'Cannot provide both an error and a rawError.'); /// Creates a [FTextField] configured for emails. const FTextField.email({ this.style, - this.labelText, - this.hintText = 'Email', + this.label, + this.rawLabel, + this.hint = 'Email', this.hintMaxLines, - this.helpText, + this.help, + this.rawHelp, this.helpMaxLines, - this.errorText, + this.error, + this.rawError, this.errorMaxLines, this.magnifierConfiguration, this.controller, @@ -563,7 +581,10 @@ final class FTextField extends StatelessWidget { this.undoController, this.spellCheckConfiguration, this.suffixIcon, - }); + }): + assert(label == null || rawLabel == null, 'Cannot provide both a label and a rawLabel.'), + assert(help == null || rawHelp == null, 'Cannot provide both a help and a rawHelp.'), + assert(error == null || rawError == null, 'Cannot provide both an error and a rawError.'); /// Creates a [FTextField] configured for passwords. /// @@ -571,12 +592,15 @@ final class FTextField extends StatelessWidget { /// when handling the creation of new passwords. const FTextField.password({ this.style, - this.labelText, - this.hintText = 'Password', + this.label, + this.rawLabel, + this.hint = 'Password', this.hintMaxLines, - this.helpText, + this.help, + this.rawHelp, this.helpMaxLines, - this.errorText, + this.error, + this.rawError, this.errorMaxLines, this.magnifierConfiguration, this.controller, @@ -622,17 +646,23 @@ final class FTextField extends StatelessWidget { this.undoController, this.spellCheckConfiguration, this.suffixIcon, - }); + }): + assert(label == null || rawLabel == null, 'Cannot provide both a label and a rawLabel.'), + assert(help == null || rawHelp == null, 'Cannot provide both a help and a rawHelp.'), + assert(error == null || rawError == null, 'Cannot provide both an error and a rawError.'); /// Creates a [FTextField] configured for multiline inputs. const FTextField.multiline({ this.style, - this.labelText, - this.hintText, + this.label, + this.rawLabel, + this.hint, this.hintMaxLines, - this.helpText, + this.help, + this.rawHelp, this.helpMaxLines, - this.errorText, + this.error, + this.rawError, this.errorMaxLines, this.magnifierConfiguration, this.controller, @@ -678,7 +708,10 @@ final class FTextField extends StatelessWidget { this.undoController, this.spellCheckConfiguration, this.suffixIcon, - }); + }): + assert(label == null || rawLabel == null, 'Cannot provide both a label and a rawLabel.'), + assert(help == null || rawHelp == null, 'Cannot provide both a help and a rawHelp.'), + assert(error == null || rawError == null, 'Cannot provide both an error and a rawError.'); @override Widget build(BuildContext context) { @@ -687,21 +720,27 @@ final class FTextField extends StatelessWidget { final style = this.style ?? theme.textFieldStyle; final stateStyle = switch (this) { _ when !enabled => style.disabled, - _ when errorText != null => style.error, + _ when error != null || rawError != null => style.error, _ => style.enabled, }; final materialLocalizations = Localizations.of(context, MaterialLocalizations); + final label = switch ((this.label, rawLabel)) { + (final String label, _) => Text(label), + (_, final Widget label) => label, + _ => null, + }; + final textField = MergeSemantics( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (labelText != null) + if (label != null) Padding( padding: const EdgeInsets.only(top: 4, bottom: 7), - child: Text( - labelText!, - style: stateStyle.label, + child: DefaultTextStyle.merge( + style: stateStyle.label.scale(typography), + child: label, ), ), Material( @@ -744,116 +783,131 @@ final class FTextField extends StatelessWidget { FTypography typography, FTextFieldStyle style, FTextFieldStateStyle current, - ) => TextField( - controller: controller, - focusNode: focusNode, - undoController: undoController, - cursorErrorColor: style.cursor, - decoration: InputDecoration( - suffixIcon: suffixIcon, - // See https://stackoverflow.com/questions/70771410/flutter-how-can-i-remove-the-content-padding-for-error-in-textformfield - prefix: Padding(padding: EdgeInsets.only(left: style.contentPadding.left)), - contentPadding: style.contentPadding.copyWith(left: 0), - hintText: hintText, - hintStyle: current.hint.scale(typography), - hintMaxLines: hintMaxLines, - helperText: helpText, - helperStyle: current.footer.scale(typography), - helperMaxLines: helpMaxLines, - errorText: errorText, - errorStyle: current.footer.scale(typography), - errorMaxLines: errorMaxLines, - disabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: style.disabled.unfocused.color, - width: style.disabled.unfocused.width, + ) { + + final rawError = this.rawError == null ? this.rawError : DefaultTextStyle.merge( + style: current.footer.scale(typography), + child: this.rawError!, + ); + + final rawHelp = this.rawHelp == null ? this.rawHelp : DefaultTextStyle.merge( + style: current.footer.scale(typography), + child: this.rawHelp!, + ); + + return TextField( + controller: controller, + focusNode: focusNode, + undoController: undoController, + cursorErrorColor: style.cursor, + decoration: InputDecoration( + suffixIcon: suffixIcon, + // See https://stackoverflow.com/questions/70771410/flutter-how-can-i-remove-the-content-padding-for-error-in-textformfield + prefix: Padding(padding: EdgeInsets.only(left: style.contentPadding.left)), + contentPadding: style.contentPadding.copyWith(left: 0), + hintText: hint, + hintStyle: current.hint.scale(typography), + hintMaxLines: hintMaxLines, + helper: rawHelp, + helperText: help, + helperStyle: current.footer.scale(typography), + helperMaxLines: helpMaxLines, + error: rawError, + errorText: error, + errorStyle: current.footer.scale(typography), + errorMaxLines: errorMaxLines, + disabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: style.disabled.unfocused.color, + width: style.disabled.unfocused.width, + ), + borderRadius: style.disabled.unfocused.radius, ), - borderRadius: style.disabled.unfocused.radius, - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: style.enabled.unfocused.color, - width: style.enabled.unfocused.width, + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: style.enabled.unfocused.color, + width: style.enabled.unfocused.width, + ), + borderRadius: style.enabled.unfocused.radius, ), - borderRadius: style.enabled.unfocused.radius, - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: style.enabled.focused.color, - width: style.enabled.focused.width, + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: style.enabled.focused.color, + width: style.enabled.focused.width, + ), + borderRadius: current.focused.radius, ), - borderRadius: current.focused.radius, - ), - errorBorder: OutlineInputBorder( - borderSide: BorderSide( - color: style.error.unfocused.color, - width: style.error.unfocused.width, + errorBorder: OutlineInputBorder( + borderSide: BorderSide( + color: style.error.unfocused.color, + width: style.error.unfocused.width, + ), + borderRadius: style.error.unfocused.radius, ), - borderRadius: style.error.unfocused.radius, - ), - focusedErrorBorder: OutlineInputBorder( - borderSide: BorderSide( - color: style.error.focused.color, - width: style.error.focused.width, + focusedErrorBorder: OutlineInputBorder( + borderSide: BorderSide( + color: style.error.focused.color, + width: style.error.focused.width, + ), + borderRadius: style.error.focused.radius, ), - borderRadius: style.error.focused.radius, ), - ), - keyboardType: keyboardType, - textInputAction: textInputAction, - textCapitalization: textCapitalization, - style: current.content.scale(typography), - textAlign: textAlign, - textAlignVertical: textAlignVertical, - textDirection: textDirection, - readOnly: readOnly, - showCursor: showCursor, - autofocus: autofocus, - statesController: statesController, - obscureText: obscureText, - autocorrect: autocorrect, - smartDashesType: smartDashesType, - smartQuotesType: smartQuotesType, - enableSuggestions: enableSuggestions, - maxLines: maxLines, - minLines: minLines, - expands: expands, - maxLength: maxLength, - maxLengthEnforcement: maxLengthEnforcement, - onChanged: onChange, - onEditingComplete: onEditingComplete, - onSubmitted: onSubmit, - onAppPrivateCommand: onAppPrivateCommand, - inputFormatters: inputFormatters, - enabled: enabled, - ignorePointers: ignorePointers, - keyboardAppearance: style.keyboardAppearance, - scrollPadding: style.scrollPadding, - dragStartBehavior: dragStartBehavior, - selectionControls: selectionControls, - scrollController: scrollController, - scrollPhysics: scrollPhysics, - autofillHints: autofillHints, - restorationId: restorationId, - scribbleEnabled: scribbleEnabled, - enableIMEPersonalizedLearning: enableIMEPersonalizedLearning, - contextMenuBuilder: contextMenuBuilder, - canRequestFocus: canRequestFocus, - spellCheckConfiguration: spellCheckConfiguration, - magnifierConfiguration: magnifierConfiguration, - ); + keyboardType: keyboardType, + textInputAction: textInputAction, + textCapitalization: textCapitalization, + style: current.content.scale(typography), + textAlign: textAlign, + textAlignVertical: textAlignVertical, + textDirection: textDirection, + readOnly: readOnly, + showCursor: showCursor, + autofocus: autofocus, + statesController: statesController, + obscureText: obscureText, + autocorrect: autocorrect, + smartDashesType: smartDashesType, + smartQuotesType: smartQuotesType, + enableSuggestions: enableSuggestions, + maxLines: maxLines, + minLines: minLines, + expands: expands, + maxLength: maxLength, + maxLengthEnforcement: maxLengthEnforcement, + onChanged: onChange, + onEditingComplete: onEditingComplete, + onSubmitted: onSubmit, + onAppPrivateCommand: onAppPrivateCommand, + inputFormatters: inputFormatters, + enabled: enabled, + ignorePointers: ignorePointers, + keyboardAppearance: style.keyboardAppearance, + scrollPadding: style.scrollPadding, + dragStartBehavior: dragStartBehavior, + selectionControls: selectionControls, + scrollController: scrollController, + scrollPhysics: scrollPhysics, + autofillHints: autofillHints, + restorationId: restorationId, + scribbleEnabled: scribbleEnabled, + enableIMEPersonalizedLearning: enableIMEPersonalizedLearning, + contextMenuBuilder: contextMenuBuilder, + canRequestFocus: canRequestFocus, + spellCheckConfiguration: spellCheckConfiguration, + magnifierConfiguration: magnifierConfiguration, + ); + } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties ..add(DiagnosticsProperty('style', style)) - ..add(StringProperty('labelText', labelText)) - ..add(StringProperty('hintText', hintText)) + ..add(StringProperty('label', label)) + ..add(StringProperty('hint', hint)) ..add(IntProperty('hintMaxLines', hintMaxLines)) - ..add(StringProperty('helpText', helpText)) + ..add(StringProperty('help', help)) ..add(IntProperty('helpMaxLines', helpMaxLines)) - ..add(StringProperty('errorText', errorText)) + ..add(StringProperty('error', error)) ..add(IntProperty('errorMaxLines', errorMaxLines)) ..add(DiagnosticsProperty('magnifierConfiguration', magnifierConfiguration)) ..add(DiagnosticsProperty('controller', controller)) diff --git a/forui/test/golden/badge/zinc-dark-FBadgeVariant.destructive-raw-badge-content.png b/forui/test/golden/badge/zinc-dark-FBadgeVariant.destructive-raw-badge-content.png new file mode 100644 index 000000000..862d5f4fc Binary files /dev/null and b/forui/test/golden/badge/zinc-dark-FBadgeVariant.destructive-raw-badge-content.png differ diff --git a/forui/test/golden/badge/zinc-dark-FBadgeVariant.destructive-text-badge-content.png b/forui/test/golden/badge/zinc-dark-FBadgeVariant.destructive-text-badge-content.png new file mode 100644 index 000000000..862d5f4fc Binary files /dev/null and b/forui/test/golden/badge/zinc-dark-FBadgeVariant.destructive-text-badge-content.png differ diff --git a/forui/test/golden/badge/zinc-dark-FBadgeVariant.outline-badge-content.png b/forui/test/golden/badge/zinc-dark-FBadgeVariant.outline-badge-content.png deleted file mode 100644 index aacd07743..000000000 Binary files a/forui/test/golden/badge/zinc-dark-FBadgeVariant.outline-badge-content.png and /dev/null differ diff --git a/forui/test/golden/badge/zinc-dark-FBadgeVariant.outline-raw-badge-content.png b/forui/test/golden/badge/zinc-dark-FBadgeVariant.outline-raw-badge-content.png new file mode 100644 index 000000000..4ad642ac3 Binary files /dev/null and b/forui/test/golden/badge/zinc-dark-FBadgeVariant.outline-raw-badge-content.png differ diff --git a/forui/test/golden/badge/zinc-dark-FBadgeVariant.outline-text-badge-content.png b/forui/test/golden/badge/zinc-dark-FBadgeVariant.outline-text-badge-content.png new file mode 100644 index 000000000..4ad642ac3 Binary files /dev/null and b/forui/test/golden/badge/zinc-dark-FBadgeVariant.outline-text-badge-content.png differ diff --git a/forui/test/golden/badge/zinc-dark-FBadgeVariant.secondary-badge-content.png b/forui/test/golden/badge/zinc-dark-FBadgeVariant.primary-raw-badge-content.png similarity index 60% rename from forui/test/golden/badge/zinc-dark-FBadgeVariant.secondary-badge-content.png rename to forui/test/golden/badge/zinc-dark-FBadgeVariant.primary-raw-badge-content.png index 77c4e4ded..d23304fa8 100644 Binary files a/forui/test/golden/badge/zinc-dark-FBadgeVariant.secondary-badge-content.png and b/forui/test/golden/badge/zinc-dark-FBadgeVariant.primary-raw-badge-content.png differ diff --git a/forui/test/golden/badge/zinc-dark-FBadgeVariant.destructive-badge-content.png b/forui/test/golden/badge/zinc-dark-FBadgeVariant.primary-text-badge-content.png similarity index 60% rename from forui/test/golden/badge/zinc-dark-FBadgeVariant.destructive-badge-content.png rename to forui/test/golden/badge/zinc-dark-FBadgeVariant.primary-text-badge-content.png index bc2c91154..d23304fa8 100644 Binary files a/forui/test/golden/badge/zinc-dark-FBadgeVariant.destructive-badge-content.png and b/forui/test/golden/badge/zinc-dark-FBadgeVariant.primary-text-badge-content.png differ diff --git a/forui/test/golden/badge/zinc-dark-FBadgeVariant.secondary-raw-badge-content.png b/forui/test/golden/badge/zinc-dark-FBadgeVariant.secondary-raw-badge-content.png new file mode 100644 index 000000000..ab2c1677b Binary files /dev/null and b/forui/test/golden/badge/zinc-dark-FBadgeVariant.secondary-raw-badge-content.png differ diff --git a/forui/test/golden/badge/zinc-dark-FBadgeVariant.secondary-text-badge-content.png b/forui/test/golden/badge/zinc-dark-FBadgeVariant.secondary-text-badge-content.png new file mode 100644 index 000000000..ab2c1677b Binary files /dev/null and b/forui/test/golden/badge/zinc-dark-FBadgeVariant.secondary-text-badge-content.png differ diff --git a/forui/test/golden/badge/zinc-light-FBadgeVariant.destructive-raw-badge-content.png b/forui/test/golden/badge/zinc-light-FBadgeVariant.destructive-raw-badge-content.png new file mode 100644 index 000000000..320bda7eb Binary files /dev/null and b/forui/test/golden/badge/zinc-light-FBadgeVariant.destructive-raw-badge-content.png differ diff --git a/forui/test/golden/badge/zinc-light-FBadgeVariant.destructive-text-badge-content.png b/forui/test/golden/badge/zinc-light-FBadgeVariant.destructive-text-badge-content.png new file mode 100644 index 000000000..320bda7eb Binary files /dev/null and b/forui/test/golden/badge/zinc-light-FBadgeVariant.destructive-text-badge-content.png differ diff --git a/forui/test/golden/badge/zinc-light-FBadgeVariant.outline-raw-badge-content.png b/forui/test/golden/badge/zinc-light-FBadgeVariant.outline-raw-badge-content.png new file mode 100644 index 000000000..152c49ec0 Binary files /dev/null and b/forui/test/golden/badge/zinc-light-FBadgeVariant.outline-raw-badge-content.png differ diff --git a/forui/test/golden/badge/zinc-light-FBadgeVariant.outline-text-badge-content.png b/forui/test/golden/badge/zinc-light-FBadgeVariant.outline-text-badge-content.png new file mode 100644 index 000000000..152c49ec0 Binary files /dev/null and b/forui/test/golden/badge/zinc-light-FBadgeVariant.outline-text-badge-content.png differ diff --git a/forui/test/golden/badge/zinc-light-FBadgeVariant.primary-badge-content.png b/forui/test/golden/badge/zinc-light-FBadgeVariant.primary-badge-content.png deleted file mode 100644 index 230f42a61..000000000 Binary files a/forui/test/golden/badge/zinc-light-FBadgeVariant.primary-badge-content.png and /dev/null differ diff --git a/forui/test/golden/badge/zinc-light-FBadgeVariant.outline-badge-content.png b/forui/test/golden/badge/zinc-light-FBadgeVariant.primary-raw-badge-content.png similarity index 59% rename from forui/test/golden/badge/zinc-light-FBadgeVariant.outline-badge-content.png rename to forui/test/golden/badge/zinc-light-FBadgeVariant.primary-raw-badge-content.png index 696220b21..f3162779e 100644 Binary files a/forui/test/golden/badge/zinc-light-FBadgeVariant.outline-badge-content.png and b/forui/test/golden/badge/zinc-light-FBadgeVariant.primary-raw-badge-content.png differ diff --git a/forui/test/golden/badge/zinc-dark-FBadgeVariant.primary-badge-content.png b/forui/test/golden/badge/zinc-light-FBadgeVariant.primary-text-badge-content.png similarity index 53% rename from forui/test/golden/badge/zinc-dark-FBadgeVariant.primary-badge-content.png rename to forui/test/golden/badge/zinc-light-FBadgeVariant.primary-text-badge-content.png index 6a028ed14..f3162779e 100644 Binary files a/forui/test/golden/badge/zinc-dark-FBadgeVariant.primary-badge-content.png and b/forui/test/golden/badge/zinc-light-FBadgeVariant.primary-text-badge-content.png differ diff --git a/forui/test/golden/badge/zinc-light-FBadgeVariant.destructive-badge-content.png b/forui/test/golden/badge/zinc-light-FBadgeVariant.secondary-raw-badge-content.png similarity index 70% rename from forui/test/golden/badge/zinc-light-FBadgeVariant.destructive-badge-content.png rename to forui/test/golden/badge/zinc-light-FBadgeVariant.secondary-raw-badge-content.png index b958e13b0..7477e6029 100644 Binary files a/forui/test/golden/badge/zinc-light-FBadgeVariant.destructive-badge-content.png and b/forui/test/golden/badge/zinc-light-FBadgeVariant.secondary-raw-badge-content.png differ diff --git a/forui/test/golden/badge/zinc-light-FBadgeVariant.secondary-badge-content.png b/forui/test/golden/badge/zinc-light-FBadgeVariant.secondary-text-badge-content.png similarity index 60% rename from forui/test/golden/badge/zinc-light-FBadgeVariant.secondary-badge-content.png rename to forui/test/golden/badge/zinc-light-FBadgeVariant.secondary-text-badge-content.png index 7666439f5..7477e6029 100644 Binary files a/forui/test/golden/badge/zinc-light-FBadgeVariant.secondary-badge-content.png and b/forui/test/golden/badge/zinc-light-FBadgeVariant.secondary-text-badge-content.png differ diff --git a/forui/test/golden/button/zinc-dark-FButtonVariant.destructive-disabled-button-content.png b/forui/test/golden/button/zinc-dark-FButtonVariant.destructive-disabled-button-content.png index 432aeca15..2dbb03e6d 100644 Binary files a/forui/test/golden/button/zinc-dark-FButtonVariant.destructive-disabled-button-content.png and b/forui/test/golden/button/zinc-dark-FButtonVariant.destructive-disabled-button-content.png differ diff --git a/forui/test/golden/button/zinc-dark-FButtonVariant.destructive-enabled-button-content.png b/forui/test/golden/button/zinc-dark-FButtonVariant.destructive-enabled-button-content.png index eaa48f079..46daf75eb 100644 Binary files a/forui/test/golden/button/zinc-dark-FButtonVariant.destructive-enabled-button-content.png and b/forui/test/golden/button/zinc-dark-FButtonVariant.destructive-enabled-button-content.png differ diff --git a/forui/test/golden/button/zinc-dark-FButtonVariant.outlined-disabled-button-content.png b/forui/test/golden/button/zinc-dark-FButtonVariant.outlined-disabled-button-content.png index fe909754f..1d244d672 100644 Binary files a/forui/test/golden/button/zinc-dark-FButtonVariant.outlined-disabled-button-content.png and b/forui/test/golden/button/zinc-dark-FButtonVariant.outlined-disabled-button-content.png differ diff --git a/forui/test/golden/button/zinc-dark-FButtonVariant.outlined-enabled-button-content.png b/forui/test/golden/button/zinc-dark-FButtonVariant.outlined-enabled-button-content.png index 79f9cf47e..eb9221b23 100644 Binary files a/forui/test/golden/button/zinc-dark-FButtonVariant.outlined-enabled-button-content.png and b/forui/test/golden/button/zinc-dark-FButtonVariant.outlined-enabled-button-content.png differ diff --git a/forui/test/golden/button/zinc-dark-FButtonVariant.primary-disabled-button-content.png b/forui/test/golden/button/zinc-dark-FButtonVariant.primary-disabled-button-content.png index b70667a87..fa0f554af 100644 Binary files a/forui/test/golden/button/zinc-dark-FButtonVariant.primary-disabled-button-content.png and b/forui/test/golden/button/zinc-dark-FButtonVariant.primary-disabled-button-content.png differ diff --git a/forui/test/golden/button/zinc-dark-FButtonVariant.primary-enabled-button-content.png b/forui/test/golden/button/zinc-dark-FButtonVariant.primary-enabled-button-content.png index 06a33b2e8..7e3e7f7b0 100644 Binary files a/forui/test/golden/button/zinc-dark-FButtonVariant.primary-enabled-button-content.png and b/forui/test/golden/button/zinc-dark-FButtonVariant.primary-enabled-button-content.png differ diff --git a/forui/test/golden/button/zinc-dark-FButtonVariant.secondary-disabled-button-content.png b/forui/test/golden/button/zinc-dark-FButtonVariant.secondary-disabled-button-content.png index 0825a617c..721d21df0 100644 Binary files a/forui/test/golden/button/zinc-dark-FButtonVariant.secondary-disabled-button-content.png and b/forui/test/golden/button/zinc-dark-FButtonVariant.secondary-disabled-button-content.png differ diff --git a/forui/test/golden/button/zinc-dark-FButtonVariant.secondary-enabled-button-content.png b/forui/test/golden/button/zinc-dark-FButtonVariant.secondary-enabled-button-content.png index adfc0ad22..df13b4775 100644 Binary files a/forui/test/golden/button/zinc-dark-FButtonVariant.secondary-enabled-button-content.png and b/forui/test/golden/button/zinc-dark-FButtonVariant.secondary-enabled-button-content.png differ diff --git a/forui/test/golden/button/zinc-light-FButtonVariant.destructive-disabled-button-content.png b/forui/test/golden/button/zinc-light-FButtonVariant.destructive-disabled-button-content.png index 840b577b5..811f86e4d 100644 Binary files a/forui/test/golden/button/zinc-light-FButtonVariant.destructive-disabled-button-content.png and b/forui/test/golden/button/zinc-light-FButtonVariant.destructive-disabled-button-content.png differ diff --git a/forui/test/golden/button/zinc-light-FButtonVariant.destructive-enabled-button-content.png b/forui/test/golden/button/zinc-light-FButtonVariant.destructive-enabled-button-content.png index b66c6538d..2113bd3dc 100644 Binary files a/forui/test/golden/button/zinc-light-FButtonVariant.destructive-enabled-button-content.png and b/forui/test/golden/button/zinc-light-FButtonVariant.destructive-enabled-button-content.png differ diff --git a/forui/test/golden/button/zinc-light-FButtonVariant.outlined-disabled-button-content.png b/forui/test/golden/button/zinc-light-FButtonVariant.outlined-disabled-button-content.png index fd1952417..74f73bdeb 100644 Binary files a/forui/test/golden/button/zinc-light-FButtonVariant.outlined-disabled-button-content.png and b/forui/test/golden/button/zinc-light-FButtonVariant.outlined-disabled-button-content.png differ diff --git a/forui/test/golden/button/zinc-light-FButtonVariant.outlined-enabled-button-content.png b/forui/test/golden/button/zinc-light-FButtonVariant.outlined-enabled-button-content.png index ca35538c1..5db85d579 100644 Binary files a/forui/test/golden/button/zinc-light-FButtonVariant.outlined-enabled-button-content.png and b/forui/test/golden/button/zinc-light-FButtonVariant.outlined-enabled-button-content.png differ diff --git a/forui/test/golden/button/zinc-light-FButtonVariant.primary-disabled-button-content.png b/forui/test/golden/button/zinc-light-FButtonVariant.primary-disabled-button-content.png index cbec8e3bc..8ff1fdef2 100644 Binary files a/forui/test/golden/button/zinc-light-FButtonVariant.primary-disabled-button-content.png and b/forui/test/golden/button/zinc-light-FButtonVariant.primary-disabled-button-content.png differ diff --git a/forui/test/golden/button/zinc-light-FButtonVariant.primary-enabled-button-content.png b/forui/test/golden/button/zinc-light-FButtonVariant.primary-enabled-button-content.png index a43c0d411..6cd3e1746 100644 Binary files a/forui/test/golden/button/zinc-light-FButtonVariant.primary-enabled-button-content.png and b/forui/test/golden/button/zinc-light-FButtonVariant.primary-enabled-button-content.png differ diff --git a/forui/test/golden/button/zinc-light-FButtonVariant.secondary-disabled-button-content.png b/forui/test/golden/button/zinc-light-FButtonVariant.secondary-disabled-button-content.png index 709553b89..eddd1aac9 100644 Binary files a/forui/test/golden/button/zinc-light-FButtonVariant.secondary-disabled-button-content.png and b/forui/test/golden/button/zinc-light-FButtonVariant.secondary-disabled-button-content.png differ diff --git a/forui/test/golden/button/zinc-light-FButtonVariant.secondary-enabled-button-content.png b/forui/test/golden/button/zinc-light-FButtonVariant.secondary-enabled-button-content.png index e89e8c002..3c4f00355 100644 Binary files a/forui/test/golden/button/zinc-light-FButtonVariant.secondary-enabled-button-content.png and b/forui/test/golden/button/zinc-light-FButtonVariant.secondary-enabled-button-content.png differ diff --git a/forui/test/golden/card/zinc-dark-card-content.png b/forui/test/golden/card/zinc-dark-card-content.png deleted file mode 100644 index 97d806e1f..000000000 Binary files a/forui/test/golden/card/zinc-dark-card-content.png and /dev/null differ diff --git a/forui/test/golden/card/zinc-dark-raw-card-content.png b/forui/test/golden/card/zinc-dark-raw-card-content.png new file mode 100644 index 000000000..386dc5ef3 Binary files /dev/null and b/forui/test/golden/card/zinc-dark-raw-card-content.png differ diff --git a/forui/test/golden/card/zinc-dark-text-card-content.png b/forui/test/golden/card/zinc-dark-text-card-content.png new file mode 100644 index 000000000..386dc5ef3 Binary files /dev/null and b/forui/test/golden/card/zinc-dark-text-card-content.png differ diff --git a/forui/test/golden/card/zinc-light-card-content.png b/forui/test/golden/card/zinc-light-card-content.png deleted file mode 100644 index bb4d7c075..000000000 Binary files a/forui/test/golden/card/zinc-light-card-content.png and /dev/null differ diff --git a/forui/test/golden/card/zinc-light-raw-card-content.png b/forui/test/golden/card/zinc-light-raw-card-content.png new file mode 100644 index 000000000..7feb996ed Binary files /dev/null and b/forui/test/golden/card/zinc-light-raw-card-content.png differ diff --git a/forui/test/golden/card/zinc-light-text-card-content.png b/forui/test/golden/card/zinc-light-text-card-content.png new file mode 100644 index 000000000..7feb996ed Binary files /dev/null and b/forui/test/golden/card/zinc-light-text-card-content.png differ diff --git a/forui/test/golden/dialog/zinc-dark-FDialogAlignment.horizontal-content.png b/forui/test/golden/dialog/zinc-dark-FDialogAlignment.horizontal-content.png deleted file mode 100644 index 481d1cad9..000000000 Binary files a/forui/test/golden/dialog/zinc-dark-FDialogAlignment.horizontal-content.png and /dev/null differ diff --git a/forui/test/golden/dialog/zinc-dark-FDialogAlignment.horizontal-raw-dialog-content.png b/forui/test/golden/dialog/zinc-dark-FDialogAlignment.horizontal-raw-dialog-content.png new file mode 100644 index 000000000..6e0bac4d3 Binary files /dev/null and b/forui/test/golden/dialog/zinc-dark-FDialogAlignment.horizontal-raw-dialog-content.png differ diff --git a/forui/test/golden/dialog/zinc-dark-FDialogAlignment.horizontal-text-dialog-content.png b/forui/test/golden/dialog/zinc-dark-FDialogAlignment.horizontal-text-dialog-content.png new file mode 100644 index 000000000..6e0bac4d3 Binary files /dev/null and b/forui/test/golden/dialog/zinc-dark-FDialogAlignment.horizontal-text-dialog-content.png differ diff --git a/forui/test/golden/dialog/zinc-dark-FDialogAlignment.vertical-content.png b/forui/test/golden/dialog/zinc-dark-FDialogAlignment.vertical-content.png deleted file mode 100644 index 3ca875fad..000000000 Binary files a/forui/test/golden/dialog/zinc-dark-FDialogAlignment.vertical-content.png and /dev/null differ diff --git a/forui/test/golden/dialog/zinc-dark-FDialogAlignment.vertical-raw-dialog-content.png b/forui/test/golden/dialog/zinc-dark-FDialogAlignment.vertical-raw-dialog-content.png new file mode 100644 index 000000000..f0150b091 Binary files /dev/null and b/forui/test/golden/dialog/zinc-dark-FDialogAlignment.vertical-raw-dialog-content.png differ diff --git a/forui/test/golden/dialog/zinc-dark-FDialogAlignment.vertical-text-dialog-content.png b/forui/test/golden/dialog/zinc-dark-FDialogAlignment.vertical-text-dialog-content.png new file mode 100644 index 000000000..f0150b091 Binary files /dev/null and b/forui/test/golden/dialog/zinc-dark-FDialogAlignment.vertical-text-dialog-content.png differ diff --git a/forui/test/golden/dialog/zinc-light-FDialogAlignment.horizontal-content.png b/forui/test/golden/dialog/zinc-light-FDialogAlignment.horizontal-content.png deleted file mode 100644 index 76fa99cbe..000000000 Binary files a/forui/test/golden/dialog/zinc-light-FDialogAlignment.horizontal-content.png and /dev/null differ diff --git a/forui/test/golden/dialog/zinc-light-FDialogAlignment.horizontal-raw-dialog-content.png b/forui/test/golden/dialog/zinc-light-FDialogAlignment.horizontal-raw-dialog-content.png new file mode 100644 index 000000000..ba9a0b1f9 Binary files /dev/null and b/forui/test/golden/dialog/zinc-light-FDialogAlignment.horizontal-raw-dialog-content.png differ diff --git a/forui/test/golden/dialog/zinc-light-FDialogAlignment.horizontal-text-dialog-content.png b/forui/test/golden/dialog/zinc-light-FDialogAlignment.horizontal-text-dialog-content.png new file mode 100644 index 000000000..ba9a0b1f9 Binary files /dev/null and b/forui/test/golden/dialog/zinc-light-FDialogAlignment.horizontal-text-dialog-content.png differ diff --git a/forui/test/golden/dialog/zinc-light-FDialogAlignment.vertical-content.png b/forui/test/golden/dialog/zinc-light-FDialogAlignment.vertical-content.png deleted file mode 100644 index 0bc62d568..000000000 Binary files a/forui/test/golden/dialog/zinc-light-FDialogAlignment.vertical-content.png and /dev/null differ diff --git a/forui/test/golden/dialog/zinc-light-FDialogAlignment.vertical-raw-dialog-content.png b/forui/test/golden/dialog/zinc-light-FDialogAlignment.vertical-raw-dialog-content.png new file mode 100644 index 000000000..8a0c8c260 Binary files /dev/null and b/forui/test/golden/dialog/zinc-light-FDialogAlignment.vertical-raw-dialog-content.png differ diff --git a/forui/test/golden/dialog/zinc-light-FDialogAlignment.vertical-text-dialog-content.png b/forui/test/golden/dialog/zinc-light-FDialogAlignment.vertical-text-dialog-content.png new file mode 100644 index 000000000..8a0c8c260 Binary files /dev/null and b/forui/test/golden/dialog/zinc-light-FDialogAlignment.vertical-text-dialog-content.png differ diff --git a/forui/test/golden/header/zinc-dark-header-overflow.png b/forui/test/golden/header/zinc-dark-header-overflow.png deleted file mode 100644 index 199ab0d3b..000000000 Binary files a/forui/test/golden/header/zinc-dark-header-overflow.png and /dev/null differ diff --git a/forui/test/golden/header/zinc-dark-header.png b/forui/test/golden/header/zinc-dark-header.png index 8f8f2556c..a99ee2519 100644 Binary files a/forui/test/golden/header/zinc-dark-header.png and b/forui/test/golden/header/zinc-dark-header.png differ diff --git a/forui/test/golden/header/zinc-dark-header-actions.png b/forui/test/golden/header/zinc-dark-raw-title.png similarity index 56% rename from forui/test/golden/header/zinc-dark-header-actions.png rename to forui/test/golden/header/zinc-dark-raw-title.png index 364125ba7..72dcab638 100644 Binary files a/forui/test/golden/header/zinc-dark-header-actions.png and b/forui/test/golden/header/zinc-dark-raw-title.png differ diff --git a/forui/test/golden/header/zinc-light-header-overflow.png b/forui/test/golden/header/zinc-light-header-overflow.png deleted file mode 100644 index 1500e1b82..000000000 Binary files a/forui/test/golden/header/zinc-light-header-overflow.png and /dev/null differ diff --git a/forui/test/golden/header/zinc-light-header.png b/forui/test/golden/header/zinc-light-header.png index 7f71a2ab7..eea9fcee0 100644 Binary files a/forui/test/golden/header/zinc-light-header.png and b/forui/test/golden/header/zinc-light-header.png differ diff --git a/forui/test/golden/header/zinc-light-header-actions.png b/forui/test/golden/header/zinc-light-raw-title.png similarity index 58% rename from forui/test/golden/header/zinc-light-header-actions.png rename to forui/test/golden/header/zinc-light-raw-title.png index 7ea3a208e..753eab311 100644 Binary files a/forui/test/golden/header/zinc-light-header-actions.png and b/forui/test/golden/header/zinc-light-raw-title.png differ diff --git a/forui/test/golden/text_field/default-zinc-dark-focused-no-text.png b/forui/test/golden/text_field/default-zinc-dark-focused-no-text.png index b8d3538b6..a0971e19b 100644 Binary files a/forui/test/golden/text_field/default-zinc-dark-focused-no-text.png and b/forui/test/golden/text_field/default-zinc-dark-focused-no-text.png differ diff --git a/forui/test/golden/text_field/default-zinc-dark-focused-raw-text.png b/forui/test/golden/text_field/default-zinc-dark-focused-raw-text.png new file mode 100644 index 000000000..a2e0127be Binary files /dev/null and b/forui/test/golden/text_field/default-zinc-dark-focused-raw-text.png differ diff --git a/forui/test/golden/text_field/default-zinc-dark-focused-text.png b/forui/test/golden/text_field/default-zinc-dark-focused-text.png index ebdd25dba..25faae303 100644 Binary files a/forui/test/golden/text_field/default-zinc-dark-focused-text.png and b/forui/test/golden/text_field/default-zinc-dark-focused-text.png differ diff --git a/forui/test/golden/text_field/default-zinc-dark-unfocused-no-text.png b/forui/test/golden/text_field/default-zinc-dark-unfocused-no-text.png index e1199aa57..8e7b13fa4 100644 Binary files a/forui/test/golden/text_field/default-zinc-dark-unfocused-no-text.png and b/forui/test/golden/text_field/default-zinc-dark-unfocused-no-text.png differ diff --git a/forui/test/golden/text_field/default-zinc-dark-unfocused-raw-text.png b/forui/test/golden/text_field/default-zinc-dark-unfocused-raw-text.png new file mode 100644 index 000000000..7a1e46320 Binary files /dev/null and b/forui/test/golden/text_field/default-zinc-dark-unfocused-raw-text.png differ diff --git a/forui/test/golden/text_field/default-zinc-dark-unfocused-text.png b/forui/test/golden/text_field/default-zinc-dark-unfocused-text.png index 3411431a4..bad7d3367 100644 Binary files a/forui/test/golden/text_field/default-zinc-dark-unfocused-text.png and b/forui/test/golden/text_field/default-zinc-dark-unfocused-text.png differ diff --git a/forui/test/golden/text_field/default-zinc-light-focused-no-text.png b/forui/test/golden/text_field/default-zinc-light-focused-no-text.png index f13e6beeb..22095100a 100644 Binary files a/forui/test/golden/text_field/default-zinc-light-focused-no-text.png and b/forui/test/golden/text_field/default-zinc-light-focused-no-text.png differ diff --git a/forui/test/golden/text_field/default-zinc-light-focused-raw-text.png b/forui/test/golden/text_field/default-zinc-light-focused-raw-text.png new file mode 100644 index 000000000..95870e393 Binary files /dev/null and b/forui/test/golden/text_field/default-zinc-light-focused-raw-text.png differ diff --git a/forui/test/golden/text_field/default-zinc-light-focused-text.png b/forui/test/golden/text_field/default-zinc-light-focused-text.png index 6d84c5337..63b5fc75e 100644 Binary files a/forui/test/golden/text_field/default-zinc-light-focused-text.png and b/forui/test/golden/text_field/default-zinc-light-focused-text.png differ diff --git a/forui/test/golden/text_field/default-zinc-light-unfocused-no-text.png b/forui/test/golden/text_field/default-zinc-light-unfocused-no-text.png index 19eaef775..f8447c986 100644 Binary files a/forui/test/golden/text_field/default-zinc-light-unfocused-no-text.png and b/forui/test/golden/text_field/default-zinc-light-unfocused-no-text.png differ diff --git a/forui/test/golden/text_field/default-zinc-light-unfocused-raw-text.png b/forui/test/golden/text_field/default-zinc-light-unfocused-raw-text.png new file mode 100644 index 000000000..c0a0eb39b Binary files /dev/null and b/forui/test/golden/text_field/default-zinc-light-unfocused-raw-text.png differ diff --git a/forui/test/golden/text_field/default-zinc-light-unfocused-text.png b/forui/test/golden/text_field/default-zinc-light-unfocused-text.png index a186a28e4..aa94e58e3 100644 Binary files a/forui/test/golden/text_field/default-zinc-light-unfocused-text.png and b/forui/test/golden/text_field/default-zinc-light-unfocused-text.png differ diff --git a/forui/test/golden/text_field/email-zinc-dark-focused-no-text.png b/forui/test/golden/text_field/email-zinc-dark-focused-no-text.png index ab3c651b0..414170fea 100644 Binary files a/forui/test/golden/text_field/email-zinc-dark-focused-no-text.png and b/forui/test/golden/text_field/email-zinc-dark-focused-no-text.png differ diff --git a/forui/test/golden/text_field/email-zinc-dark-focused-text.png b/forui/test/golden/text_field/email-zinc-dark-focused-text.png index 74b8332ac..c1b8e08bf 100644 Binary files a/forui/test/golden/text_field/email-zinc-dark-focused-text.png and b/forui/test/golden/text_field/email-zinc-dark-focused-text.png differ diff --git a/forui/test/golden/text_field/email-zinc-dark-unfocused-no-text.png b/forui/test/golden/text_field/email-zinc-dark-unfocused-no-text.png index 015e28748..45bb933c1 100644 Binary files a/forui/test/golden/text_field/email-zinc-dark-unfocused-no-text.png and b/forui/test/golden/text_field/email-zinc-dark-unfocused-no-text.png differ diff --git a/forui/test/golden/text_field/email-zinc-dark-unfocused-text.png b/forui/test/golden/text_field/email-zinc-dark-unfocused-text.png index afed1d0f4..2f646e22e 100644 Binary files a/forui/test/golden/text_field/email-zinc-dark-unfocused-text.png and b/forui/test/golden/text_field/email-zinc-dark-unfocused-text.png differ diff --git a/forui/test/golden/text_field/email-zinc-light-focused-no-text.png b/forui/test/golden/text_field/email-zinc-light-focused-no-text.png index fc8a3c859..b6f6a3cc2 100644 Binary files a/forui/test/golden/text_field/email-zinc-light-focused-no-text.png and b/forui/test/golden/text_field/email-zinc-light-focused-no-text.png differ diff --git a/forui/test/golden/text_field/email-zinc-light-focused-text.png b/forui/test/golden/text_field/email-zinc-light-focused-text.png index bdff36501..284dbc672 100644 Binary files a/forui/test/golden/text_field/email-zinc-light-focused-text.png and b/forui/test/golden/text_field/email-zinc-light-focused-text.png differ diff --git a/forui/test/golden/text_field/email-zinc-light-unfocused-no-text.png b/forui/test/golden/text_field/email-zinc-light-unfocused-no-text.png index 19c21dfb9..6e04cf61b 100644 Binary files a/forui/test/golden/text_field/email-zinc-light-unfocused-no-text.png and b/forui/test/golden/text_field/email-zinc-light-unfocused-no-text.png differ diff --git a/forui/test/golden/text_field/email-zinc-light-unfocused-text.png b/forui/test/golden/text_field/email-zinc-light-unfocused-text.png index b62d9e506..5172c1229 100644 Binary files a/forui/test/golden/text_field/email-zinc-light-unfocused-text.png and b/forui/test/golden/text_field/email-zinc-light-unfocused-text.png differ diff --git a/forui/test/golden/text_field/error-zinc-dark-focused-no-text.png b/forui/test/golden/text_field/error-zinc-dark-focused-no-text.png index a5854f0c4..f37078e31 100644 Binary files a/forui/test/golden/text_field/error-zinc-dark-focused-no-text.png and b/forui/test/golden/text_field/error-zinc-dark-focused-no-text.png differ diff --git a/forui/test/golden/text_field/error-zinc-dark-focused-raw-text.png b/forui/test/golden/text_field/error-zinc-dark-focused-raw-text.png new file mode 100644 index 000000000..2dcc9ea3c Binary files /dev/null and b/forui/test/golden/text_field/error-zinc-dark-focused-raw-text.png differ diff --git a/forui/test/golden/text_field/error-zinc-dark-focused-text.png b/forui/test/golden/text_field/error-zinc-dark-focused-text.png index af50450f8..d850eab0e 100644 Binary files a/forui/test/golden/text_field/error-zinc-dark-focused-text.png and b/forui/test/golden/text_field/error-zinc-dark-focused-text.png differ diff --git a/forui/test/golden/text_field/error-zinc-dark-unfocused-no-text.png b/forui/test/golden/text_field/error-zinc-dark-unfocused-no-text.png index 5e41fa604..595def582 100644 Binary files a/forui/test/golden/text_field/error-zinc-dark-unfocused-no-text.png and b/forui/test/golden/text_field/error-zinc-dark-unfocused-no-text.png differ diff --git a/forui/test/golden/text_field/error-zinc-dark-unfocused-raw-text.png b/forui/test/golden/text_field/error-zinc-dark-unfocused-raw-text.png new file mode 100644 index 000000000..c8784e4c8 Binary files /dev/null and b/forui/test/golden/text_field/error-zinc-dark-unfocused-raw-text.png differ diff --git a/forui/test/golden/text_field/error-zinc-dark-unfocused-text.png b/forui/test/golden/text_field/error-zinc-dark-unfocused-text.png index 936a868c3..92a1cb6e8 100644 Binary files a/forui/test/golden/text_field/error-zinc-dark-unfocused-text.png and b/forui/test/golden/text_field/error-zinc-dark-unfocused-text.png differ diff --git a/forui/test/golden/text_field/error-zinc-light-focused-no-text.png b/forui/test/golden/text_field/error-zinc-light-focused-no-text.png index cead17e16..61ec8378d 100644 Binary files a/forui/test/golden/text_field/error-zinc-light-focused-no-text.png and b/forui/test/golden/text_field/error-zinc-light-focused-no-text.png differ diff --git a/forui/test/golden/text_field/error-zinc-light-focused-raw-text.png b/forui/test/golden/text_field/error-zinc-light-focused-raw-text.png new file mode 100644 index 000000000..a5bb434a2 Binary files /dev/null and b/forui/test/golden/text_field/error-zinc-light-focused-raw-text.png differ diff --git a/forui/test/golden/text_field/error-zinc-light-focused-text.png b/forui/test/golden/text_field/error-zinc-light-focused-text.png index 446166722..465cae999 100644 Binary files a/forui/test/golden/text_field/error-zinc-light-focused-text.png and b/forui/test/golden/text_field/error-zinc-light-focused-text.png differ diff --git a/forui/test/golden/text_field/error-zinc-light-unfocused-no-text.png b/forui/test/golden/text_field/error-zinc-light-unfocused-no-text.png index 7aa78de0d..83125d37f 100644 Binary files a/forui/test/golden/text_field/error-zinc-light-unfocused-no-text.png and b/forui/test/golden/text_field/error-zinc-light-unfocused-no-text.png differ diff --git a/forui/test/golden/text_field/error-zinc-light-unfocused-raw-text.png b/forui/test/golden/text_field/error-zinc-light-unfocused-raw-text.png new file mode 100644 index 000000000..b0b0f3240 Binary files /dev/null and b/forui/test/golden/text_field/error-zinc-light-unfocused-raw-text.png differ diff --git a/forui/test/golden/text_field/error-zinc-light-unfocused-text.png b/forui/test/golden/text_field/error-zinc-light-unfocused-text.png index c57b9628a..b871a892d 100644 Binary files a/forui/test/golden/text_field/error-zinc-light-unfocused-text.png and b/forui/test/golden/text_field/error-zinc-light-unfocused-text.png differ diff --git a/forui/test/golden/text_field/multiline-zinc-dark-focused-no-text.png b/forui/test/golden/text_field/multiline-zinc-dark-focused-no-text.png index 53837cd5c..6c64bd7f5 100644 Binary files a/forui/test/golden/text_field/multiline-zinc-dark-focused-no-text.png and b/forui/test/golden/text_field/multiline-zinc-dark-focused-no-text.png differ diff --git a/forui/test/golden/text_field/multiline-zinc-dark-focused-text.png b/forui/test/golden/text_field/multiline-zinc-dark-focused-text.png index e6729286c..daa675dd7 100644 Binary files a/forui/test/golden/text_field/multiline-zinc-dark-focused-text.png and b/forui/test/golden/text_field/multiline-zinc-dark-focused-text.png differ diff --git a/forui/test/golden/text_field/multiline-zinc-dark-unfocused-no-text.png b/forui/test/golden/text_field/multiline-zinc-dark-unfocused-no-text.png index 4a0f9f02f..1928d1fa4 100644 Binary files a/forui/test/golden/text_field/multiline-zinc-dark-unfocused-no-text.png and b/forui/test/golden/text_field/multiline-zinc-dark-unfocused-no-text.png differ diff --git a/forui/test/golden/text_field/multiline-zinc-dark-unfocused-text.png b/forui/test/golden/text_field/multiline-zinc-dark-unfocused-text.png index 62fc506a7..fa3b77738 100644 Binary files a/forui/test/golden/text_field/multiline-zinc-dark-unfocused-text.png and b/forui/test/golden/text_field/multiline-zinc-dark-unfocused-text.png differ diff --git a/forui/test/golden/text_field/multiline-zinc-light-focused-no-text.png b/forui/test/golden/text_field/multiline-zinc-light-focused-no-text.png index 75b2cec59..1f9fcf650 100644 Binary files a/forui/test/golden/text_field/multiline-zinc-light-focused-no-text.png and b/forui/test/golden/text_field/multiline-zinc-light-focused-no-text.png differ diff --git a/forui/test/golden/text_field/multiline-zinc-light-focused-text.png b/forui/test/golden/text_field/multiline-zinc-light-focused-text.png index 0116cb435..0f34bef89 100644 Binary files a/forui/test/golden/text_field/multiline-zinc-light-focused-text.png and b/forui/test/golden/text_field/multiline-zinc-light-focused-text.png differ diff --git a/forui/test/golden/text_field/multiline-zinc-light-unfocused-no-text.png b/forui/test/golden/text_field/multiline-zinc-light-unfocused-no-text.png index c2898c00d..3ec65d60b 100644 Binary files a/forui/test/golden/text_field/multiline-zinc-light-unfocused-no-text.png and b/forui/test/golden/text_field/multiline-zinc-light-unfocused-no-text.png differ diff --git a/forui/test/golden/text_field/multiline-zinc-light-unfocused-text.png b/forui/test/golden/text_field/multiline-zinc-light-unfocused-text.png index 52831c15c..4c06afe80 100644 Binary files a/forui/test/golden/text_field/multiline-zinc-light-unfocused-text.png and b/forui/test/golden/text_field/multiline-zinc-light-unfocused-text.png differ diff --git a/forui/test/golden/text_field/password-zinc-dark-focused-no-text.png b/forui/test/golden/text_field/password-zinc-dark-focused-no-text.png index 6119a8b14..db10bf479 100644 Binary files a/forui/test/golden/text_field/password-zinc-dark-focused-no-text.png and b/forui/test/golden/text_field/password-zinc-dark-focused-no-text.png differ diff --git a/forui/test/golden/text_field/password-zinc-dark-focused-text.png b/forui/test/golden/text_field/password-zinc-dark-focused-text.png index 3cf839085..fe5196125 100644 Binary files a/forui/test/golden/text_field/password-zinc-dark-focused-text.png and b/forui/test/golden/text_field/password-zinc-dark-focused-text.png differ diff --git a/forui/test/golden/text_field/password-zinc-dark-unfocused-no-text.png b/forui/test/golden/text_field/password-zinc-dark-unfocused-no-text.png index 83888c8c0..9bf104208 100644 Binary files a/forui/test/golden/text_field/password-zinc-dark-unfocused-no-text.png and b/forui/test/golden/text_field/password-zinc-dark-unfocused-no-text.png differ diff --git a/forui/test/golden/text_field/password-zinc-dark-unfocused-text.png b/forui/test/golden/text_field/password-zinc-dark-unfocused-text.png index 9f19b3507..9f31ef685 100644 Binary files a/forui/test/golden/text_field/password-zinc-dark-unfocused-text.png and b/forui/test/golden/text_field/password-zinc-dark-unfocused-text.png differ diff --git a/forui/test/golden/text_field/password-zinc-light-focused-no-text.png b/forui/test/golden/text_field/password-zinc-light-focused-no-text.png index e02f64e1f..74384304c 100644 Binary files a/forui/test/golden/text_field/password-zinc-light-focused-no-text.png and b/forui/test/golden/text_field/password-zinc-light-focused-no-text.png differ diff --git a/forui/test/golden/text_field/password-zinc-light-focused-text.png b/forui/test/golden/text_field/password-zinc-light-focused-text.png index 903271a23..30f3620f9 100644 Binary files a/forui/test/golden/text_field/password-zinc-light-focused-text.png and b/forui/test/golden/text_field/password-zinc-light-focused-text.png differ diff --git a/forui/test/golden/text_field/password-zinc-light-unfocused-no-text.png b/forui/test/golden/text_field/password-zinc-light-unfocused-no-text.png index 264a6232d..ca5a86653 100644 Binary files a/forui/test/golden/text_field/password-zinc-light-unfocused-no-text.png and b/forui/test/golden/text_field/password-zinc-light-unfocused-no-text.png differ diff --git a/forui/test/golden/text_field/password-zinc-light-unfocused-text.png b/forui/test/golden/text_field/password-zinc-light-unfocused-text.png index 99803066b..9ea182b1e 100644 Binary files a/forui/test/golden/text_field/password-zinc-light-unfocused-text.png and b/forui/test/golden/text_field/password-zinc-light-unfocused-text.png differ diff --git a/forui/test/src/widgets/badge_golden_test.dart b/forui/test/src/widgets/badge/badge_golden_test.dart similarity index 72% rename from forui/test/src/widgets/badge_golden_test.dart rename to forui/test/src/widgets/badge/badge_golden_test.dart index dd3e3b33b..5d4b9f937 100644 --- a/forui/test/src/widgets/badge_golden_test.dart +++ b/forui/test/src/widgets/badge/badge_golden_test.dart @@ -6,13 +6,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:forui/forui.dart'; -import '../test_scaffold.dart'; +import '../../test_scaffold.dart'; void main() { group('FBadge', () { for (final (name, theme, background) in TestScaffold.themes) { for (final variant in FBadgeVariant.values) { - testWidgets('$name with FBadgeContent', (tester) async { + testWidgets('$name with text FBadgeContent', (tester) async { await tester.pumpWidget( TestScaffold( data: theme, @@ -26,10 +26,29 @@ void main() { await expectLater( find.byType(TestScaffold), - matchesGoldenFile('badge/$name-$variant-badge-content.png'), + matchesGoldenFile('badge/$name-$variant-text-badge-content.png'), ); }); + testWidgets('$name with raw FBadgeContent', (tester) async { + await tester.pumpWidget( + TestScaffold( + data: theme, + background: background, + child: FBadge( + rawLabel: const Text('Badge'), + design: variant, + ), + ), + ); + + await expectLater( + find.byType(TestScaffold), + matchesGoldenFile('badge/$name-$variant-raw-badge-content.png'), + ); + }); + + testWidgets('$name with raw content', (tester) async { await tester.pumpWidget( TestScaffold( diff --git a/forui/test/src/widgets/badge/badge_test.dart b/forui/test/src/widgets/badge/badge_test.dart new file mode 100644 index 000000000..2b6702558 --- /dev/null +++ b/forui/test/src/widgets/badge/badge_test.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_test/flutter_test.dart'; + +import 'package:forui/forui.dart'; + +void main() { + group('FBadge', () { + for (final (label, rawLabel) in [ + ('', null), + (null, const SizedBox()), + ]) { + testWidgets('constructor does not throw error', (tester) async { + expect( + () => FBadge( + label: label, + rawLabel: rawLabel, + ), + returnsNormally, + ); + }); + } + + for (final (label, rawLabel) in [ + (null, null), + ('', const SizedBox()), + ]) { + testWidgets('constructor throws error', (tester) async { + expect( + () => FBadge( + label: label, + rawLabel: rawLabel, + ), + throwsAssertionError, + ); + }); + } + }); +} diff --git a/forui/test/src/widgets/button_golden_test.dart b/forui/test/src/widgets/button_golden_test.dart index c6c3d9e27..877496dfe 100644 --- a/forui/test/src/widgets/button_golden_test.dart +++ b/forui/test/src/widgets/button_golden_test.dart @@ -19,8 +19,10 @@ void main() { child: Padding( padding: const EdgeInsets.symmetric(horizontal: 20), child: FButton( - text: 'Button', + labelText: 'Button', design: variant, + prefixIcon: FButtonIcon(icon: FAssets.icons.circlePlay), + suffixIcon: FButtonIcon(icon: FAssets.icons.circleStop), onPress: () {}, ), ), @@ -40,8 +42,10 @@ void main() { child: Padding( padding: const EdgeInsets.symmetric(horizontal: 20), child: FButton( - text: 'Button', + labelText: 'Button', design: variant, + prefixIcon: FButtonIcon(icon: FAssets.icons.circlePlay), + suffixIcon: FButtonIcon(icon: FAssets.icons.circleStop), onPress: null, ), ), @@ -63,7 +67,7 @@ void main() { child: FButton.raw( design: variant, onPress: () {}, - builder: (_, style) => Padding( + child: Padding( padding: const EdgeInsets.all(50), child: Container( width: 50, @@ -102,7 +106,7 @@ void main() { child: FButton.raw( design: variant, onPress: null, - builder: (_, style) => Padding( + child: Padding( padding: const EdgeInsets.all(50), child: Container( width: 50, diff --git a/forui/test/src/widgets/card_golden_test.dart b/forui/test/src/widgets/card/card_golden_test.dart similarity index 63% rename from forui/test/src/widgets/card_golden_test.dart rename to forui/test/src/widgets/card/card_golden_test.dart index 6010b1f4e..fa6a7f149 100644 --- a/forui/test/src/widgets/card_golden_test.dart +++ b/forui/test/src/widgets/card/card_golden_test.dart @@ -6,12 +6,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:forui/forui.dart'; -import '../test_scaffold.dart'; +import '../../test_scaffold.dart'; void main() { group('FCard', () { for (final (name, theme, background) in TestScaffold.themes) { - testWidgets('$name with FCardContent', (tester) async { + testWidgets('$name with text FCardContent', (tester) async { await tester.pumpWidget( TestScaffold( data: theme, @@ -30,7 +30,30 @@ void main() { await expectLater( find.byType(TestScaffold), - matchesGoldenFile('card/$name-card-content.png'), + matchesGoldenFile('card/$name-text-card-content.png'), + ); + }); + + testWidgets('$name with raw FCardContent', (tester) async { + await tester.pumpWidget( + TestScaffold( + data: theme, + background: background, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + FCard( + rawTitle: const Text('Notifications'), + rawSubtitle: const Text('You have 3 unread messages.'), + ), + ], + ), + ), + ); + + await expectLater( + find.byType(TestScaffold), + matchesGoldenFile('card/$name-raw-card-content.png'), ); }); diff --git a/forui/test/src/widgets/card/card_test.dart b/forui/test/src/widgets/card/card_test.dart new file mode 100644 index 000000000..6801cb89e --- /dev/null +++ b/forui/test/src/widgets/card/card_test.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_test/flutter_test.dart'; + +import 'package:forui/forui.dart'; + +void main() { + group('FCard', () { + for (final (string, raw) in [ + (null, null), + ('', null), + (null, const SizedBox()), + ]) { + testWidgets('constructor title does not throw error', (tester) async { + expect( + () => FCard( + title: string, + rawTitle: raw, + ), + returnsNormally, + ); + }); + + testWidgets('constructor subtitle does not throw error', (tester) async { + expect( + () => FCard( + subtitle: string, + rawSubtitle: raw, + ), + returnsNormally, + ); + }); + } + + for (final (string, raw) in [ + ('', const SizedBox()), + ]) { + testWidgets('constructor title throws error', (tester) async { + expect( + () => FCard( + title: string, + rawTitle: raw, + ), + throwsAssertionError, + ); + }); + + testWidgets('constructor subtitle throws error', (tester) async { + expect( + () => FCard( + subtitle: string, + rawSubtitle: raw, + ), + throwsAssertionError, + ); + }); + } + }); +} diff --git a/forui/test/src/widgets/dialog/dialog_golden_test.dart b/forui/test/src/widgets/dialog/dialog_golden_test.dart index 8794c8d97..84b13526d 100644 --- a/forui/test/src/widgets/dialog/dialog_golden_test.dart +++ b/forui/test/src/widgets/dialog/dialog_golden_test.dart @@ -8,26 +8,43 @@ import '../../test_scaffold.dart'; class UnderTest extends StatelessWidget { final FDialogAlignment alignment; + final bool raw; - const UnderTest({required this.alignment, super.key}); + const UnderTest({required this.alignment, required this.raw, super.key}); @override - Widget build(BuildContext context) => FDialog( - alignment: alignment, - title: 'Are you absolutely sure?', - subtitle: 'This action cannot be undone. This will permanently delete your account and remove your data from our servers.', - actions: [ - FButton(text: 'Continue', onPress: () {}), - FButton(design: FButtonVariant.outlined, text: 'Cancel', onPress: () { + Widget build(BuildContext context) { + final actions = [ + FButton(labelText: 'Continue', onPress: () {}), + FButton(design: FButtonVariant.outlined, labelText: 'Cancel', onPress: () { Navigator.of(context).pop(); }), - ], - ); + ]; + + if (raw) { + return FDialog( + alignment: alignment, + rawTitle: const Text('Are you absolutely sure?'), + rawBody: const Text('This action cannot be undone. This will permanently delete your account and remove your data from our servers.'), + actions: actions, + ); + + } else { + return FDialog( + alignment: alignment, + title: 'Are you absolutely sure?', + body: 'This action cannot be undone. This will permanently delete your account and remove your data from our servers.', + actions: actions, + ); + } + } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(EnumProperty('alignment', alignment)); + properties + ..add(EnumProperty('alignment', alignment)) + ..add(DiagnosticsProperty('raw', raw)); } } @@ -36,24 +53,40 @@ void main() { group('FDialog', () { for (final (name, theme, background) in TestScaffold.themes) { for (final alignment in [FDialogAlignment.horizontal, FDialogAlignment.vertical]) { - testWidgets('$name with $alignment content', (tester) async { + testWidgets('$name with $alignment text FDialogContent', (tester) async { + await tester.pumpWidget( + MaterialApp( + home: TestScaffold( + data: theme, + background: background, + child: UnderTest(alignment: alignment, raw: false), + ), + ), + ); + + await expectLater( + find.byType(UnderTest), + matchesGoldenFile('dialog/$name-$alignment-text-dialog-content.png'), + ); + }); + + testWidgets('$name with $alignment raw FDialogContent', (tester) async { await tester.pumpWidget( MaterialApp( home: TestScaffold( data: theme, background: background, - child: UnderTest(alignment: alignment), + child: UnderTest(alignment: alignment, raw: true), ), ), ); await expectLater( find.byType(UnderTest), - matchesGoldenFile('dialog/$name-$alignment-content.png'), + matchesGoldenFile('dialog/$name-$alignment-raw-dialog-content.png'), ); }); } - testWidgets('$name with raw content', (tester) async { await tester.pumpWidget( diff --git a/forui/test/src/widgets/dialog/dialog_test.dart b/forui/test/src/widgets/dialog/dialog_test.dart new file mode 100644 index 000000000..93479f8db --- /dev/null +++ b/forui/test/src/widgets/dialog/dialog_test.dart @@ -0,0 +1,63 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_test/flutter_test.dart'; + +import 'package:forui/forui.dart'; + +void main() { + group('FDialog', () { + for (final (string, raw) in [ + (null, null), + ('', null), + (null, const SizedBox()), + ]) { + testWidgets('constructor title does not throw error', (tester) async { + expect( + () => FDialog( + title: string, + rawTitle: raw, + actions: const [], + ), + returnsNormally, + ); + }); + + testWidgets('constructor body does not throw error', (tester) async { + expect( + () => FDialog( + body: string, + rawBody: raw, + actions: const [], + ), + returnsNormally, + ); + }); + } + + for (final (string, raw) in [ + ('', const SizedBox()), + ]) { + testWidgets('constructor title throws error', (tester) async { + expect( + () => FDialog( + title: string, + rawTitle: raw, + actions: const [], + ), + throwsAssertionError, + ); + }); + + testWidgets('constructor body throws error', (tester) async { + expect( + () => FDialog( + body: string, + rawBody: raw, + actions: const [], + ), + throwsAssertionError, + ); + }); + } + }); +} diff --git a/forui/test/src/widgets/header/header_golden_test.dart b/forui/test/src/widgets/header/header_golden_test.dart new file mode 100644 index 000000000..c1656720e --- /dev/null +++ b/forui/test/src/widgets/header/header_golden_test.dart @@ -0,0 +1,75 @@ +@Tags(['golden']) +library; + +import 'package:flutter/cupertino.dart'; + +import 'package:flutter_test/flutter_test.dart'; + +import 'package:forui/forui.dart'; +import '../../test_scaffold.dart'; + +const title = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.'; + +void main() { + group('FHeader', () { + for (final (name, theme, _) in TestScaffold.themes) { + testWidgets('$name with FHeader actions', (tester) async { + await tester.pumpWidget( + TestScaffold( + data: theme, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: FHeader( + title: title, + actions: [ + FHeaderAction( + icon: FAssets.icons.alarmClock, + onPress: null, + ), + FHeaderAction( + icon: FAssets.icons.plus, + onPress: () {}, + ), + ], + ), + ) + ), + ); + + await expectLater( + find.byType(TestScaffold), + matchesGoldenFile('header/$name-header.png'), + ); + }); + + testWidgets('$name with raw title', (tester) async { + await tester.pumpWidget( + TestScaffold( + data: theme, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: FHeader( + rawTitle: const Text('Title'), + actions: [ + FHeaderAction( + icon: FAssets.icons.alarmClock, + onPress: null, + ), + FHeaderAction( + icon: FAssets.icons.plus, + onPress: () {}, + ), + ], + ), + ) + ), + ); + + await expectLater( + find.byType(TestScaffold), + matchesGoldenFile('header/$name-raw-title.png'), + ); + }); + } + }); +} diff --git a/forui/test/src/widgets/header/header_test.dart b/forui/test/src/widgets/header/header_test.dart new file mode 100644 index 000000000..22743a29d --- /dev/null +++ b/forui/test/src/widgets/header/header_test.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_test/flutter_test.dart'; + +import 'package:forui/forui.dart'; + +void main() { + group('FHeader', () { + for (final (title, rawTitle) in [ + ('', null), + (null, const SizedBox()), + ]) { + testWidgets('constructor does not throw error', (tester) async { + expect( + () => FHeader( + title: title, + rawTitle: rawTitle, + ), + returnsNormally, + ); + }); + } + + for (final (title, rawTitle) in [ + (null, null), + ('', const SizedBox()), + ]) { + testWidgets('constructor throws error', (tester) async { + expect( + () => FHeader( + title: title, + rawTitle: rawTitle, + ), + throwsAssertionError, + ); + }); + } + }); +} diff --git a/forui/test/src/widgets/header_golden_test.dart b/forui/test/src/widgets/header_golden_test.dart deleted file mode 100644 index 997f9362e..000000000 --- a/forui/test/src/widgets/header_golden_test.dart +++ /dev/null @@ -1,90 +0,0 @@ -@Tags(['golden']) -library; - -import 'package:flutter/cupertino.dart'; - -import 'package:flutter_test/flutter_test.dart'; - -import 'package:forui/forui.dart'; -import '../test_scaffold.dart'; - -void main() { - group('FHeader', () { - for (final (name, theme, _) in TestScaffold.themes) { - testWidgets('$name with FHeader actions', (tester) async { - await tester.pumpWidget( - TestScaffold( - data: theme, - child: const Padding( - padding: EdgeInsets.symmetric(horizontal: 20), - child: FHeader(title: 'Title'), - ) - ), - ); - - await expectLater( - find.byType(TestScaffold), - matchesGoldenFile('header/$name-header.png'), - ); - }); - - testWidgets('$name with FHeader actions', (tester) async { - await tester.pumpWidget( - TestScaffold( - data: theme, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: FHeader( - title: 'Title', - actions: [ - FHeaderAction( - icon: FAssets.icons.alarmClock, - onPress: null, - ), - FHeaderAction( - icon: FAssets.icons.plus, - onPress: () {}, - ), - ], - ), - ) - ), - ); - - await expectLater( - find.byType(TestScaffold), - matchesGoldenFile('header/$name-header-actions.png'), - ); - }); - - testWidgets('$name with FHeader title overflow', (tester) async { - await tester.pumpWidget( - TestScaffold( - data: theme, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: FHeader( - title: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.', - actions: [ - FHeaderAction( - icon: FAssets.icons.alarmClock, - onPress: null, - ), - FHeaderAction( - icon: FAssets.icons.plus, - onPress: () {}, - ), - ], - ), - ) - ), - ); - - await expectLater( - find.byType(TestScaffold), - matchesGoldenFile('header/$name-header-overflow.png'), - ); - }); - } - }); -} diff --git a/forui/test/src/widgets/text_field/text_field_golden_test.dart b/forui/test/src/widgets/text_field/text_field_golden_test.dart index 8aae0f907..1b6130f6f 100644 --- a/forui/test/src/widgets/text_field/text_field_golden_test.dart +++ b/forui/test/src/widgets/text_field/text_field_golden_test.dart @@ -18,6 +18,60 @@ void main() { group('FTextField', () { for (final (theme, theme_, _) in TestScaffold.themes) { for (final (focused, focused_) in [('focused', true), ('unfocused', false)]) { + testWidgets('default - $theme - $focused - raw text', (tester) async { + await tester.pumpWidget( + MaterialApp( + home: TestScaffold( + data: theme_, + child: Padding( + padding: const EdgeInsets.all(20), + child: FTextField( + controller: TextEditingController(text: 'short text'), + autofocus: focused_, + rawLabel: const Text('My Label'), + hint: 'hint', + rawHelp: const Text('Some help text.'), + ), + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + await expectLater( + find.byType(TestScaffold), + matchesGoldenFile('text_field/default-$theme-$focused-raw-text.png'), + ); + }); + + testWidgets('error - $theme - $focused - raw text', (tester) async { + await tester.pumpWidget( + MaterialApp( + home: TestScaffold( + data: theme_, + child: Padding( + padding: const EdgeInsets.all(20), + child: FTextField( + controller: TextEditingController(text: 'short text'), + autofocus: focused_, + rawLabel: const Text('My Label'), + hint: 'hint', + rawError: const Text('An error has occurred.'), + ), + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + await expectLater( + find.byType(TestScaffold), + matchesGoldenFile('text_field/error-$theme-$focused-raw-text.png'), + ); + }); + for (final (text, text_) in [('text', 'short text'), ('no-text', null)]) { testWidgets('default - $theme - $focused - $text', (tester) async { final controller = text_ == null ? null : TextEditingController(text: text_); @@ -30,9 +84,9 @@ void main() { child: FTextField( controller: controller, autofocus: focused_, - labelText: 'My Label', - hintText: 'hint', - helpText: 'Some help text.', + label: 'My Label', + hint: 'hint', + help: 'Some help text.', ), ), ), @@ -58,9 +112,9 @@ void main() { child: FTextField( controller: controller, autofocus: focused_, - labelText: 'My Label', - hintText: 'hint', - errorText: 'An error has occurred.', + label: 'My Label', + hint: 'hint', + error: 'An error has occurred.', ), ), ), @@ -86,8 +140,8 @@ void main() { child: FTextField.email( controller: controller, autofocus: focused_, - labelText: 'Email', - hintText: 'janedoe@foruslabs.com', + label: 'Email', + hint: 'janedoe@foruslabs.com', ), ), ), @@ -113,8 +167,8 @@ void main() { child: FTextField.password( controller: controller, autofocus: focused_, - labelText: 'Password', - hintText: 'password', + label: 'Password', + hint: 'password', ), ), ), @@ -142,8 +196,8 @@ void main() { child: FTextField.multiline( controller: controller, autofocus: focused_, - labelText: 'My Label', - hintText: 'hint', + label: 'My Label', + hint: 'hint', ), ), ), @@ -158,7 +212,6 @@ void main() { ); }); } - } } }); diff --git a/forui/test/src/widgets/text_field/text_field_test.dart b/forui/test/src/widgets/text_field/text_field_test.dart index d29c77530..6f41015fc 100644 --- a/forui/test/src/widgets/text_field/text_field_test.dart +++ b/forui/test/src/widgets/text_field/text_field_test.dart @@ -63,5 +63,34 @@ void main() { expect(tester.takeException(), null); }); + + for (final constructor in [ + (string, raw) => FTextField(label: string, rawLabel: raw), + (string, raw) => FTextField(help: string, rawHelp: raw), + (string, raw) => FTextField(error: string, rawError: raw), + (string, raw) => FTextField.email(label: string, rawLabel: raw), + (string, raw) => FTextField.email(help: string, rawHelp: raw), + (string, raw) => FTextField.email(error: string, rawError: raw), + (string, raw) => FTextField.password(label: string, rawLabel: raw), + (string, raw) => FTextField.password(help: string, rawHelp: raw), + (string, raw) => FTextField.password(error: string, rawError: raw), + (string, raw) => FTextField.multiline(label: string, rawLabel: raw), + (string, raw) => FTextField.multiline(help: string, rawHelp: raw), + (string, raw) => FTextField.multiline(error: string, rawError: raw), + ]) { + for (final (string, raw) in [ + (null, null), + ('', null), + (null, const SizedBox()), + ]) { + testWidgets('constructor does not throw error', (tester) async { + expect(() => constructor(string, raw), returnsNormally); + }); + } + + testWidgets('constructor title throws error', (tester) async { + expect(() => constructor('', const SizedBox()), throwsAssertionError); + }); + } }); }