diff --git a/demo/lib/components/alert.dart b/demo/lib/components/alert.dart new file mode 100644 index 0000000..1f67ccf --- /dev/null +++ b/demo/lib/components/alert.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; +import 'package:mix/mix.dart'; +import 'package:remix_ui/remix_ui.dart'; +import 'package:widgetbook/widgetbook.dart'; +import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; + +@widgetbook.UseCase( + name: 'interactive playground', + type: RemixAlert, +) +Widget buildCheckboxUseCase(BuildContext context) { + return Center( + child: SizedBox( + width: 300, + child: RemixAlert( + title: StyledText( + context.knobs.string( + label: 'Title', + initialValue: 'Error', + ), + ), + subtitle: StyledText( + context.knobs.string( + label: 'Subtitle', + initialValue: 'Your session has expired. Please log in again.', + ), + ), + leading: context.knobs.boolean( + label: 'Leading', + initialValue: false, + ) + ? const StyledIcon(Icons.warning_amber_rounded) + : null, + ), + ), + ); +} diff --git a/demo/lib/main.directories.g.dart b/demo/lib/main.directories.g.dart index 93d420c..8b13789 100644 --- a/demo/lib/main.directories.g.dart +++ b/demo/lib/main.directories.g.dart @@ -1,137 +1 @@ -// coverage:ignore-file -// ignore_for_file: type=lint -// ignore_for_file: unused_import, prefer_relative_imports, directives_ordering -// GENERATED CODE - DO NOT MODIFY BY HAND - -// ************************************************************************** -// AppGenerator -// ************************************************************************** - -// ignore_for_file: no_leading_underscores_for_library_prefixes -import 'package:demo/components/avatar.dart' as _i2; -import 'package:demo/components/badge.dart' as _i3; -import 'package:demo/components/button.dart' as _i4; -import 'package:demo/components/card.dart' as _i5; -import 'package:demo/components/checkbox.dart' as _i6; -import 'package:demo/components/divider.dart' as _i7; -import 'package:demo/components/list_tile.dart' as _i8; -import 'package:demo/components/radio.dart' as _i9; -import 'package:demo/components/switch.dart' as _i10; -import 'package:widgetbook/widgetbook.dart' as _i1; - -final directories = <_i1.WidgetbookNode>[ - _i1.WidgetbookFolder( - name: 'components', - children: [ - _i1.WidgetbookFolder( - name: 'avatar', - children: [ - _i1.WidgetbookLeafComponent( - name: 'RemixAvatar', - useCase: _i1.WidgetbookUseCase( - name: 'interactive playground', - builder: _i2.buildCheckboxUseCase, - ), - ) - ], - ), - _i1.WidgetbookFolder( - name: 'badge', - children: [ - _i1.WidgetbookLeafComponent( - name: 'RemixBadge', - useCase: _i1.WidgetbookUseCase( - name: 'interactive playground', - builder: _i3.buildCheckboxUseCase, - ), - ) - ], - ), - _i1.WidgetbookFolder( - name: 'button', - children: [ - _i1.WidgetbookLeafComponent( - name: 'RemixButton', - useCase: _i1.WidgetbookUseCase( - name: 'interactive playground', - builder: _i4.buildButtonUseCase, - ), - ) - ], - ), - _i1.WidgetbookFolder( - name: 'card', - children: [ - _i1.WidgetbookLeafComponent( - name: 'RemixCard', - useCase: _i1.WidgetbookUseCase( - name: 'interactive playground', - builder: _i5.buildCheckboxUseCase, - ), - ) - ], - ), - _i1.WidgetbookFolder( - name: 'checkbox', - children: [ - _i1.WidgetbookLeafComponent( - name: 'RemixCheckbox', - useCase: _i1.WidgetbookUseCase( - name: 'interactive playground', - builder: _i6.buildCheckboxUseCase, - ), - ) - ], - ), - _i1.WidgetbookFolder( - name: 'divider', - children: [ - _i1.WidgetbookLeafComponent( - name: 'RemixDivider', - useCase: _i1.WidgetbookUseCase( - name: 'interactive playground', - builder: _i7.buildCheckboxUseCase, - ), - ) - ], - ), - _i1.WidgetbookFolder( - name: 'list_tile', - children: [ - _i1.WidgetbookLeafComponent( - name: 'RemixListTile', - useCase: _i1.WidgetbookUseCase( - name: 'interactive playground', - builder: _i8.buildCheckboxUseCase, - ), - ) - ], - ), - _i1.WidgetbookFolder( - name: 'radio', - children: [ - _i1.WidgetbookLeafComponent( - name: 'RemixRadio', - useCase: _i1.WidgetbookUseCase( - name: 'interactive playground', - builder: _i9.buildRadioUseCase, - ), - ) - ], - ), - _i1.WidgetbookFolder( - name: 'switch', - children: [ - _i1.WidgetbookLeafComponent( - name: 'RemixSwitch', - useCase: _i1.WidgetbookUseCase( - name: 'interactive playground', - builder: _i10.buildRadioUseCase, - ), - ) - ], - ), - ], - ) -]; diff --git a/lib/components/alert/alert.dart b/lib/components/alert/alert.dart new file mode 100644 index 0000000..d850403 --- /dev/null +++ b/lib/components/alert/alert.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; +import 'package:mix/mix.dart'; +import 'package:remix_ui/components/alert/alert.style.dart'; +import 'package:remix_ui/components/card/card.style.dart'; + +import '../../utils/component_recipe.dart'; + +class RemixAlert extends StatelessWidget + implements RemixComponentRecipe { + const RemixAlert({ + super.key, + this.leading, + this.title, + this.subtitle, + this.style, + this.variants = const [], + }); + + final Widget? leading; + final Widget? title; + final Widget? subtitle; + + @override + final AlertStyles? style; + + @override + final List variants; + + AlertStyles buildStyle(List variants) { + final result = style == null ? AlertStyles.base() : style!; + return result.applyVariants(variants); + } + + @override + Widget build(BuildContext context) { + final style = buildStyle(variants); + + return HBox( + style: style.outerRowContainer, + children: [ + if (leading != null) + MixProvider.build( + context, + style: style.icon, + builder: (_) => leading!, + ), + VBox( + style: style.innerColumnContainer, + children: [ + if (title != null) + MixProvider.build( + context, + style: style.title, + builder: (_) => title!, + ), + if (subtitle != null) + MixProvider.build( + context, + style: style.subtitle, + builder: (_) => subtitle!, + ), + ], + ), + ], + ); + } +} diff --git a/lib/components/alert/alert.style.dart b/lib/components/alert/alert.style.dart new file mode 100644 index 0000000..e9bb26a --- /dev/null +++ b/lib/components/alert/alert.style.dart @@ -0,0 +1,104 @@ +import 'package:mix/mix.dart'; + +class AlertStyles extends StyleRecipe { + const AlertStyles({ + this.outerRowContainer = const Style.empty(), + this.innerColumnContainer = const Style.empty(), + this.title = const Style.empty(), + this.subtitle = const Style.empty(), + this.icon = const Style.empty(), + }); + + final Style outerRowContainer; + final Style innerColumnContainer; + final Style title; + final Style subtitle; + final Style icon; + + factory AlertStyles.base() { + return AlertStyles( + outerRowContainer: _outerRowContainer(), + innerColumnContainer: _innerColumnContainer(), + title: _title(), + subtitle: _subtitle(), + icon: _icon(), + ); + } + + @override + AlertStyles applyVariants(List variants) { + return AlertStyles( + outerRowContainer: outerRowContainer.applyVariants(variants), + innerColumnContainer: innerColumnContainer.applyVariants(variants), + title: title.applyVariants(variants), + subtitle: subtitle.applyVariants(variants), + icon: icon.applyVariants(variants), + ); + } + + @override + AlertStyles merge(AlertStyles? other) { + if (other == null) return this; + return copyWith( + outerRowContainer: outerRowContainer.merge(other.outerRowContainer), + innerColumnContainer: + innerColumnContainer.merge(other.innerColumnContainer), + title: title.merge(other.title), + subtitle: subtitle.merge(other.subtitle), + icon: icon.merge(other.icon), + ); + } + + @override + AlertStyles copyWith({ + Style? outerRowContainer, + Style? innerColumnContainer, + Style? title, + Style? subtitle, + Style? icon, + }) { + return AlertStyles( + outerRowContainer: outerRowContainer ?? this.outerRowContainer, + innerColumnContainer: innerColumnContainer ?? this.innerColumnContainer, + title: title ?? this.title, + subtitle: subtitle ?? this.subtitle, + icon: icon ?? this.icon, + ); + } +} + +Style _outerRowContainer() => Style( + flex.gap(8), + box.padding(16), + box.borderRadius(8), + box.border.width(1), + box.border.color.redAccent(), + flex.mainAxisSize.min(), + flex.mainAxisAlignment.start(), + flex.crossAxisAlignment.start(), + ); + +Style _innerColumnContainer() => Style( + flex.gap(2), + flex.mainAxisSize.min(), + flex.mainAxisAlignment.start(), + flex.crossAxisAlignment.start(), + flexible.expanded(), + ); + +Style _title() => Style( + text.style.fontSize(14), + text.style.fontWeight.w600(), + text.style.color.redAccent(), + ); + +Style _subtitle() => Style( + text.style.fontSize(14), + text.style.fontWeight.normal(), + text.style.color.redAccent(), + ); + +Style _icon() => Style( + icon.size(20), + icon.color.redAccent(), + ); diff --git a/lib/components/card/card.dart b/lib/components/card/card.dart index 72f5e12..8c3bd00 100644 --- a/lib/components/card/card.dart +++ b/lib/components/card/card.dart @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import 'package:mix/mix.dart'; import 'package:remix_ui/components/card/card.style.dart'; +import '../../utils/component_recipe.dart'; + class PresableRemixCard extends RemixCard { const PresableRemixCard({ super.key, @@ -11,16 +13,14 @@ class PresableRemixCard extends RemixCard { }); } -class RemixCard extends StatelessWidget { +class RemixCard extends StatelessWidget + implements RemixComponentRecipe { const RemixCard({ super.key, required this.child, - CardStyles? style, - }) : _customStyle = style; - - final Widget child; - - final CardStyles? _customStyle; + this.style, + this.variants = const [], + }); factory RemixCard.pressable( Widget child, { @@ -34,9 +34,23 @@ class RemixCard extends StatelessWidget { ); } + final Widget child; + + @override + final CardStyles? style; + + @override + final List variants; + + CardStyles buildStyle(List variants) { + final result = style == null ? CardStyles.base() : style!; + + return result.applyVariants(variants); + } + @override Widget build(BuildContext context) { - final style = CardStyles.build(_customStyle); + final style = buildStyle(variants); return Box( style: style.container, diff --git a/lib/components/card/card.style.dart b/lib/components/card/card.style.dart index 0dd065b..976ce7e 100644 --- a/lib/components/card/card.style.dart +++ b/lib/components/card/card.style.dart @@ -7,14 +7,7 @@ class CardStyles extends StyleRecipe { final Style container; - factory CardStyles.build([ - CardStyles? other, - List variants = const [], - ]) { - return CardStyles.defaults().merge(other).applyVariants(variants); - } - - factory CardStyles.defaults() { + factory CardStyles.base() { return CardStyles( container: _container(), ); diff --git a/lib/remix_ui.dart b/lib/remix_ui.dart index e29c012..e12baf5 100644 --- a/lib/remix_ui.dart +++ b/lib/remix_ui.dart @@ -1,5 +1,7 @@ library remix_ui; +export 'components/alert/alert.dart'; +export 'components/alert/alert.style.dart'; export 'components/button/button.dart'; export 'components/button/button.style.dart'; export 'components/button/button.variants.dart';