Skip to content

Commit

Permalink
feat: Added NavRail hover state (#204)
Browse files Browse the repository at this point in the history
feat: Added NavRail focus state
  • Loading branch information
DE7924 authored Nov 11, 2024
1 parent 321b57d commit 39c5cdf
Showing 1 changed file with 91 additions and 56 deletions.
147 changes: 91 additions & 56 deletions lib/src/components/navigation_rail/navigation_rail.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

import '../../../zeta_flutter.dart';

Expand Down Expand Up @@ -124,7 +125,7 @@ class ZetaNavigationRail extends ZetaStatelessWidget {
}
}

class _ZetaNavigationRailItemContent extends ZetaStatelessWidget {
class _ZetaNavigationRailItemContent extends ZetaStatefulWidget {
const _ZetaNavigationRailItemContent({
required this.label,
this.icon,
Expand All @@ -143,66 +144,100 @@ class _ZetaNavigationRailItemContent extends ZetaStatelessWidget {
final EdgeInsets? padding;
final bool? wordWrap;

// TODO(UX-1173): No hover state for navigation rail items
@override
State<_ZetaNavigationRailItemContent> createState() => _ZetaNavigationRailItemContentState();

@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
..add(StringProperty('label', label))
..add(DiagnosticsProperty<bool>('selected', selected))
..add(DiagnosticsProperty<bool>('disabled', disabled))
..add(ObjectFlagProperty<VoidCallback?>.has('onTap', onTap))
..add(DiagnosticsProperty<EdgeInsets?>('padding', padding))
..add(DiagnosticsProperty<bool?>('wordWrap', wordWrap));
}
}

class _ZetaNavigationRailItemContentState extends State<_ZetaNavigationRailItemContent> {
bool _hovered = false;
bool _focused = false;

@override
Widget build(BuildContext context) {
final zeta = Zeta.of(context);
return Semantics(
button: true,
enabled: !disabled,
child: MouseRegion(
cursor: disabled ? SystemMouseCursors.forbidden : SystemMouseCursors.click,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: disabled ? null : onTap,
child: DecoratedBox(
decoration: BoxDecoration(
color: disabled
? null
: selected
? zeta.colors.blue.shade10
: null,
borderRadius: context.rounded ? Zeta.of(context).radius.rounded : null,
),
child: ConstrainedBox(
constraints: BoxConstraints(
minWidth: Zeta.of(context).spacing.xl_9,
minHeight: Zeta.of(context).spacing.xl_9,
enabled: !widget.disabled,
child: Focus(
onFocusChange: (focused) => setState(() => _focused = focused),
onKeyEvent: (node, event) {
if (event.logicalKey == LogicalKeyboardKey.enter || event.logicalKey == LogicalKeyboardKey.space) {
widget.onTap?.call();
return KeyEventResult.handled;
}
return KeyEventResult.ignored;
},
child: MouseRegion(
cursor: widget.disabled ? SystemMouseCursors.forbidden : SystemMouseCursors.click,
onEnter: (_) => setState(() => _hovered = true),
onExit: (_) => setState(() => _hovered = false),
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: widget.disabled ? null : widget.onTap,
child: DecoratedBox(
decoration: BoxDecoration(
color: widget.disabled
? null
: widget.selected
? zeta.colors.blue.shade10
: _hovered
? zeta.colors.surfaceHover
: null,
border: _focused ? Border.all(color: zeta.colors.blue, width: 2) : null,
borderRadius: context.rounded ? Zeta.of(context).radius.rounded : null,
),
child: SelectionContainer.disabled(
child: Padding(
padding: padding ??
EdgeInsets.symmetric(
horizontal: Zeta.of(context).spacing.small,
vertical: Zeta.of(context).spacing.medium,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (icon != null)
IconTheme(
data: IconThemeData(
color: disabled
child: ConstrainedBox(
constraints: BoxConstraints(
minWidth: Zeta.of(context).spacing.xl_9,
minHeight: Zeta.of(context).spacing.xl_9,
),
child: SelectionContainer.disabled(
child: Padding(
padding: widget.padding ??
EdgeInsets.symmetric(
horizontal: Zeta.of(context).spacing.small,
vertical: Zeta.of(context).spacing.medium,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (widget.icon != null)
IconTheme(
data: IconThemeData(
color: widget.disabled
? zeta.colors.cool.shade50
: widget.selected || _hovered
? zeta.colors.textDefault
: zeta.colors.cool.shade70,
size: Zeta.of(context).spacing.xl_2,
),
child: widget.icon!,
),
Text(
(widget.wordWrap ?? true) ? widget.label.replaceAll(' ', '\n') : widget.label,
textAlign: TextAlign.center,
style: ZetaTextStyles.titleSmall.copyWith(
color: widget.disabled
? zeta.colors.cool.shade50
: selected
: widget.selected || _hovered
? zeta.colors.textDefault
: zeta.colors.cool.shade70,
size: Zeta.of(context).spacing.xl_2,
),
child: icon!,
),
Text(
(wordWrap ?? true) ? label.replaceAll(' ', '\n') : label,
textAlign: TextAlign.center,
style: ZetaTextStyles.titleSmall.copyWith(
color: disabled
? zeta.colors.cool.shade50
: selected
? zeta.colors.textDefault
: zeta.colors.cool.shade70,
),
),
],
],
),
),
),
),
Expand All @@ -217,12 +252,12 @@ class _ZetaNavigationRailItemContent extends ZetaStatelessWidget {
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
..add(ObjectFlagProperty<VoidCallback?>.has('onTap', onTap))
..add(DiagnosticsProperty<bool>('disabled', disabled))
..add(DiagnosticsProperty<bool>('selected', selected))
..add(DiagnosticsProperty<EdgeInsets?>('padding', padding))
..add(StringProperty('label', label))
..add(DiagnosticsProperty<bool?>('wordWrap', wordWrap));
..add(ObjectFlagProperty<VoidCallback?>.has('onTap', widget.onTap))
..add(DiagnosticsProperty<bool>('disabled', widget.disabled))
..add(DiagnosticsProperty<bool>('selected', widget.selected))
..add(DiagnosticsProperty<EdgeInsets?>('padding', widget.padding))
..add(StringProperty('label', widget.label))
..add(DiagnosticsProperty<bool?>('wordWrap', widget.wordWrap));
}
}

Expand Down

0 comments on commit 39c5cdf

Please sign in to comment.