From be16d9eba2b85aed78373610855e3fbd31e38b75 Mon Sep 17 00:00:00 2001 From: Joe Date: Sun, 23 Jun 2024 15:49:28 +0800 Subject: [PATCH] Complete implementation --- forui/lib/src/theme/theme.dart | 5 +- forui/lib/src/theme/theme_data.dart | 44 ++- .../lib/src/widgets/badge/badge_content.dart | 2 +- forui/lib/src/widgets/badge/badge_styles.dart | 12 +- .../src/widgets/button/button_content.dart | 9 +- forui/lib/src/widgets/card/card.dart | 1 - forui/lib/src/widgets/card/card_content.dart | 64 ++-- forui/lib/src/widgets/dialog/dialog.dart | 113 ++++--- .../src/widgets/dialog/dialog_content.dart | 104 +++---- forui/lib/src/widgets/header/header.dart | 5 +- .../src/widgets/text_field/text_field.dart | 14 +- .../widgets/text_field/text_field_style.dart | 17 +- forui/test/src/theme/typography_test.dart | 294 ++++++++++-------- 13 files changed, 348 insertions(+), 336 deletions(-) diff --git a/forui/lib/src/theme/theme.dart b/forui/lib/src/theme/theme.dart index c45b51109..1cf36c633 100644 --- a/forui/lib/src/theme/theme.dart +++ b/forui/lib/src/theme/theme.dart @@ -104,7 +104,10 @@ class FTheme extends StatelessWidget { child: Directionality( textDirection: textDirection ?? Directionality.of(context), child: DefaultTextStyle( - style: data.typography.base.copyWith(color: data.colorScheme.foreground), + style: data.typography.base.copyWith( + fontFamily: data.typography.defaultFontFamily, + color: data.colorScheme.foreground, + ), child: child, ), ), diff --git a/forui/lib/src/theme/theme_data.dart b/forui/lib/src/theme/theme_data.dart index ca95321d4..32cace336 100644 --- a/forui/lib/src/theme/theme_data.dart +++ b/forui/lib/src/theme/theme_data.dart @@ -70,22 +70,31 @@ final class FThemeData with Diagnosticable { }); /// Creates a [FThemeData] that configures the widget styles using the given properties. - FThemeData.inherit({ - required this.colorScheme, - this.style = const FStyle(), - }) : typography = FTypography.inherit(colorScheme: colorScheme), - badgeStyles = FBadgeStyles.inherit(colorScheme: colorScheme, typography: typography, style: style), - buttonStyles = FButtonStyles.inherit( - colorScheme: colorScheme, - typography: typography, - style: style, - ), - cardStyle = FCardStyle.inherit(colorScheme: colorScheme, typography: typography, style: style), - dialogStyle = FDialogStyle.inherit(style: style, colorScheme: colorScheme, typography: typography), - headerStyle = FHeaderStyle.inherit(colorScheme: colorScheme, typography: typography), - textFieldStyle = FTextFieldStyle.inherit(colorScheme: colorScheme, typography: typography, style: style), - separatorStyles = FSeparatorStyles.inherit(colorScheme: colorScheme, style: style), - switchStyle = FSwitchStyle.inherit(colorScheme: colorScheme); + factory FThemeData.inherit({ + required FColorScheme colorScheme, + FStyle style = const FStyle(), + FTypography? typography, + }) { + typography ??= FTypography.inherit(colorScheme: colorScheme); + + return FThemeData( + colorScheme: colorScheme, + typography: typography, + style: style, + badgeStyles: FBadgeStyles.inherit(colorScheme: colorScheme, typography: typography, style: style), + buttonStyles: FButtonStyles.inherit( + colorScheme: colorScheme, + typography: typography, + style: style, + ), + cardStyle: FCardStyle.inherit(colorScheme: colorScheme, typography: typography, style: style), + dialogStyle: FDialogStyle.inherit(style: style, colorScheme: colorScheme, typography: typography), + headerStyle: FHeaderStyle.inherit(colorScheme: colorScheme, typography: typography), + textFieldStyle: FTextFieldStyle.inherit(colorScheme: colorScheme, typography: typography, style: style), + separatorStyles: FSeparatorStyles.inherit(colorScheme: colorScheme, style: style), + switchStyle: FSwitchStyle.inherit(colorScheme: colorScheme), + ); + } /// Returns a copy of this [FThemeData] with the given properties replaced. /// @@ -103,7 +112,8 @@ final class FThemeData with Diagnosticable { /// print(theme.colorScheme == copy.colorScheme); // true /// print(copy.typography); // bar /// ``` - @useResult FThemeData copyWith({ + @useResult + FThemeData copyWith({ FColorScheme? colorScheme, FTypography? typography, FStyle? style, diff --git a/forui/lib/src/widgets/badge/badge_content.dart b/forui/lib/src/widgets/badge/badge_content.dart index ebbb10187..5a63720fb 100644 --- a/forui/lib/src/widgets/badge/badge_content.dart +++ b/forui/lib/src/widgets/badge/badge_content.dart @@ -18,7 +18,7 @@ final class FBadgeContent extends StatelessWidget { child: Padding( padding: style.content.padding, child: DefaultTextStyle.merge( - style: style.content.labelTextStyle.scale(context.theme.typography), + style: style.content.labelTextStyle, child: switch ((label, rawLabel)) { (final String label, _) => Text(label), (_, final Widget label) => label, diff --git a/forui/lib/src/widgets/badge/badge_styles.dart b/forui/lib/src/widgets/badge/badge_styles.dart index ec5bd3610..b5fd46bc3 100644 --- a/forui/lib/src/widgets/badge/badge_styles.dart +++ b/forui/lib/src/widgets/badge/badge_styles.dart @@ -29,9 +29,8 @@ class FBadgeStyles with Diagnosticable { backgroundColor: colorScheme.primary, borderColor: colorScheme.primary, content: FBadgeContentStyle( - labelTextStyle: TextStyle( + labelTextStyle: typography.sm.copyWith( color: colorScheme.primaryForeground, - fontSize: typography.sm, fontWeight: FontWeight.w600, ), ), @@ -41,9 +40,8 @@ class FBadgeStyles with Diagnosticable { backgroundColor: colorScheme.secondary, borderColor: colorScheme.secondary, content: FBadgeContentStyle( - labelTextStyle: TextStyle( + labelTextStyle: typography.sm.copyWith( color: colorScheme.secondaryForeground, - fontSize: typography.sm, fontWeight: FontWeight.w600, ), ), @@ -53,9 +51,8 @@ class FBadgeStyles with Diagnosticable { backgroundColor: colorScheme.background, borderColor: colorScheme.border, content: FBadgeContentStyle( - labelTextStyle: TextStyle( + labelTextStyle: typography.sm.copyWith( color: colorScheme.foreground, - fontSize: typography.sm, fontWeight: FontWeight.w600, ), ), @@ -65,9 +62,8 @@ class FBadgeStyles with Diagnosticable { backgroundColor: colorScheme.destructive, borderColor: colorScheme.destructive, content: FBadgeContentStyle( - labelTextStyle: TextStyle( + labelTextStyle: typography.sm.copyWith( color: colorScheme.destructiveForeground, - fontSize: typography.sm, fontWeight: FontWeight.w600, ), ), diff --git a/forui/lib/src/widgets/button/button_content.dart b/forui/lib/src/widgets/button/button_content.dart index 34a469f5d..d58c9c4a4 100644 --- a/forui/lib/src/widgets/button/button_content.dart +++ b/forui/lib/src/widgets/button/button_content.dart @@ -17,13 +17,12 @@ final class FButtonContent extends StatelessWidget { @override Widget build(BuildContext context) { - final typography = context.theme.typography; final (:style, :enabled) = FButton._of(context); return Padding( padding: style.content.padding, child: DefaultTextStyle.merge( - style: enabled ? style.content.enabledTextStyle.scale(typography) : style.content.disabledTextStyle.scale(typography), + style: enabled ? style.content.enabledTextStyle : style.content.disabledTextStyle, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: separate([ @@ -75,13 +74,11 @@ class FButtonContentStyle with Diagnosticable { horizontal: 16, vertical: 12.5, ), - enabledTextStyle = TextStyle( - fontSize: typography.base, + enabledTextStyle = typography.base.copyWith( fontWeight: FontWeight.w500, color: enabled, ), - disabledTextStyle = TextStyle( - fontSize: typography.base, + disabledTextStyle = typography.base.copyWith( fontWeight: FontWeight.w500, color: disabled, ); diff --git a/forui/lib/src/widgets/card/card.dart b/forui/lib/src/widgets/card/card.dart index 8926f40a1..1fb722fda 100644 --- a/forui/lib/src/widgets/card/card.dart +++ b/forui/lib/src/widgets/card/card.dart @@ -71,7 +71,6 @@ final class FCard extends StatelessWidget { super.debugFillProperties(properties); properties.add(DiagnosticsProperty('style', style)); } - } /// [FCard]'s style. diff --git a/forui/lib/src/widgets/card/card_content.dart b/forui/lib/src/widgets/card/card_content.dart index bcfc8d9c4..730ba9afa 100644 --- a/forui/lib/src/widgets/card/card_content.dart +++ b/forui/lib/src/widgets/card/card_content.dart @@ -1,6 +1,7 @@ part of 'card.dart'; -@internal final class FCardContent extends StatelessWidget { +@internal +final class FCardContent extends StatelessWidget { final String? title; final Widget? rawTitle; final String? subtitle; @@ -13,28 +14,27 @@ part of 'card.dart'; this.rawTitle, this.subtitle, this.rawSubtitle, - this.child, - this.style, + 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( @@ -42,19 +42,18 @@ part of 'card.dart'; children: [ if (title != null) DefaultTextStyle.merge( - style: style.titleTextStyle.scale(typography), + style: style.titleTextStyle, child: title, ), - if (subtitle != null) DefaultTextStyle.merge( - style: style.subtitleTextStyle.scale(typography), + style: style.subtitleTextStyle, child: subtitle, ), - if (child != null) Padding( - padding: (title == null && subtitle == null) ? const EdgeInsets.only(top: 4) : const EdgeInsets.only(top: 10), + padding: + (title == null && subtitle == null) ? const EdgeInsets.only(top: 4) : const EdgeInsets.only(top: 10), child: child!, ), ], @@ -91,17 +90,13 @@ final class FCardContentStyle with Diagnosticable { }); /// Creates a [FCardContentStyle] that inherits its properties from [colorScheme] and [typography]. - FCardContentStyle.inherit({required FColorScheme colorScheme, required FTypography typography}): - titleTextStyle = TextStyle( - fontSize: typography.base, - fontWeight: FontWeight.w600, - color: colorScheme.foreground, - ), - subtitleTextStyle = TextStyle( - fontSize: typography.sm, - color: colorScheme.mutedForeground, - ), - padding = const EdgeInsets.fromLTRB(16, 12, 16, 16); + FCardContentStyle.inherit({required FColorScheme colorScheme, required FTypography typography}) + : titleTextStyle = typography.base.copyWith( + fontWeight: FontWeight.w600, + color: colorScheme.foreground, + ), + subtitleTextStyle = typography.sm.copyWith(color: colorScheme.mutedForeground), + padding = const EdgeInsets.fromLTRB(16, 12, 16, 16); /// Returns a copy of this [FCardContentStyle] with the given properties replaced. /// @@ -120,11 +115,12 @@ final class FCardContentStyle with Diagnosticable { TextStyle? titleTextStyle, TextStyle? subtitleTextStyle, EdgeInsets? padding, - }) => FCardContentStyle( - titleTextStyle: titleTextStyle ?? this.titleTextStyle, - subtitleTextStyle: subtitleTextStyle ?? this.subtitleTextStyle, - padding: padding ?? this.padding, - ); + }) => + FCardContentStyle( + titleTextStyle: titleTextStyle ?? this.titleTextStyle, + subtitleTextStyle: subtitleTextStyle ?? this.subtitleTextStyle, + padding: padding ?? this.padding, + ); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { @@ -136,11 +132,13 @@ final class FCardContentStyle with Diagnosticable { } @override - bool operator ==(Object other) => identical(this, other) || other is FCardContentStyle && - runtimeType == other.runtimeType && - titleTextStyle == other.titleTextStyle && - subtitleTextStyle == other.subtitleTextStyle && - padding == other.padding; + bool operator ==(Object other) => + identical(this, other) || + other is FCardContentStyle && + runtimeType == other.runtimeType && + titleTextStyle == other.titleTextStyle && + subtitleTextStyle == other.subtitleTextStyle && + padding == other.padding; @override int get hashCode => titleTextStyle.hashCode ^ subtitleTextStyle.hashCode ^ padding.hashCode; diff --git a/forui/lib/src/widgets/dialog/dialog.dart b/forui/lib/src/widgets/dialog/dialog.dart index 4fa8615b5..b9f9dff83 100644 --- a/forui/lib/src/widgets/dialog/dialog.dart +++ b/forui/lib/src/widgets/dialog/dialog.dart @@ -87,28 +87,27 @@ class FDialog extends StatelessWidget { Widget? rawBody, Axis direction = Axis.vertical, super.key, - }): - 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 (direction) { - Axis.horizontal => (context, style) => FHorizontalDialogContent( - style: style.horizontal, - title: title, - rawTitle: rawTitle, - body: body, - rawBody: rawBody, - actions: actions, - ), - Axis.vertical => (context, style) => FVerticalDialogContent( - style: style.vertical, - title: title, - rawTitle: rawTitle, - body: body, - rawBody: rawBody, - actions: actions, - ), - }; + }) : 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 (direction) { + Axis.horizontal => (context, style) => FHorizontalDialogContent( + style: style.horizontal, + title: title, + rawTitle: rawTitle, + body: body, + rawBody: rawBody, + actions: actions, + ), + Axis.vertical => (context, style) => FVerticalDialogContent( + style: style.vertical, + title: title, + rawTitle: rawTitle, + body: body, + rawBody: rawBody, + actions: actions, + ), + }; /// Creates a [FDialog] with a custom builder. const FDialog.raw({ @@ -123,8 +122,8 @@ class FDialog extends StatelessWidget { @override Widget build(BuildContext context) { final theme = context.theme; - final style = this.style ?? theme.dialogStyle; final typography = theme.typography; + final style = this.style ?? theme.dialogStyle; return AnimatedPadding( padding: MediaQuery.viewInsetsOf(context) + style.insetPadding, @@ -138,10 +137,7 @@ class FDialog extends StatelessWidget { context: context, child: Align( child: DefaultTextStyle( - style: context.theme.typography.toTextStyle( - fontSize: typography.base, - color: context.theme.colorScheme.foreground, - ), + style: typography.base.copyWith(color: theme.colorScheme.foreground), child: Semantics( scopesRoute: true, explicitChildNodes: true, @@ -169,7 +165,8 @@ class FDialog extends StatelessWidget { super.debugFillProperties(properties); properties ..add(DiagnosticsProperty('style', style)) - ..add(DiagnosticsProperty('insetAnimationDuration', insetAnimationDuration, defaultValue: const Duration(milliseconds: 100))) + ..add(DiagnosticsProperty('insetAnimationDuration', insetAnimationDuration, + defaultValue: const Duration(milliseconds: 100))) ..add(DiagnosticsProperty('insetAnimationCurve', insetAnimationCurve, defaultValue: Curves.decelerate)) ..add(StringProperty('semanticLabel', semanticLabel)) ..add(DiagnosticsProperty('builder', builder)); @@ -207,26 +204,26 @@ final class FDialogStyle with Diagnosticable { }); /// Creates a [FDialogStyle] that inherits its properties from the given [style], [colorScheme], and [typography]. - FDialogStyle.inherit({required FStyle style, required FColorScheme colorScheme, required FTypography typography}): - decoration = BoxDecoration( - borderRadius: style.borderRadius, - color: colorScheme.background, - ), - insetPadding = const EdgeInsets.symmetric(horizontal: 40, vertical: 24), - horizontal = FDialogContentStyle.inherit( - colorScheme: colorScheme, - typography: typography, - padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 25), - actionPadding: 7, - ), - vertical = FDialogContentStyle.inherit( - colorScheme: colorScheme, - typography: typography, - padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 25), - actionPadding: 8, - ), - minWidth = 280, - maxWidth = 560; + FDialogStyle.inherit({required FStyle style, required FColorScheme colorScheme, required FTypography typography}) + : decoration = BoxDecoration( + borderRadius: style.borderRadius, + color: colorScheme.background, + ), + insetPadding = const EdgeInsets.symmetric(horizontal: 40, vertical: 24), + horizontal = FDialogContentStyle.inherit( + colorScheme: colorScheme, + typography: typography, + padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 25), + actionPadding: 7, + ), + vertical = FDialogContentStyle.inherit( + colorScheme: colorScheme, + typography: typography, + padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 25), + actionPadding: 8, + ), + minWidth = 280, + maxWidth = 560; /// Returns a copy of this [FButtonCustomStyle] with the given properties replaced. /// @@ -244,21 +241,23 @@ final class FDialogStyle with Diagnosticable { /// print(copy.minWidth); // 1 /// print(copy.maxWidth); // 3 /// ``` - @useResult FDialogStyle copyWith({ + @useResult + FDialogStyle copyWith({ BoxDecoration? decoration, EdgeInsets? insetPadding, FDialogContentStyle? horizontal, FDialogContentStyle? vertical, double? minWidth, double? maxWidth, - }) => FDialogStyle( - decoration: decoration ?? this.decoration, - insetPadding: insetPadding ?? this.insetPadding, - horizontal: horizontal ?? this.horizontal, - vertical: vertical ?? this.vertical, - minWidth: minWidth ?? this.minWidth, - maxWidth: maxWidth ?? this.maxWidth, - ); + }) => + FDialogStyle( + decoration: decoration ?? this.decoration, + insetPadding: insetPadding ?? this.insetPadding, + horizontal: horizontal ?? this.horizontal, + vertical: vertical ?? this.vertical, + minWidth: minWidth ?? this.minWidth, + maxWidth: maxWidth ?? this.maxWidth, + ); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { diff --git a/forui/lib/src/widgets/dialog/dialog_content.dart b/forui/lib/src/widgets/dialog/dialog_content.dart index a3d440f83..f3be1af91 100644 --- a/forui/lib/src/widgets/dialog/dialog_content.dart +++ b/forui/lib/src/widgets/dialog/dialog_content.dart @@ -1,6 +1,7 @@ part of 'dialog.dart'; -@internal sealed class FDialogContent extends StatelessWidget { +@internal +sealed class FDialogContent extends StatelessWidget { final FDialogContentStyle style; final CrossAxisAlignment alignment; final String? title; @@ -12,7 +13,7 @@ part of 'dialog.dart'; final List actions; const FDialogContent({ - required this.style, + required this.style, required this.alignment, required this.title, required this.titleTextAlign, @@ -23,23 +24,23 @@ part of 'dialog.dart'; 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, @@ -54,7 +55,7 @@ part of 'dialog.dart'; container: true, child: DefaultTextStyle.merge( textAlign: titleTextAlign, - style: style.titleTextStyle.scale(typography), + style: style.titleTextStyle, child: title, ), ), @@ -66,7 +67,7 @@ part of 'dialog.dart'; container: true, child: DefaultTextStyle.merge( textAlign: bodyTextAlign, - style: style.bodyTextStyle.scale(typography), + style: style.bodyTextStyle, child: body, ), ), @@ -77,7 +78,7 @@ part of 'dialog.dart'; ), ); } - + Widget _actions(BuildContext context); @override @@ -94,7 +95,8 @@ part of 'dialog.dart'; } } -@internal class FHorizontalDialogContent extends FDialogContent { +@internal +class FHorizontalDialogContent extends FDialogContent { const FHorizontalDialogContent({ required super.style, required super.title, @@ -102,29 +104,22 @@ part of 'dialog.dart'; required super.body, required super.rawBody, required super.actions, - }): super( - alignment: CrossAxisAlignment.start, - titleTextAlign: TextAlign.start, - bodyTextAlign: TextAlign.start - ); + }) : super(alignment: CrossAxisAlignment.start, titleTextAlign: TextAlign.start, bodyTextAlign: TextAlign.start); @override Widget _actions(BuildContext context) => Row( - mainAxisAlignment: MainAxisAlignment.end, - children: separate( - [ - for (final action in actions) - IntrinsicWidth( - child: action, - ), - ], - by: [ SizedBox(width: style.actionPadding) ], - ), - ); + mainAxisAlignment: MainAxisAlignment.end, + children: separate( + [ + for (final action in actions) IntrinsicWidth(child: action), + ], + by: [SizedBox(width: style.actionPadding)], + ), + ); } - -@internal class FVerticalDialogContent extends FDialogContent { +@internal +class FVerticalDialogContent extends FDialogContent { const FVerticalDialogContent({ required super.style, required super.title, @@ -132,20 +127,16 @@ part of 'dialog.dart'; required super.body, required super.rawBody, required super.actions, - }): super( - alignment: CrossAxisAlignment.center, - titleTextAlign: TextAlign.center, - bodyTextAlign: TextAlign.center - ); + }) : super(alignment: CrossAxisAlignment.center, titleTextAlign: TextAlign.center, bodyTextAlign: TextAlign.center); @override Widget _actions(BuildContext context) => Column( - mainAxisSize: MainAxisSize.min, - children: separate( - actions, - by: [ SizedBox(height: style.actionPadding) ], - ), - ); + mainAxisSize: MainAxisSize.min, + children: separate( + actions, + by: [SizedBox(height: style.actionPadding)], + ), + ); } /// The dialog content's style. @@ -161,7 +152,7 @@ final class FDialogContentStyle with Diagnosticable { /// The space between actions. final double actionPadding; - + /// Creates a [FDialogContentStyle]. FDialogContentStyle({ required this.titleTextStyle, @@ -169,23 +160,18 @@ final class FDialogContentStyle with Diagnosticable { required this.padding, required this.actionPadding, }); - + /// Creates a [FDialogContentStyle] that inherits its properties from [colorScheme] and [typography]. FDialogContentStyle.inherit({ required FColorScheme colorScheme, required FTypography typography, required this.padding, required this.actionPadding, - }): - titleTextStyle = TextStyle( - fontSize: typography.lg, - fontWeight: FontWeight.w600, - color: colorScheme.foreground, - ), - bodyTextStyle = TextStyle( - fontSize: typography.sm, - color: colorScheme.mutedForeground, - ); + }) : titleTextStyle = typography.lg.copyWith( + fontWeight: FontWeight.w600, + color: colorScheme.foreground, + ), + bodyTextStyle = typography.sm.copyWith(color: colorScheme.mutedForeground); /// Returns a copy of this [FDialogContentStyle] with the given properties replaced. /// @@ -203,17 +189,19 @@ final class FDialogContentStyle with Diagnosticable { /// print(style.titleTextStyle == copy.titleTextStyle); // true /// print(style.bodyTextStyle == copy.bodyTextStyle); // false /// ``` - @useResult FDialogContentStyle copyWith({ + @useResult + FDialogContentStyle copyWith({ TextStyle? titleTextStyle, TextStyle? bodyTextStyle, EdgeInsets? padding, double? actionPadding, - }) => FDialogContentStyle( - titleTextStyle: titleTextStyle ?? this.titleTextStyle, - bodyTextStyle: bodyTextStyle ?? this.bodyTextStyle, - padding: padding ?? this.padding, - actionPadding: actionPadding ?? this.actionPadding, - ); + }) => + FDialogContentStyle( + titleTextStyle: titleTextStyle ?? this.titleTextStyle, + bodyTextStyle: bodyTextStyle ?? this.bodyTextStyle, + padding: padding ?? this.padding, + actionPadding: actionPadding ?? this.actionPadding, + ); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { diff --git a/forui/lib/src/widgets/header/header.dart b/forui/lib/src/widgets/header/header.dart index bcbc476b7..cc446ed91 100644 --- a/forui/lib/src/widgets/header/header.dart +++ b/forui/lib/src/widgets/header/header.dart @@ -73,7 +73,7 @@ class FHeader extends StatelessWidget { overflow: TextOverflow.fade, maxLines: 1, softWrap: false, - style: style.titleTextStyle.scale(typography), + style: style.titleTextStyle, child: title, ), ), @@ -105,8 +105,7 @@ final class FHeaderStyle with Diagnosticable { /// Creates a [FHeaderStyle] that inherits its properties from the given [FColorScheme] and [FTypography]. FHeaderStyle.inherit({required FColorScheme colorScheme, required FTypography typography}) - : titleTextStyle = TextStyle( - fontSize: typography.xl3, + : titleTextStyle = typography.xl3.copyWith( fontWeight: FontWeight.w700, color: colorScheme.foreground, ), diff --git a/forui/lib/src/widgets/text_field/text_field.dart b/forui/lib/src/widgets/text_field/text_field.dart index 2db69ba41..c6f10128a 100644 --- a/forui/lib/src/widgets/text_field/text_field.dart +++ b/forui/lib/src/widgets/text_field/text_field.dart @@ -775,7 +775,7 @@ final class FTextField extends StatelessWidget { Padding( padding: const EdgeInsets.only(top: 4, bottom: 7), child: DefaultTextStyle.merge( - style: stateStyle.labelTextStyle.scale(typography), + style: stateStyle.labelTextStyle, child: label, ), ), @@ -822,12 +822,12 @@ final class FTextField extends StatelessWidget { ) { final rawError = this.rawError == null ? this.rawError : DefaultTextStyle.merge( - style: current.footerTextStyle.scale(typography), + style: current.footerTextStyle, child: this.rawError!, ); final rawHelp = this.rawHelp == null ? this.rawHelp : DefaultTextStyle.merge( - style: current.footerTextStyle.scale(typography), + style: current.footerTextStyle, child: this.rawHelp!, ); @@ -842,15 +842,15 @@ final class FTextField extends StatelessWidget { prefix: Padding(padding: EdgeInsets.only(left: style.contentPadding.left)), contentPadding: style.contentPadding.copyWith(left: 0), hintText: hint, - hintStyle: current.hintTextStyle.scale(typography), + hintStyle: current.hintTextStyle, hintMaxLines: hintMaxLines, helper: rawHelp, helperText: help, - helperStyle: current.footerTextStyle.scale(typography), + helperStyle: current.footerTextStyle, helperMaxLines: helpMaxLines, error: rawError, errorText: error, - errorStyle: current.footerTextStyle.scale(typography), + errorStyle: current.footerTextStyle, errorMaxLines: errorMaxLines, disabledBorder: OutlineInputBorder( borderSide: BorderSide( @@ -891,7 +891,7 @@ final class FTextField extends StatelessWidget { keyboardType: keyboardType, textInputAction: textInputAction, textCapitalization: textCapitalization, - style: current.contentTextStyle.scale(typography), + style: current.contentTextStyle, textAlign: textAlign, textAlignVertical: textAlignVertical, textDirection: textDirection, diff --git a/forui/lib/src/widgets/text_field/text_field_style.dart b/forui/lib/src/widgets/text_field/text_field_style.dart index 01b2dad06..1c7b97a8f 100644 --- a/forui/lib/src/widgets/text_field/text_field_style.dart +++ b/forui/lib/src/widgets/text_field/text_field_style.dart @@ -12,8 +12,9 @@ final class FTextFieldStyle with Diagnosticable { /// The cursor indicates the current location of text insertion point in the field. final Color cursorColor; - /// The padding surrounding this text field's content. Defaults to - /// `const EdgeInsets.symmetric(horizontal: 15, vertical: 5)`. + /// The padding surrounding this text field's content. + /// + /// Defaults to `const EdgeInsets.symmetric(horizontal: 15, vertical: 5)`. final EdgeInsets contentPadding; /// Configures padding to edges surrounding a [Scrollable] when this text field scrolls into view. @@ -199,24 +200,20 @@ final class FTextFieldStateStyle with Diagnosticable { required FTypography typography, required FStyle style, }): - labelTextStyle = TextStyle( + labelTextStyle = typography.sm.copyWith( color: labelColor, - fontSize: typography.sm, fontWeight: FontWeight.w600, ), - contentTextStyle = TextStyle( + contentTextStyle = typography.sm.copyWith( fontFamily: typography.defaultFontFamily, - fontSize: typography.sm, color: contentColor, ), - hintTextStyle = TextStyle( + hintTextStyle = typography.sm.copyWith( fontFamily: typography.defaultFontFamily, - fontSize: typography.sm, color: hintColor, ), - footerTextStyle = TextStyle( + footerTextStyle = typography.sm.copyWith( fontFamily: typography.defaultFontFamily, - fontSize: typography.sm, color: footerColor, ), focused = FTextFieldBorderStyle.inherit(color: focusedBorderColor, style: style), diff --git a/forui/test/src/theme/typography_test.dart b/forui/test/src/theme/typography_test.dart index 18ad36cc9..a878abe42 100644 --- a/forui/test/src/theme/typography_test.dart +++ b/forui/test/src/theme/typography_test.dart @@ -7,153 +7,207 @@ import 'package:forui/forui.dart'; void main() { group('FTypography', () { - const typography = FTypography( - defaultFontFamily: 'Roboto', - sizeScalar: 2, - letterSpacingScalar: 3, - wordSpacingScalar: 4, - heightScalar: 5, - ); + FTypography typography = const FTypography(); + + setUp(() { + typography = const FTypography( + defaultFontFamily: 'Roboto', + xs: TextStyle(fontSize: 1), + sm: TextStyle(fontSize: 2), + base: TextStyle(fontSize: 3), + lg: TextStyle(fontSize: 4), + xl: TextStyle(fontSize: 5), + xl2: TextStyle(fontSize: 6), + xl3: TextStyle(fontSize: 7), + xl4: TextStyle(fontSize: 8), + xl5: TextStyle(fontSize: 9), + xl6: TextStyle(fontSize: 10), + xl7: TextStyle(fontSize: 11), + xl8: TextStyle(fontSize: 12), + ); + }); group('constructor', () { test('no arguments', () { const typography = FTypography(); + expect(typography.defaultFontFamily, 'packages/forui/Inter'); - expect(typography.sizeScalar, 1); - expect(typography.letterSpacingScalar, 1); - expect(typography.wordSpacingScalar, 1); - expect(typography.heightScalar, 1); + expect(typography.xs, const TextStyle(fontSize: 12, height: 1)); + expect(typography.sm, const TextStyle(fontSize: 14, height: 1.25)); + expect(typography.base, const TextStyle(fontSize: 16, height: 1.5)); + expect(typography.lg, const TextStyle(fontSize: 18, height: 1.75)); + expect(typography.xl, const TextStyle(fontSize: 20, height: 1.75)); + expect(typography.xl2, const TextStyle(fontSize: 22, height: 2)); + expect(typography.xl3, const TextStyle(fontSize: 30, height: 2.25)); + expect(typography.xl4, const TextStyle(fontSize: 36, height: 2.5)); + expect(typography.xl5, const TextStyle(fontSize: 48, height: 1)); + expect(typography.xl6, const TextStyle(fontSize: 60, height: 1)); + expect(typography.xl7, const TextStyle(fontSize: 72, height: 1)); + expect(typography.xl8, const TextStyle(fontSize: 96, height: 1)); }); test('blank font family', () => expect(() => FTypography(defaultFontFamily: ''), throwsAssertionError)); + }); - test('sizeScalar is 0', () => expect(() => FTypography(sizeScalar: 0), throwsAssertionError)); - - test('sizeScalar is NaN', () => expect(() => FTypography(sizeScalar: double.nan), throwsAssertionError)); - - test('letterSpacingScalar is 0', () => expect(() => FTypography(letterSpacingScalar: 0), throwsAssertionError)); - - test('letterSpacingScalar is NaN', - () => expect(() => FTypography(letterSpacingScalar: double.nan), throwsAssertionError)); - - test('wordSpacingScalar is 0', () => expect(() => FTypography(wordSpacingScalar: 0), throwsAssertionError)); + group('inherit constructor', () { + const colorScheme = FColorScheme( + brightness: Brightness.light, + background: Colors.black, + foreground: Colors.black12, + primary: Colors.black26, + primaryForeground: Colors.black38, + secondary: Colors.black45, + secondaryForeground: Colors.black54, + muted: Colors.black87, + mutedForeground: Colors.blue, + destructive: Colors.blueAccent, + destructiveForeground: Colors.blueGrey, + error: Colors.red, + errorForeground: Colors.redAccent, + border: Colors.lightBlue, + ); - test('wordSpacingScalar is NaN', () => expect(() => FTypography(wordSpacingScalar: double.nan), throwsAssertionError)); + test('no arguments', () { + typography = FTypography.inherit(colorScheme: colorScheme); - test('heightScalar is 0', () => expect(() => FTypography(heightScalar: 0), throwsAssertionError)); + expect(typography.defaultFontFamily, 'packages/forui/Inter'); + expect(typography.xs, TextStyle(color: colorScheme.foreground, fontSize: 12, height: 1)); + expect(typography.sm, TextStyle(color: colorScheme.foreground, fontSize: 14, height: 1.25)); + expect(typography.base, TextStyle(color: colorScheme.foreground, fontSize: 16, height: 1.5)); + expect(typography.lg, TextStyle(color: colorScheme.foreground, fontSize: 18, height: 1.75)); + expect(typography.xl, TextStyle(color: colorScheme.foreground, fontSize: 20, height: 1.75)); + expect(typography.xl2, TextStyle(color: colorScheme.foreground, fontSize: 22, height: 2)); + expect(typography.xl3, TextStyle(color: colorScheme.foreground, fontSize: 30, height: 2.25)); + expect(typography.xl4, TextStyle(color: colorScheme.foreground, fontSize: 36, height: 2.5)); + expect(typography.xl5, TextStyle(color: colorScheme.foreground, fontSize: 48, height: 1)); + expect(typography.xl6, TextStyle(color: colorScheme.foreground, fontSize: 60, height: 1)); + expect(typography.xl7, TextStyle(color: colorScheme.foreground, fontSize: 72, height: 1)); + expect(typography.xl8, TextStyle(color: colorScheme.foreground, fontSize: 96, height: 1)); + }); - test('heightScalar is NaN', () => expect(() => FTypography(heightScalar: double.nan), throwsAssertionError)); + test( + 'blank font family', + () => expect( + () => FTypography.inherit( + colorScheme: colorScheme, + defaultFontFamily: '', + ), + throwsAssertionError, + ), + ); }); - // TODO: scale function. - - group('copyWith(...)', () { + group('scale(...)', () { test('no arguments', () { - typography.copyWith(); + typography = typography.scale(); expect(typography.defaultFontFamily, 'Roboto'); - expect(typography.sizeScalar, 2); - expect(typography.letterSpacingScalar, 3); - expect(typography.wordSpacingScalar, 4); - expect(typography.heightScalar, 5); + expect(typography.xs, const TextStyle(fontSize: 1)); + expect(typography.sm, const TextStyle(fontSize: 2)); + expect(typography.base, const TextStyle(fontSize: 3)); + expect(typography.lg, const TextStyle(fontSize: 4)); + expect(typography.xl, const TextStyle(fontSize: 5)); + expect(typography.xl2, const TextStyle(fontSize: 6)); + expect(typography.xl3, const TextStyle(fontSize: 7)); + expect(typography.xl4, const TextStyle(fontSize: 8)); + expect(typography.xl5, const TextStyle(fontSize: 9)); + expect(typography.xl6, const TextStyle(fontSize: 10)); + expect(typography.xl7, const TextStyle(fontSize: 11)); + expect(typography.xl8, const TextStyle(fontSize: 12)); }); test('all arguments', () { - final typography = const FTypography().copyWith( - defaultFontFamily: 'Roboto', - sizeScalar: 2, - letterSpacingScalar: 3, - wordSpacingScalar: 4, - heightScalar: 5, - ); + typography = typography.scale(sizeScalar: 10); expect(typography.defaultFontFamily, 'Roboto'); - expect(typography.sizeScalar, 2); - expect(typography.letterSpacingScalar, 3); - expect(typography.wordSpacingScalar, 4); - expect(typography.heightScalar, 5); + expect(typography.xs, const TextStyle(fontSize: 10)); + expect(typography.sm, const TextStyle(fontSize: 20)); + expect(typography.base, const TextStyle(fontSize: 30)); + expect(typography.lg, const TextStyle(fontSize: 40)); + expect(typography.xl, const TextStyle(fontSize: 50)); + expect(typography.xl2, const TextStyle(fontSize: 60)); + expect(typography.xl3, const TextStyle(fontSize: 70)); + expect(typography.xl4, const TextStyle(fontSize: 80)); + expect(typography.xl5, const TextStyle(fontSize: 90)); + expect(typography.xl6, const TextStyle(fontSize: 100)); + expect(typography.xl7, const TextStyle(fontSize: 110)); + expect(typography.xl8, const TextStyle(fontSize: 120)); }); }); - group('toTextStyle(...)', () { + group('copyWith(...)', () { test('no arguments', () { - final style = typography.toTextStyle(); - - expect(style.fontFamily, 'Roboto'); - expect(style.fontSize, null); - expect(style.letterSpacing, null); - expect(style.wordSpacing, null); - expect(style.height, null); - }); - - test('scaled arguments', () { - final style = typography.toTextStyle( - fontSize: 7, - letterSpacing: 11, - wordSpacing: 13, - height: 17, - ); + typography = const FTypography(defaultFontFamily: 'Roboto'); + typography = typography.copyWith(); - expect(style.fontFamily, 'Roboto'); - expect(style.fontSize, 14); - expect(style.letterSpacing, 33); - expect(style.wordSpacing, 52); - expect(style.height, 85); + expect(typography.defaultFontFamily, 'Roboto'); + expect(typography.xs, const TextStyle(fontSize: 12, height: 1)); + expect(typography.sm, const TextStyle(fontSize: 14, height: 1.25)); + expect(typography.base, const TextStyle(fontSize: 16, height: 1.5)); + expect(typography.lg, const TextStyle(fontSize: 18, height: 1.75)); + expect(typography.xl, const TextStyle(fontSize: 20, height: 1.75)); + expect(typography.xl2, const TextStyle(fontSize: 22, height: 2)); + expect(typography.xl3, const TextStyle(fontSize: 30, height: 2.25)); + expect(typography.xl4, const TextStyle(fontSize: 36, height: 2.5)); + expect(typography.xl5, const TextStyle(fontSize: 48, height: 1)); + expect(typography.xl6, const TextStyle(fontSize: 60, height: 1)); + expect(typography.xl7, const TextStyle(fontSize: 72, height: 1)); + expect(typography.xl8, const TextStyle(fontSize: 96, height: 1)); }); - test('other arguments', () { - final style = typography.toTextStyle( - color: const Color(0xFF000000), + test('all arguments', () { + final typography = const FTypography().copyWith( + defaultFontFamily: 'AnotherFont', + xs: const TextStyle(fontSize: 1), + sm: const TextStyle(fontSize: 2), + base: const TextStyle(fontSize: 3), + lg: const TextStyle(fontSize: 4), + xl: const TextStyle(fontSize: 5), + xl2: const TextStyle(fontSize: 6), + xl3: const TextStyle(fontSize: 7), + xl4: const TextStyle(fontSize: 8), + xl5: const TextStyle(fontSize: 9), + xl6: const TextStyle(fontSize: 10), + xl7: const TextStyle(fontSize: 11), + xl8: const TextStyle(fontSize: 12), ); - expect(style.color, const Color(0xFF000000)); + expect(typography.defaultFontFamily, 'AnotherFont'); + expect(typography.xs, const TextStyle(fontSize: 1)); + expect(typography.sm, const TextStyle(fontSize: 2)); + expect(typography.base, const TextStyle(fontSize: 3)); + expect(typography.lg, const TextStyle(fontSize: 4)); + expect(typography.xl, const TextStyle(fontSize: 5)); + expect(typography.xl2, const TextStyle(fontSize: 6)); + expect(typography.xl3, const TextStyle(fontSize: 7)); + expect(typography.xl4, const TextStyle(fontSize: 8)); + expect(typography.xl5, const TextStyle(fontSize: 9)); + expect(typography.xl6, const TextStyle(fontSize: 10)); + expect(typography.xl7, const TextStyle(fontSize: 11)); + expect(typography.xl8, const TextStyle(fontSize: 12)); }); }); test('debugFillProperties', () { - const font = FTypography( - defaultFontFamily: 'Roboto', - sizeScalar: 2, - letterSpacingScalar: 3, - wordSpacingScalar: 4, - heightScalar: 5, - xs: 6, - sm: 7, - base: 8, - lg: 9, - xl: 10, - xl2: 11, - xl3: 12, - xl4: 13, - xl5: 14, - xl6: 15, - xl7: 16, - xl8: 17, - ); - final builder = DiagnosticPropertiesBuilder(); - font.debugFillProperties(builder); + typography.debugFillProperties(builder); expect( builder.properties.map((p) => p.toString()), [ StringProperty('family', 'Roboto'), - DoubleProperty('sizeScalar', 2), - DoubleProperty('letterSpacingScalar', 3), - DoubleProperty('wordSpacingScalar', 4), - DoubleProperty('heightScalar', 5), - DoubleProperty('xs', 6), - DoubleProperty('sm', 7), - DoubleProperty('base', 8), - DoubleProperty('lg', 9), - DoubleProperty('xl', 10), - DoubleProperty('xl2', 11), - DoubleProperty('xl3', 12), - DoubleProperty('xl4', 13), - DoubleProperty('xl5', 14), - DoubleProperty('xl6', 15), - DoubleProperty('xl7', 16), - DoubleProperty('xl8', 17), + DiagnosticsProperty('xs', const TextStyle(fontSize: 1)), + DiagnosticsProperty('sm', const TextStyle(fontSize: 2)), + DiagnosticsProperty('base', const TextStyle(fontSize: 3)), + DiagnosticsProperty('lg', const TextStyle(fontSize: 4)), + DiagnosticsProperty('xl', const TextStyle(fontSize: 5)), + DiagnosticsProperty('xl2', const TextStyle(fontSize: 6)), + DiagnosticsProperty('xl3', const TextStyle(fontSize: 7)), + DiagnosticsProperty('xl4', const TextStyle(fontSize: 8)), + DiagnosticsProperty('xl5', const TextStyle(fontSize: 9)), + DiagnosticsProperty('xl6', const TextStyle(fontSize: 10)), + DiagnosticsProperty('xl7', const TextStyle(fontSize: 11)), + DiagnosticsProperty('xl8', const TextStyle(fontSize: 12)), ].map((p) => p.toString())); }); @@ -171,32 +225,4 @@ void main() { }); }); }); - - group('FontTextStyle', () { - const font = FTypography( - defaultFontFamily: 'Roboto', - sizeScalar: 2, - letterSpacingScalar: 3, - wordSpacingScalar: 4, - heightScalar: 5, - ); - - test('scale(...)', () { - final style = const TextStyle( - color: Colors.blueAccent, - fontFamily: 'default-font', - fontSize: 7, - letterSpacing: 11, - wordSpacing: 13, - height: 17, - ).scale(font); - - expect(style.color, Colors.blueAccent); - expect(style.fontFamily, 'default-font'); - expect(style.fontSize, 14); - expect(style.letterSpacing, 33); - expect(style.wordSpacing, 52); - expect(style.height, 85); - }); - }); }