Skip to content

Commit

Permalink
Merge branch 'master' into multiselect
Browse files Browse the repository at this point in the history
  • Loading branch information
witwash authored Oct 16, 2023
2 parents c17258c + bdab7b7 commit 3eae2b6
Show file tree
Hide file tree
Showing 9 changed files with 210 additions and 163 deletions.
1 change: 1 addition & 0 deletions optimus/lib/optimus.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export 'src/form/select_input_form_field.dart';
export 'src/icon.dart';
export 'src/icon_list.dart';
export 'src/link/inline_link.dart';
export 'src/link/link_variant.dart';
export 'src/link/standalone_link.dart';
export 'src/lists/font_variant.dart';
export 'src/lists/list_tile.dart';
Expand Down
111 changes: 72 additions & 39 deletions optimus/lib/src/link/base_link.dart
Original file line number Diff line number Diff line change
@@ -1,25 +1,31 @@
import 'package:flutter/material.dart';
import 'package:optimus/optimus.dart';
import 'package:optimus/src/enabled.dart';
import 'package:optimus/src/link/link_variant.dart';
import 'package:optimus/src/spacing.dart';
import 'package:optimus/src/theme/optimus_tokens.dart';
import 'package:optimus/src/theme/theme.dart';

class BaseLink extends StatefulWidget {
const BaseLink({
super.key,
required this.text,
required this.textStyle,
this.color,
this.icon,
this.onPressed,
this.overflow,
this.inherit = false,
this.strong = false,
this.variant = OptimusLinkVariant.primary,
});

final VoidCallback? onPressed;
final TextStyle textStyle;
final TextStyle? textStyle;
final Widget text;
final Widget? icon;
final Color? color;
final bool strong;
final bool inherit;
final TextOverflow? overflow;
final OptimusLinkVariant variant;

@override
State<BaseLink> createState() => _BaseLinkState();
Expand All @@ -29,58 +35,85 @@ class _BaseLinkState extends State<BaseLink> with ThemeGetter {
bool _isHovering = false;
bool _isTappedDown = false;

void _onHoverChanged(bool isHovering) {
setState(() => _isHovering = isHovering);
void _handleHoverChange(bool isHovering) =>
setState(() => _isHovering = isHovering);

Color get _effectiveColor => widget.inherit ? _inheritedColor : _color;

Color get _color {
if (!_isEnabled) return widget.variant.getDisabledColor(tokens);
if (_isTappedDown) return widget.variant.getTappedColor(tokens);
if (_isHovering) return widget.variant.getHoveredColor(tokens);

return widget.variant.getDefaultColor(tokens);
}

Color get _color =>
widget.color ??
(widget.inherit
? _inheritedColor
: _isTappedDown
? theme.colors.primary700
: theme.colors.primary500);
Color get _inheritedColor => widget.textStyle?.color ?? _color;

Color get _inheritedColor =>
widget.textStyle.color ?? theme.colors.neutral1000;
bool get _isEnabled => widget.onPressed != null;

TextStyle get _textStyle =>
widget.textStyle ?? DefaultTextStyle.of(context).style;

@override
Widget build(BuildContext context) {
final icon = widget.icon;

final text = DefaultTextStyle(
style: _textStyle.copyWith(
color: _effectiveColor,
overflow: widget.overflow,
fontWeight: widget.strong ? FontWeight.w500 : FontWeight.w400,
decoration: _isHovering ? null : TextDecoration.underline,
),
child: widget.text,
);

final child = icon != null
? Row(
mainAxisSize: MainAxisSize.min,
children: [
text,
Padding(
padding: const EdgeInsets.only(left: spacing100),
child: IconTheme(
data: IconThemeData(color: _effectiveColor),
child: icon,
),
),
],
)
: text;

return OptimusEnabled(
isEnabled: widget.onPressed != null,
isEnabled: _isEnabled,
child: MouseRegion(
onEnter: (_) => _onHoverChanged(true),
onExit: (_) => _onHoverChanged(false),
onEnter: (_) => _handleHoverChange(true),
onExit: (_) => _handleHoverChange(false),
child: GestureDetector(
onTap: widget.onPressed,
onTapDown: (_) => setState(() => _isTappedDown = true),
onTapUp: (_) => setState(() => _isTappedDown = false),
onTapCancel: () => setState(() => _isTappedDown = false),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (icon != null)
Padding(
padding: const EdgeInsets.symmetric(horizontal: spacing50),
child: IconTheme(
data: IconThemeData(color: _color),
child: icon,
),
),
DefaultTextStyle(
style: widget.textStyle.copyWith(
color: _color,
overflow: widget.overflow,
decoration: _isHovering ? null : TextDecoration.underline,
),
child: widget.text,
),
],
),
child: child,
),
),
);
}
}

extension on OptimusLinkVariant {
Color getDefaultColor(OptimusTokens tokens) => switch (this) {
OptimusLinkVariant.primary => tokens.textInteractiveDefault,
OptimusLinkVariant.basic => tokens.textStaticPrimary,
};
Color getHoveredColor(OptimusTokens tokens) => switch (this) {
OptimusLinkVariant.primary => tokens.textInteractiveHover,
OptimusLinkVariant.basic => tokens.textStaticTertiary,
};
Color getTappedColor(OptimusTokens tokens) => switch (this) {
OptimusLinkVariant.primary => tokens.textInteractiveActive,
OptimusLinkVariant.basic => tokens.textStaticPrimary,
};
Color getDisabledColor(OptimusTokens tokens) => tokens.textDisabled;
}
24 changes: 15 additions & 9 deletions optimus/lib/src/link/inline_link.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:optimus/src/link/base_link.dart';
import 'package:optimus/src/link/link_variant.dart';

/// A link widget that is used to display a link inside the
/// body of text. You can pass a custom [TextStyle] which will be used to render
/// the link. The only thing that will be overwritten is the [FontWeight] and
/// will be set to [FontWeight.w600].
/// body of text.
///
/// Links as interactive elements should always be used sparingly and with
/// consideration. Too many can easily clutter a page and make it difficult for
Expand All @@ -18,34 +17,41 @@ class OptimusInlineLink extends StatelessWidget {
this.onPressed,
this.overflow,
this.inherit = false,
this.strong = false,
this.variant = OptimusLinkVariant.primary,
});

/// Called when link is tapped.
///
/// If this callback is null, then the button will be disabled.
final VoidCallback? onPressed;

/// Controls the link's text
/// Controls the link's text.
final Widget text;

/// Controls if link should inherit parent style
/// Controls if link should inherit parent style.
final bool inherit;

/// Controls the link's text overflowing
/// Controls the link's text overflowing.
final TextOverflow? overflow;

/// Custom text style for the link.
final TextStyle? textStyle;

TextStyle _textStyle(BuildContext context) =>
textStyle ?? DefaultTextStyle.of(context).style;
/// Defines the weight of the font.
final bool strong;

/// Link color variant.
final OptimusLinkVariant variant;

@override
Widget build(BuildContext context) => BaseLink(
text: text,
textStyle: _textStyle(context).copyWith(fontWeight: FontWeight.w600),
textStyle: textStyle,
inherit: inherit,
onPressed: onPressed,
overflow: overflow,
variant: variant,
strong: strong,
);
}
4 changes: 4 additions & 0 deletions optimus/lib/src/link/link_variant.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/// Variant of the link.
/// [OptimusLinkVariant.primary] - will use indigo as a base color.
/// [OptimusLinkVariant.basic] - will use the bare (grey) color as its base.
enum OptimusLinkVariant { primary, basic }
66 changes: 32 additions & 34 deletions optimus/lib/src/link/standalone_link.dart
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import 'package:flutter/material.dart';
import 'package:optimus/optimus.dart';
import 'package:optimus/src/link/base_link.dart';
import 'package:optimus/src/typography/presets.dart';

/// Standalone links are available in two size options to accommodate various
/// environments with different requirements.
enum OptimusStandaloneLinkSize {
/// Used when space is limited or to match with smaller text sizes on a page.
small,
medium,

/// Used when space is not limited or to match with larger text sizes on a
/// page.
normal,
large,
}

/// A link widget that is used to display a link on its own, not a part of the
Expand All @@ -25,63 +24,62 @@ class OptimusStandaloneLink extends StatelessWidget {
super.key,
this.onPressed,
required this.text,
required this.size,
this.color,
this.size,
this.overflow,
this.inherit = false,
this.external = false,
this.isExternal = false,
this.strong = false,
this.variant = OptimusLinkVariant.primary,
});

/// Called when link is tapped.
///
/// If this callback is null, then the button will be disabled.
final VoidCallback? onPressed;

/// Controls the link's text
/// Link text.
final Widget text;

/// Controls the link's size
final OptimusStandaloneLinkSize size;

/// Controls the link's color
final Color? color;

/// Controls if link should inherit parent style
/// Controls if link should inherit parent style.
final bool inherit;

/// Controls if link is external and icon should be displayed
final bool external;
/// Controls if link is external and icon should be displayed.
final bool isExternal;

/// Controls the link's text overflowing
/// Link's text overflow style.
final TextOverflow? overflow;

Widget? get _icon => external
? Icon(
OptimusIcons.external_link,
size: size.iconSize,
)
: null;
/// Weight of the font.
final bool strong;

/// Link size.
final OptimusStandaloneLinkSize? size;

// Link color variant.
final OptimusLinkVariant variant;
@override
Widget build(BuildContext context) => BaseLink(
text: text,
textStyle: size.linkStyle,
color: color,
textStyle: DefaultTextStyle.of(context).style.copyWith(
fontSize: size?.fontSize,
),
inherit: inherit,
onPressed: onPressed,
overflow: overflow,
icon: _icon,
icon: isExternal
? Icon(
OptimusIcons.external_link,
size: size?.fontSize,
)
: null,
variant: variant,
strong: strong,
);
}

extension on OptimusStandaloneLinkSize {
TextStyle get linkStyle => switch (this) {
OptimusStandaloneLinkSize.small => preset200b,
OptimusStandaloneLinkSize.normal => preset300b,
};

double get iconSize => switch (this) {
OptimusStandaloneLinkSize.small => 14,
OptimusStandaloneLinkSize.normal => 16,
double get fontSize => switch (this) {
OptimusStandaloneLinkSize.medium => 14,
OptimusStandaloneLinkSize.large => 16,
};
}
Loading

0 comments on commit 3eae2b6

Please sign in to comment.