Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Card variants #84

Merged
merged 12 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions docs/pages/docs/alert.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Tabs } from 'nextra/components';
import { Widget } from "../../components/widget";

# Alert
Displays a callout for user attention.

<Tabs items={['Preview', 'Code']}>
<Tabs.Tab>
<Widget name='alert' query={{}}/>
</Tabs.Tab>
<Tabs.Tab>
```dart
FAlert(
title: const Text('Heads Up!'),
subtitle: const Text('You can add components to your app using the cli.'),
);
```
</Tabs.Tab>
</Tabs>

## Usage

### `FAlert(...)`

```dart
FAlert(
icon: FAlertIcon(icon: FAssets.icons.badgeAlert),
title: const Text('Heads Up!'),
subtitle: const Text('You can add components to your app using the cli.'),
);
```

## Examples

### Primary
<Tabs items={['Preview', 'Code']}>
<Tabs.Tab>
<Widget name='alert' query={{}}/>
</Tabs.Tab>
<Tabs.Tab>
```dart
FAlert(
title: const Text('Heads Up!'),
subtitle: const Text('You can add components to your app using the cli.'),
);
```
</Tabs.Tab>
</Tabs>

### Destructive
<Tabs items={['Preview', 'Code']}>
<Tabs.Tab>
<Widget name='alert' query={{style: 'destructive'}}/>
</Tabs.Tab>
<Tabs.Tab>
```dart
FAlert(
title: const Text('Heads Up!'),
subtitle: const Text('You can add components to your app using the cli.'),
style: FAlertStyle.destructive,
);
```
</Tabs.Tab>
</Tabs>
1 change: 1 addition & 0 deletions forui/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## Next

### Additions
* Add `FAlert`
* Add `FCalendar`
* Add `FBottomNavigationBar`

Expand Down
4 changes: 4 additions & 0 deletions forui/example/lib/example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ class _ExampleState extends State<Example> {
const SizedBox(height: 100),
FProgress(value: 0.9),
const SizedBox(height: 10),
FAlert(
title: const Text('Heads Up! Forui is coming to flutter!'),
subtitle: const Text('You can add components dfijsoi djfosfj to your app using the cli.'),
)
],
);
}
10 changes: 10 additions & 0 deletions forui/lib/src/theme/theme_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ final class FThemeData with Diagnosticable {
/// The style. It is used to configure the miscellaneous properties, such as border radii, of Forui widgets.
final FStyle style;

/// The alert styles.
final FAlertStyles alertStyles;

/// The badge styles.
final FBadgeStyles badgeStyles;

Expand Down Expand Up @@ -80,6 +83,7 @@ final class FThemeData with Diagnosticable {
required this.buttonStyles,
required this.calendarStyle,
required this.cardStyle,
required this.alertStyles,
required this.checkboxStyle,
required this.dialogStyle,
required this.headerStyle,
Expand All @@ -105,6 +109,7 @@ final class FThemeData with Diagnosticable {
colorScheme: colorScheme,
typography: typography,
style: style,
alertStyles: FAlertStyles.inherit(colorScheme: colorScheme, typography: typography, style: style),
badgeStyles: FBadgeStyles.inherit(colorScheme: colorScheme, typography: typography, style: style),
bottomNavigationBarStyle: FBottomNavigationBarStyle.inherit(colorScheme: colorScheme, typography: typography),
buttonStyles: FButtonStyles.inherit(colorScheme: colorScheme, typography: typography, style: style),
Expand Down Expand Up @@ -143,6 +148,7 @@ final class FThemeData with Diagnosticable {
FColorScheme? colorScheme,
FTypography? typography,
FStyle? style,
FAlertStyles? alertStyles,
FBadgeStyles? badgeStyles,
FBottomNavigationBarStyle? bottomNavigationBarStyle,
FButtonStyles? buttonStyles,
Expand All @@ -162,6 +168,7 @@ final class FThemeData with Diagnosticable {
colorScheme: colorScheme ?? this.colorScheme,
typography: typography ?? this.typography,
style: style ?? this.style,
alertStyles: alertStyles ?? this.alertStyles,
badgeStyles: badgeStyles ?? this.badgeStyles,
bottomNavigationBarStyle: bottomNavigationBarStyle ?? this.bottomNavigationBarStyle,
buttonStyles: buttonStyles ?? this.buttonStyles,
Expand All @@ -185,6 +192,7 @@ final class FThemeData with Diagnosticable {
..add(DiagnosticsProperty('colorScheme', colorScheme, level: DiagnosticLevel.debug))
..add(DiagnosticsProperty('typography', typography, level: DiagnosticLevel.debug))
..add(DiagnosticsProperty('style', style, level: DiagnosticLevel.debug))
..add(DiagnosticsProperty('alertStyles', alertStyles, level: DiagnosticLevel.debug))
..add(DiagnosticsProperty('badgeStyles', badgeStyles, level: DiagnosticLevel.debug))
..add(DiagnosticsProperty('bottomNavigationBarStyle', bottomNavigationBarStyle, level: DiagnosticLevel.debug))
..add(DiagnosticsProperty('buttonStyles', buttonStyles, level: DiagnosticLevel.debug))
Expand All @@ -209,6 +217,7 @@ final class FThemeData with Diagnosticable {
colorScheme == other.colorScheme &&
typography == other.typography &&
style == other.style &&
alertStyles == other.alertStyles &&
badgeStyles == other.badgeStyles &&
bottomNavigationBarStyle == other.bottomNavigationBarStyle &&
buttonStyles == other.buttonStyles &&
Expand All @@ -229,6 +238,7 @@ final class FThemeData with Diagnosticable {
colorScheme.hashCode ^
typography.hashCode ^
style.hashCode ^
alertStyles.hashCode ^
badgeStyles.hashCode ^
bottomNavigationBarStyle.hashCode ^
buttonStyles.hashCode ^
Expand Down
205 changes: 205 additions & 0 deletions forui/lib/src/widgets/alert/alert.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';

import 'package:meta/meta.dart';

import 'package:forui/forui.dart';

part 'alert_styles.dart';

part 'alert_icon.dart';

/// An alert.
///
/// Displays a callout for user attention.
///
/// See:
/// * https://forui.dev/docs/alert for working examples.
/// * [FAlertStyle] for customizing an alert's appearance.
class FAlert extends StatelessWidget {
@useResult
static FAlertCustomStyle _of(BuildContext context) {
final theme = context.dependOnInheritedWidgetOfExactType<_InheritedData>();
return theme?.style ?? context.theme.alertStyles.primary;
}

/// The icon. Defaults to [FAssets.icons.circleAlert].
final Widget icon;

/// The title.
final Widget title;

/// The subtitle.
final Widget? subtitle;

/// The style. Defaults to [FAlertStyle.primary].
///
/// Although typically one of the pre-defined styles in [FAlertStyle], it can also be a [FAlertCustomStyle].
final FAlertStyle style;

/// Creates a [FAlert] with a tile, subtitle, and icon.
///
/// The alert's layout is as follows:
/// ```
/// |---------------------------|
/// | [icon] [title] |
/// | [subtitle] |
/// |---------------------------|
/// ```
FAlert({
required this.title,
Widget? icon,
this.subtitle,
this.style = FAlertStyle.primary,
super.key,
}) : icon = icon ?? FAlertIcon(icon: FAssets.icons.circleAlert);

@override
Widget build(BuildContext context) {
final style = switch (this.style) {
final FAlertCustomStyle style => style,
Variant.primary => context.theme.alertStyles.primary,
Variant.destructive => context.theme.alertStyles.destructive,
};

return DecoratedBox(
decoration: style.decoration,
child: Padding(
padding: style.padding,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
_InheritedData(style: style, child: icon),
Flexible(
child: Padding(
padding: const EdgeInsets.only(left: 8),
child: DefaultTextStyle.merge(
style: style.titleTextStyle,
child: title,
),
),
),
],
),
if (subtitle != null)
Row(
children: [
SizedBox(width: style.icon.height),
Flexible(
child: Padding(
padding: const EdgeInsets.only(top: 3, left: 8),
child: DefaultTextStyle.merge(
style: style.subtitleTextStyle,
child: subtitle!,
),
),
),
],
),
],
),
),
);
}

@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty('style', style));
}
}

/// A [FAlert]'s style.
///
/// A style can be either one of the pre-defined styles in [FAlertStyle] or a [FAlertCustomStyle]. The pre-defined
/// styles are a convenient shorthand for the various [FAlertCustomStyle]s in the current context's [FAlertStyles].
sealed class FAlertStyle {
/// The alert's primary style.
///
/// Shorthand for the current context's [FAlertStyle.primary] style.
static const FAlertStyle primary = Variant.primary;

/// The alert's destructive style.
///
/// Shorthand for the current context's [FAlertStyle.destructive] style.
static const FAlertStyle destructive = Variant.destructive;
}

@internal
enum Variant implements FAlertStyle {
primary,
destructive,
}

/// A custom [FAlert] style.
final class FAlertCustomStyle extends FAlertStyle with Diagnosticable {
/// The decoration.
final BoxDecoration decoration;

/// The padding. Defaults to `EdgeInsets.fromLTRB(16, 12, 16, 16)`.
final EdgeInsets padding;

/// The icon's style.
final FAlertIconStyle icon;

/// The title's [TextStyle].
final TextStyle titleTextStyle;

/// The subtitle's [TextStyle].
final TextStyle subtitleTextStyle;

/// Creates a [FAlertCustomStyle].
FAlertCustomStyle({
required this.decoration,
required this.icon,
required this.titleTextStyle,
required this.subtitleTextStyle,
this.padding = const EdgeInsets.all(16),
});

@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
..add(DiagnosticsProperty('decoration', decoration))
..add(DiagnosticsProperty('padding', padding))
..add(DiagnosticsProperty('icon', icon))
..add(DiagnosticsProperty('titleTextStyle', titleTextStyle))
..add(DiagnosticsProperty('subtitleTextStyle', subtitleTextStyle));
}

@override
bool operator ==(Object other) =>
identical(this, other) ||
other is FAlertCustomStyle &&
runtimeType == other.runtimeType &&
decoration == other.decoration &&
padding == other.padding &&
icon == other.icon &&
titleTextStyle == other.titleTextStyle &&
subtitleTextStyle == other.subtitleTextStyle;

@override
int get hashCode =>
decoration.hashCode ^ padding.hashCode ^ icon.hashCode ^ titleTextStyle.hashCode ^ subtitleTextStyle.hashCode;
}

class _InheritedData extends InheritedWidget {
final FAlertCustomStyle style;

const _InheritedData({
required this.style,
required super.child,
});

@override
bool updateShouldNotify(covariant _InheritedData old) => style != old.style;

@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty('style', style));
}
}
Loading
Loading