From b094a4e6e6122fbb68aa9463384569f5e7137b7e Mon Sep 17 00:00:00 2001 From: Daniel Eshkeri Date: Thu, 14 Nov 2024 13:38:34 +0000 Subject: [PATCH 1/6] fix: breadcrumb now removes the items after the one that is clicked --- .../pages/components/breadcrumbs_example.dart | 108 ++++++++++++++---- example/widgetbook/main.dart | 2 +- .../components/breadcrumbs_widgetbook.dart | 77 ++++++------- .../breadcrumb.dart} | 81 ++++++------- lib/src/components/components.dart | 2 +- 5 files changed, 160 insertions(+), 110 deletions(-) rename lib/src/components/{breadcrumbs/breadcrumbs.dart => breadcrumb/breadcrumb.dart} (82%) diff --git a/example/lib/pages/components/breadcrumbs_example.dart b/example/lib/pages/components/breadcrumbs_example.dart index b6e0c7fc..4d383ed0 100644 --- a/example/lib/pages/components/breadcrumbs_example.dart +++ b/example/lib/pages/components/breadcrumbs_example.dart @@ -12,15 +12,63 @@ class BreadCrumbsExample extends StatefulWidget { } class _BreadCrumbsExampleState extends State { - List _children = [ - ZetaBreadCrumb( - label: 'Icon before with separator', - onPressed: () { - print("Breadcrumb " + 0.toString() + "Clicked"); - }, - ), - ]; - int index = 1; + List _children = []; + int index = 3; + + @override + void initState() { + super.initState(); + _children = [ + ZetaBreadcrumbItem( + label: 'Breadcrumb', + onPressed: () { + print("Breadcrumb clicked"); + }, + ), + ZetaBreadcrumbItem( + label: 'Item 1', + onPressed: () { + print("Breadcrumb clicked"); + }, + ), + ZetaBreadcrumbItem( + label: 'Item 2', + onPressed: () { + print("Breadcrumb clicked"); + }, + ), + ZetaBreadcrumbItem( + label: 'Item 3', + onPressed: () { + print("Breadcrumb clicked"); + }, + ), + ZetaBreadcrumbItem( + label: 'Item 4', + onPressed: () { + print("Breadcrumb clicked"); + }, + ), + ZetaBreadcrumbItem( + label: 'Item 5', + onPressed: () { + print("Breadcrumb clicked"); + }, + ), + ZetaBreadcrumbItem( + label: 'Item 6', + onPressed: () { + print("Breadcrumb clicked"); + }, + ), + ZetaBreadcrumbItem( + label: 'Item 7', + onPressed: () { + print("Breadcrumb clicked"); + }, + ), + ]; + } @override Widget build(BuildContext context) { @@ -31,25 +79,35 @@ class _BreadCrumbsExampleState extends State { child: SizedBox( width: double.infinity, child: Column(children: [ - ZetaBreadCrumbs(children: _children), + ZetaBreadcrumb(children: _children.sublist(0, 1)), + SizedBox( + height: 50, + ), + ZetaBreadcrumb(children: _children.sublist(0, 2)), + SizedBox( + height: 50, + ), + ZetaBreadcrumb(children: _children.sublist(0, 3)), + SizedBox( + height: 50, + ), + ZetaBreadcrumb(children: _children.sublist(0, 4)), + SizedBox( + height: 50, + ), + ZetaBreadcrumb(children: _children.sublist(0, 5)), + SizedBox( + height: 50, + ), + ZetaBreadcrumb(children: _children.sublist(0, 6)), + SizedBox( + height: 50, + ), + ZetaBreadcrumb(children: _children.sublist(0, 7)), SizedBox( height: 50, ), - FilledButton( - onPressed: () { - setState(() { - _children.add( - ZetaBreadCrumb( - label: 'Icon before with seperator', - onPressed: () { - print("Breadcrumb clicked"); - }, - ), - ); - index++; - }); - }, - child: Text("Add Breadcrumb")) + ZetaBreadcrumb(children: _children), ])), ), ), diff --git a/example/widgetbook/main.dart b/example/widgetbook/main.dart index 7eeba843..e8eade35 100644 --- a/example/widgetbook/main.dart +++ b/example/widgetbook/main.dart @@ -192,7 +192,7 @@ class _HotReloadState extends State { WidgetbookUseCase(name: 'Accordion', builder: (context) => accordionUseCase(context)), WidgetbookUseCase(name: 'Banners', builder: (context) => bannerUseCase(context)), WidgetbookUseCase(name: 'Bottom Sheet', builder: (context) => bottomSheetContentUseCase(context)), - WidgetbookUseCase(name: 'BreadCrumbs', builder: (context) => breadCrumbsUseCase(context)), + WidgetbookUseCase(name: 'BreadCrumbs', builder: (context) => breadCrumbUseCase(context)), WidgetbookUseCase(name: 'Checkbox', builder: (context) => checkboxUseCase(context)), WidgetbookUseCase(name: 'Comms Button', builder: (context) => commsButtonUseCase(context)), WidgetbookUseCase(name: 'Date Input', builder: (context) => dateInputUseCase(context)), diff --git a/example/widgetbook/pages/components/breadcrumbs_widgetbook.dart b/example/widgetbook/pages/components/breadcrumbs_widgetbook.dart index 63c99216..015c9cd4 100644 --- a/example/widgetbook/pages/components/breadcrumbs_widgetbook.dart +++ b/example/widgetbook/pages/components/breadcrumbs_widgetbook.dart @@ -2,62 +2,53 @@ import 'package:flutter/material.dart'; import 'package:zeta_flutter/zeta_flutter.dart'; import '../../utils/scaffold.dart'; +import 'package:widgetbook/widgetbook.dart'; + import '../../utils/utils.dart'; -Widget breadCrumbsUseCase(BuildContext context) => WidgetbookScaffold( +final List children = [ + ZetaBreadcrumbItem(label: 'Breadcrumb', onPressed: () {}), + ZetaBreadcrumbItem(label: 'Item 1', onPressed: () {}), + ZetaBreadcrumbItem(label: 'Item 2', onPressed: () {}), + ZetaBreadcrumbItem(label: 'Item 3', onPressed: () {}), + ZetaBreadcrumbItem(label: 'Item 4', onPressed: () {}), + ZetaBreadcrumbItem(label: 'Item 5', onPressed: () {}), + ZetaBreadcrumbItem(label: 'Item 6', onPressed: () {}) +]; + +Widget breadCrumbUseCase(BuildContext context) => WidgetbookScaffold( builder: (context, _) => Center( - child: BreadCrumbExample(context), + child: BreadCrumbExample(context, children), ), ); -class BreadCrumbExample extends StatefulWidget { - const BreadCrumbExample(this.c); - final BuildContext c; - - @override - State createState() => _BreadCrumbExampleState(); -} - -class _BreadCrumbExampleState extends State { - List _children = [ - ZetaBreadCrumb( - label: 'Icon before with seperator', - onPressed: () { - print("Breadcrumb " + 0.toString() + "Clicked"); - }, - ), - ]; - int index = 1; +class BreadCrumbExample extends StatelessWidget { + BreadCrumbExample(this.context, this.children); + final BuildContext context; + final List children; @override Widget build(BuildContext _) { return SingleChildScrollView( child: SizedBox( - width: double.infinity, - child: Column(children: [ - ZetaBreadCrumbs( - children: _children, + width: double.infinity, + child: Column( + children: [ + ZetaBreadcrumb( + children: context.knobs.list( + label: 'Items', + labelBuilder: (value) => value.length.toString(), + initialOption: children.sublist(0, 2), + options: List.generate( + children.length, + (index) => children.sublist(0, index + 1), + ), + ), activeIcon: iconKnob(context), ), - SizedBox( - height: 50, - ), - FilledButton( - onPressed: () { - setState(() { - _children.add( - ZetaBreadCrumb( - label: 'Icon before with seperator', - onPressed: () { - print("Breadcrumb clicked"); - }, - ), - ); - index++; - }); - }, - child: Text("Add Breadcrumb")) - ])), + ], + ), + ), ); } } diff --git a/lib/src/components/breadcrumbs/breadcrumbs.dart b/lib/src/components/breadcrumb/breadcrumb.dart similarity index 82% rename from lib/src/components/breadcrumbs/breadcrumbs.dart rename to lib/src/components/breadcrumb/breadcrumb.dart index 6f0f4aca..ca60f3c7 100644 --- a/lib/src/components/breadcrumbs/breadcrumbs.dart +++ b/lib/src/components/breadcrumb/breadcrumb.dart @@ -6,16 +6,16 @@ import '../../../zeta_flutter.dart'; /// The breadcrumb is a secondary navigation pattern that helps a user understand the hierarchy among levels and navigate back through them. /// -/// [children] should consist of [ZetaBreadCrumb]s. +/// [children] should consist of [ZetaBreadcrumbItem]s. /// /// {@category Components} /// /// Figma: https://www.figma.com/design/JesXQFLaPJLc1BdBM4sisI/%F0%9F%A6%93-ZDS---Components?node-id=229-5&node-type=canvas&m=dev /// /// Widgetbook: https://zeta-ds.web.app/flutter/widgetbook/index.html#/?path=components/breadcrumbs -class ZetaBreadCrumbs extends ZetaStatefulWidget { - ///Constructor for [ZetaBreadCrumbs] - const ZetaBreadCrumbs({ +class ZetaBreadcrumb extends ZetaStatefulWidget { + ///Constructor for [ZetaBreadcrumb] + const ZetaBreadcrumb({ super.key, super.rounded, required this.children, @@ -24,7 +24,7 @@ class ZetaBreadCrumbs extends ZetaStatefulWidget { }); /// Breadcrumb children - final List children; + final List children; /// Active icon for breadcrumb final IconData? activeIcon; @@ -34,37 +34,39 @@ class ZetaBreadCrumbs extends ZetaStatefulWidget { final String? moreSemanticLabel; @override - State createState() => _ZetaBreadCrumbsState(); + State createState() => _ZetaBreadcrumbsState(); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties - ..add(IterableProperty('children', children)) + ..add(IterableProperty('children', children)) ..add(DiagnosticsProperty('rounded', rounded)) ..add(DiagnosticsProperty('activeIcon', activeIcon)) ..add(StringProperty('moreSemanticLabel', moreSemanticLabel)); } } -class _ZetaBreadCrumbsState extends State { +class _ZetaBreadcrumbsState extends State { late int _selectedIndex; - late List _children; + late List _children; @override void initState() { super.initState(); + // selects the last item _selectedIndex = widget.children.length - 1; _children = [...widget.children]; } @override - void didUpdateWidget(ZetaBreadCrumbs oldWidget) { + void didUpdateWidget(ZetaBreadcrumb oldWidget) { super.didUpdateWidget(oldWidget); - if (widget.children.length != _children.length) { - _selectedIndex = widget.children.length - 1; - _children = [...widget.children]; - } + // will always be equal??? + // if (widget.children.length != _children.length) { + _selectedIndex = widget.children.length - 1; + _children = [...widget.children]; + // } } @override @@ -75,7 +77,7 @@ class _ZetaBreadCrumbsState extends State { child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( - children: renderedChildren(widget.children) + children: renderedChildren(_children) .divide( Row( children: [ @@ -92,13 +94,14 @@ class _ZetaBreadCrumbsState extends State { } ///Creates breadcrumb widget - ZetaBreadCrumb createBreadCrumb(ZetaBreadCrumb input, int index) { - return ZetaBreadCrumb( + ZetaBreadcrumbItem createBreadCrumb(ZetaBreadcrumbItem input, int index) { + return ZetaBreadcrumbItem( label: input.label, isSelected: _selectedIndex == index, onPressed: () { setState(() { _selectedIndex = index; + _children = _children.sublist(0, index + 1); }); input.onPressed.call(); }, @@ -106,7 +109,7 @@ class _ZetaBreadCrumbsState extends State { ); } - List renderedChildren(List children) { + List renderedChildren(List children) { final List returnList = []; if (children.length > 3) { returnList.add(createBreadCrumb(children.first, 0)); @@ -117,7 +120,7 @@ class _ZetaBreadCrumbsState extends State { truncatedChildren.add(createBreadCrumb(element, index + 1)); } returnList - ..add(_BreadCrumbsTruncated(semanticLabel: widget.moreSemanticLabel, children: truncatedChildren)) + ..add(_TruncatedItem(semanticLabel: widget.moreSemanticLabel, children: truncatedChildren)) ..add(createBreadCrumb(children.last, children.length - 1)); } else { for (final (index, element) in children.indexed) { @@ -128,14 +131,12 @@ class _ZetaBreadCrumbsState extends State { } } -// TODO(UX-1131): Rename to breadcrumbitem - -/// Class for untruncated [ZetaBreadCrumb]. +/// Class for untruncated [ZetaBreadcrumbItem]. /// -/// Should be a child of [ZetaBreadCrumbs]. -class ZetaBreadCrumb extends StatefulWidget { - ///Constructor for [ZetaBreadCrumb] - const ZetaBreadCrumb({ +/// Should be a child of [ZetaBreadcrumb]. +class ZetaBreadcrumbItem extends StatefulWidget { + ///Constructor for [ZetaBreadcrumbItem] + const ZetaBreadcrumbItem({ super.key, required this.label, this.icon, @@ -145,19 +146,19 @@ class ZetaBreadCrumb extends StatefulWidget { this.semanticLabel, }); - /// [ZetaBreadCrumb] label. + /// [ZetaBreadcrumbItem] label. final String label; /// Selected icon. final IconData? icon; - /// Is [ZetaBreadCrumb] selected. + /// Is [ZetaBreadcrumbItem] selected. final bool isSelected; - /// Handles press for [ZetaBreadCrumb] + /// Handles press for [ZetaBreadcrumbItem] final VoidCallback onPressed; - /// Active icon for [ZetaBreadCrumb] + /// Active icon for [ZetaBreadcrumbItem] final IconData? activeIcon; /// Label passed to wrapping [Semantics] widget. @@ -168,7 +169,7 @@ class ZetaBreadCrumb extends StatefulWidget { final String? semanticLabel; @override - State createState() => _ZetaBreadCrumbState(); + State createState() => _ZetaBreadcrumbState(); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { @@ -183,7 +184,7 @@ class ZetaBreadCrumb extends StatefulWidget { } } -class _ZetaBreadCrumbState extends State { +class _ZetaBreadcrumbState extends State { final controller = WidgetStatesController(); @override @@ -251,13 +252,13 @@ class _ZetaBreadCrumbState extends State { } } -/// Class for [_BreadCrumbsTruncated] -@Deprecated('This functionality is not needed anymore. Use [ZetaBreadCrumb] instead. ' 'Deprecated since 0.14.1') -typedef BreadCrumbsTruncated = _BreadCrumbsTruncated; +/// Class for [_TruncatedItem] +@Deprecated('This functionality is not needed anymore. Use [ZetaBreadcrumb] instead. ' 'Deprecated since 0.14.1') +typedef TruncatedItem = _TruncatedItem; -class _BreadCrumbsTruncated extends StatefulWidget { - ///Constructor for [_BreadCrumbsTruncated] - const _BreadCrumbsTruncated({ +class _TruncatedItem extends StatefulWidget { + ///Constructor for [_TruncatedItem] + const _TruncatedItem({ required this.children, this.semanticLabel, }); @@ -271,7 +272,7 @@ class _BreadCrumbsTruncated extends StatefulWidget { final String? semanticLabel; @override - State<_BreadCrumbsTruncated> createState() => _BreadCrumbsTruncatedState(); + State<_TruncatedItem> createState() => _TruncatedItemState(); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); @@ -279,7 +280,7 @@ class _BreadCrumbsTruncated extends StatefulWidget { } } -class _BreadCrumbsTruncatedState extends State<_BreadCrumbsTruncated> { +class _TruncatedItemState extends State<_TruncatedItem> { bool _expanded = false; @override diff --git a/lib/src/components/components.dart b/lib/src/components/components.dart index 63bae3a4..38a024cb 100644 --- a/lib/src/components/components.dart +++ b/lib/src/components/components.dart @@ -9,7 +9,7 @@ export 'badges/tag.dart'; export 'banner/banner.dart'; export 'bottom sheets/bottom_sheet.dart'; export 'bottom sheets/menu_items.dart'; -export 'breadcrumbs/breadcrumbs.dart'; +export 'breadcrumb/breadcrumb.dart'; export 'button_group/button_group.dart'; export 'buttons/button.dart'; export 'buttons/button_style.dart'; From 6c2ed11a4e17e02eaf4dd986b774da2dfde66bd1 Mon Sep 17 00:00:00 2001 From: Daniel Eshkeri Date: Thu, 14 Nov 2024 15:29:29 +0000 Subject: [PATCH 2/6] fix: removed active icon prop fix: rounded now affects breadcrumb icons fix: The icon that was passed in now shows on breadcrumb fix: truncated only hides any breadcrumbs over the maxItemsShown number fix: intruduced a value listenable builder to handle hover and pressed states on breadcrumb item --- example/lib/home.dart | 4 +- ...s_example.dart => breadcrumb_example.dart} | 38 ++- example/widgetbook/main.dart | 4 +- ...etbook.dart => breadcrumb_widgetbook.dart} | 20 +- lib/src/components/breadcrumb/breadcrumb.dart | 261 +++++++++--------- 5 files changed, 170 insertions(+), 157 deletions(-) rename example/lib/pages/components/{breadcrumbs_example.dart => breadcrumb_example.dart} (70%) rename example/widgetbook/pages/components/{breadcrumbs_widgetbook.dart => breadcrumb_widgetbook.dart} (70%) diff --git a/example/lib/home.dart b/example/lib/home.dart index 0534fd37..a36d7091 100644 --- a/example/lib/home.dart +++ b/example/lib/home.dart @@ -6,7 +6,7 @@ import 'package:zeta_example/pages/components/avatar_example.dart'; import 'package:zeta_example/pages/components/badges_example.dart'; import 'package:zeta_example/pages/components/banner_example.dart'; import 'package:zeta_example/pages/components/bottom_sheet_example.dart'; -import 'package:zeta_example/pages/components/breadcrumbs_example.dart'; +import 'package:zeta_example/pages/components/breadcrumb_example.dart'; import 'package:zeta_example/pages/components/button_example.dart'; import 'package:zeta_example/pages/components/chat_item_example.dart'; import 'package:zeta_example/pages/components/checkbox_example.dart'; @@ -67,7 +67,7 @@ final List components = [ Component(BannerExample.name, (context) => const BannerExample()), Component(BadgesExample.name, (context) => const BadgesExample()), Component(BottomSheetExample.name, (context) => const BottomSheetExample()), - Component(BreadCrumbsExample.name, (context) => const BreadCrumbsExample()), + Component(BreadcrumbExample.name, (context) => const BreadcrumbExample()), Component(ButtonExample.name, (context) => const ButtonExample()), Component(ChatItemExample.name, (context) => const ChatItemExample()), Component(CheckBoxExample.name, (context) => const CheckBoxExample()), diff --git a/example/lib/pages/components/breadcrumbs_example.dart b/example/lib/pages/components/breadcrumb_example.dart similarity index 70% rename from example/lib/pages/components/breadcrumbs_example.dart rename to example/lib/pages/components/breadcrumb_example.dart index 4d383ed0..5bd82f19 100644 --- a/example/lib/pages/components/breadcrumbs_example.dart +++ b/example/lib/pages/components/breadcrumb_example.dart @@ -2,18 +2,17 @@ import 'package:flutter/material.dart'; import 'package:zeta_example/widgets.dart'; import 'package:zeta_flutter/zeta_flutter.dart'; -class BreadCrumbsExample extends StatefulWidget { - static const String name = 'Breadcrumbs'; +class BreadcrumbExample extends StatefulWidget { + static const String name = 'Breadcrumb'; - const BreadCrumbsExample({super.key}); + const BreadcrumbExample({super.key}); @override - State createState() => _BreadCrumbsExampleState(); + State createState() => _BreadcrumbExampleState(); } -class _BreadCrumbsExampleState extends State { +class _BreadcrumbExampleState extends State { List _children = []; - int index = 3; @override void initState() { @@ -39,6 +38,7 @@ class _BreadCrumbsExampleState extends State { ), ZetaBreadcrumbItem( label: 'Item 3', + icon: ZetaIcons.star, onPressed: () { print("Breadcrumb clicked"); }, @@ -73,7 +73,7 @@ class _BreadCrumbsExampleState extends State { @override Widget build(BuildContext context) { return ExampleScaffold( - name: 'Breadcrumbs', + name: 'Breadcrumb', child: Center( child: SingleChildScrollView( child: SizedBox( @@ -91,23 +91,37 @@ class _BreadCrumbsExampleState extends State { SizedBox( height: 50, ), - ZetaBreadcrumb(children: _children.sublist(0, 4)), + ZetaBreadcrumb( + children: _children.sublist(0, 4), + maxItemsShown: 3, + ), SizedBox( height: 50, ), - ZetaBreadcrumb(children: _children.sublist(0, 5)), + ZetaBreadcrumb( + children: _children.sublist(0, 5), + maxItemsShown: 4, + ), SizedBox( height: 50, ), - ZetaBreadcrumb(children: _children.sublist(0, 6)), + ZetaBreadcrumb( + children: _children.sublist(0, 6), + maxItemsShown: 3, + ), SizedBox( height: 50, ), - ZetaBreadcrumb(children: _children.sublist(0, 7)), + ZetaBreadcrumb( + children: _children.sublist(0, 7), + ), SizedBox( height: 50, ), - ZetaBreadcrumb(children: _children), + ZetaBreadcrumb( + children: _children, + maxItemsShown: 1, + ), ])), ), ), diff --git a/example/widgetbook/main.dart b/example/widgetbook/main.dart index e8eade35..740cb129 100644 --- a/example/widgetbook/main.dart +++ b/example/widgetbook/main.dart @@ -16,7 +16,7 @@ import 'pages/components/avatar_widgetbook.dart'; import 'pages/components/badges_widgetbook.dart'; import 'pages/components/banner_widgetbook.dart'; import 'pages/components/bottom_sheet_widgetbook.dart'; -import 'pages/components/breadcrumbs_widgetbook.dart'; +import 'pages/components/breadcrumb_widgetbook.dart'; import 'pages/components/button_widgetbook.dart'; import 'pages/components/chat_item_widgetbook.dart'; import 'pages/components/checkbox_widgetbook.dart'; @@ -192,7 +192,7 @@ class _HotReloadState extends State { WidgetbookUseCase(name: 'Accordion', builder: (context) => accordionUseCase(context)), WidgetbookUseCase(name: 'Banners', builder: (context) => bannerUseCase(context)), WidgetbookUseCase(name: 'Bottom Sheet', builder: (context) => bottomSheetContentUseCase(context)), - WidgetbookUseCase(name: 'BreadCrumbs', builder: (context) => breadCrumbUseCase(context)), + WidgetbookUseCase(name: 'Breadcrumb', builder: (context) => breadcrumbUseCase(context)), WidgetbookUseCase(name: 'Checkbox', builder: (context) => checkboxUseCase(context)), WidgetbookUseCase(name: 'Comms Button', builder: (context) => commsButtonUseCase(context)), WidgetbookUseCase(name: 'Date Input', builder: (context) => dateInputUseCase(context)), diff --git a/example/widgetbook/pages/components/breadcrumbs_widgetbook.dart b/example/widgetbook/pages/components/breadcrumb_widgetbook.dart similarity index 70% rename from example/widgetbook/pages/components/breadcrumbs_widgetbook.dart rename to example/widgetbook/pages/components/breadcrumb_widgetbook.dart index 015c9cd4..1dc8c1d4 100644 --- a/example/widgetbook/pages/components/breadcrumbs_widgetbook.dart +++ b/example/widgetbook/pages/components/breadcrumb_widgetbook.dart @@ -4,8 +4,6 @@ import 'package:zeta_flutter/zeta_flutter.dart'; import '../../utils/scaffold.dart'; import 'package:widgetbook/widgetbook.dart'; -import '../../utils/utils.dart'; - final List children = [ ZetaBreadcrumbItem(label: 'Breadcrumb', onPressed: () {}), ZetaBreadcrumbItem(label: 'Item 1', onPressed: () {}), @@ -16,14 +14,14 @@ final List children = [ ZetaBreadcrumbItem(label: 'Item 6', onPressed: () {}) ]; -Widget breadCrumbUseCase(BuildContext context) => WidgetbookScaffold( +Widget breadcrumbUseCase(BuildContext context) => WidgetbookScaffold( builder: (context, _) => Center( - child: BreadCrumbExample(context, children), + child: BreadcrumbExample(context, children), ), ); -class BreadCrumbExample extends StatelessWidget { - BreadCrumbExample(this.context, this.children); +class BreadcrumbExample extends StatelessWidget { + BreadcrumbExample(this.context, this.children); final BuildContext context; final List children; @@ -35,16 +33,22 @@ class BreadCrumbExample extends StatelessWidget { child: Column( children: [ ZetaBreadcrumb( + rounded: context.knobs.boolean(label: 'Rounded', initialValue: true), children: context.knobs.list( label: 'Items', labelBuilder: (value) => value.length.toString(), - initialOption: children.sublist(0, 2), + initialOption: children.sublist(0, 4), options: List.generate( children.length, (index) => children.sublist(0, index + 1), ), ), - activeIcon: iconKnob(context), + maxItemsShown: context.knobs.int.slider( + label: 'Max Items Shown', + initialValue: 2, + min: 1, + max: children.length, + ), ), ], ), diff --git a/lib/src/components/breadcrumb/breadcrumb.dart b/lib/src/components/breadcrumb/breadcrumb.dart index ca60f3c7..a1b9576f 100644 --- a/lib/src/components/breadcrumb/breadcrumb.dart +++ b/lib/src/components/breadcrumb/breadcrumb.dart @@ -2,8 +2,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import '../../../zeta_flutter.dart'; -// TODO(UX-1131): Refactor this to make BreadCrumbItem a class, not a widget. - /// The breadcrumb is a secondary navigation pattern that helps a user understand the hierarchy among levels and navigate back through them. /// /// [children] should consist of [ZetaBreadcrumbItem]s. @@ -19,20 +17,20 @@ class ZetaBreadcrumb extends ZetaStatefulWidget { super.key, super.rounded, required this.children, - this.activeIcon, this.moreSemanticLabel, + this.maxItemsShown = 2, }); /// Breadcrumb children final List children; - /// Active icon for breadcrumb - final IconData? activeIcon; - /// Label passed to wrapping [Semantics] widget. /// {@macro zeta-widget-semantic-label} final String? moreSemanticLabel; + /// Maximum number of items shown in the breadcrumb that aren't truncated. + final int maxItemsShown; + @override State createState() => _ZetaBreadcrumbsState(); @@ -42,8 +40,8 @@ class ZetaBreadcrumb extends ZetaStatefulWidget { properties ..add(IterableProperty('children', children)) ..add(DiagnosticsProperty('rounded', rounded)) - ..add(DiagnosticsProperty('activeIcon', activeIcon)) - ..add(StringProperty('moreSemanticLabel', moreSemanticLabel)); + ..add(StringProperty('moreSemanticLabel', moreSemanticLabel)) + ..add(IntProperty('maxItemsShown', maxItemsShown)); } } @@ -54,7 +52,7 @@ class _ZetaBreadcrumbsState extends State { @override void initState() { super.initState(); - // selects the last item + _selectedIndex = widget.children.length - 1; _children = [...widget.children]; } @@ -62,11 +60,9 @@ class _ZetaBreadcrumbsState extends State { @override void didUpdateWidget(ZetaBreadcrumb oldWidget) { super.didUpdateWidget(oldWidget); - // will always be equal??? - // if (widget.children.length != _children.length) { + _selectedIndex = widget.children.length - 1; _children = [...widget.children]; - // } } @override @@ -82,7 +78,11 @@ class _ZetaBreadcrumbsState extends State { Row( children: [ SizedBox(width: Zeta.of(context).spacing.small), - ZetaIcon(ZetaIcons.chevron_right, size: Zeta.of(context).spacing.xl), + ZetaIcon( + ZetaIcons.chevron_right, + size: Zeta.of(context).spacing.xl, + rounded: rounded, + ), SizedBox(width: Zeta.of(context).spacing.small), ], ), @@ -98,6 +98,7 @@ class _ZetaBreadcrumbsState extends State { return ZetaBreadcrumbItem( label: input.label, isSelected: _selectedIndex == index, + icon: input.icon, onPressed: () { setState(() { _selectedIndex = index; @@ -105,23 +106,24 @@ class _ZetaBreadcrumbsState extends State { }); input.onPressed.call(); }, - activeIcon: widget.activeIcon, ); } List renderedChildren(List children) { final List returnList = []; - if (children.length > 3) { + if (children.length > widget.maxItemsShown) { returnList.add(createBreadCrumb(children.first, 0)); final List truncatedChildren = []; - for (final (index, element) in children.sublist(1, children.length - 1).indexed) { + for (final (index, element) in children.sublist(1, children.length - (widget.maxItemsShown - 1)).indexed) { truncatedChildren.add(createBreadCrumb(element, index + 1)); } - returnList - ..add(_TruncatedItem(semanticLabel: widget.moreSemanticLabel, children: truncatedChildren)) - ..add(createBreadCrumb(children.last, children.length - 1)); + returnList.add(_TruncatedItem(semanticLabel: widget.moreSemanticLabel, children: truncatedChildren)); + + for (final (index, element) in children.sublist(children.length - (widget.maxItemsShown - 1)).indexed) { + returnList.add(createBreadCrumb(element, index + children.length - (widget.maxItemsShown))); + } } else { for (final (index, element) in children.indexed) { returnList.add(createBreadCrumb(element, index)); @@ -134,15 +136,15 @@ class _ZetaBreadcrumbsState extends State { /// Class for untruncated [ZetaBreadcrumbItem]. /// /// Should be a child of [ZetaBreadcrumb]. -class ZetaBreadcrumbItem extends StatefulWidget { +class ZetaBreadcrumbItem extends ZetaStatelessWidget { ///Constructor for [ZetaBreadcrumbItem] - const ZetaBreadcrumbItem({ + ZetaBreadcrumbItem({ super.key, + super.rounded, required this.label, this.icon, this.isSelected = false, required this.onPressed, - this.activeIcon, this.semanticLabel, }); @@ -158,9 +160,6 @@ class ZetaBreadcrumbItem extends StatefulWidget { /// Handles press for [ZetaBreadcrumbItem] final VoidCallback onPressed; - /// Active icon for [ZetaBreadcrumbItem] - final IconData? activeIcon; - /// Label passed to wrapping [Semantics] widget. /// /// {@macro zeta-widget-semantic-label} @@ -168,64 +167,50 @@ class ZetaBreadcrumbItem extends StatefulWidget { /// If null, [label] is used. final String? semanticLabel; - @override - State createState() => _ZetaBreadcrumbState(); + // /// If true, the [ZetaBreadcrumbItem] icon will be rounded. + // final bool? rounded; - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(ObjectFlagProperty.has('onPressed', onPressed)) - ..add(StringProperty('label', label)) - ..add(DiagnosticsProperty('icon', icon)) - ..add(DiagnosticsProperty('isSelected', isSelected)) - ..add(DiagnosticsProperty('activeIcon', activeIcon)) - ..add(StringProperty('semanticLabel', semanticLabel)); - } -} - -class _ZetaBreadcrumbState extends State { + /// Controller for [InkWell] states to control hover and pressed states. final controller = WidgetStatesController(); - @override - void initState() { - super.initState(); - controller.addListener(() { - if (context.mounted && mounted) { - setState(() {}); - } - }); - } - @override Widget build(BuildContext context) { final colors = Zeta.of(context).colors; - return Semantics( - label: widget.semanticLabel ?? widget.label, - selected: widget.isSelected, - child: InkWell( - statesController: controller, - onTap: widget.onPressed, - enableFeedback: false, - splashColor: Colors.transparent, - overlayColor: WidgetStateProperty.resolveWith((states) { - return Colors.transparent; - }), - child: Row( - children: [ - if (widget.isSelected) - Icon( - widget.activeIcon ?? ZetaIcons.star_round, - color: getColor(controller.value, colors), - ), - SizedBox( - width: Zeta.of(context).spacing.small, - ), - Text( - widget.label, - style: ZetaTextStyles.bodySmall.apply(color: getColor(controller.value, colors)), + final rounded = context.rounded; + return ZetaRoundedScope( + rounded: rounded, + child: Semantics( + label: semanticLabel ?? label, + selected: isSelected, + child: InkWell( + statesController: controller, + onTap: onPressed, + enableFeedback: false, + splashColor: Colors.transparent, + overlayColor: WidgetStateProperty.resolveWith((states) { + return Colors.transparent; + }), + child: ValueListenableBuilder( + valueListenable: controller, + builder: (context, value, child) => Row( + children: [ + if (icon != null) + ZetaIcon( + icon, + rounded: rounded, + color: getColor(value, colors), + ), + SizedBox( + width: Zeta.of(context).spacing.small, + ), + Text( + label, + style: ZetaTextStyles.bodySmall.apply(color: getColor(controller.value, colors)), + ), + if (child != null) child, + ], ), - ], + ), ), ), ); @@ -236,19 +221,26 @@ class _ZetaBreadcrumbState extends State { if (states.contains(WidgetState.hovered)) { return colors.blue; } - if (widget.isSelected) return colors.black; + if (isSelected) return colors.black; return colors.textSubtle; } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add( - DiagnosticsProperty( - 'controller', - controller, - ), - ); + properties + ..add( + DiagnosticsProperty( + 'controller', + controller, + ), + ) + ..add(StringProperty('label', label)) + ..add(DiagnosticsProperty('icon', icon)) + ..add(DiagnosticsProperty('isSelected', isSelected)) + ..add(ObjectFlagProperty.has('onPressed', onPressed)) + ..add(StringProperty('semanticLabel', semanticLabel)) + ..add(DiagnosticsProperty('rounded', rounded)); } } @@ -290,59 +282,62 @@ class _TruncatedItemState extends State<_TruncatedItem> { return _expanded ? expandedBreadcrumb() - : Semantics( - label: widget.semanticLabel, - button: true, - child: FilledButton( - onPressed: () { - setState(() { - _expanded = true; - }); - }, - style: ButtonStyle( - backgroundColor: WidgetStateProperty.resolveWith((states) { - if (states.contains(WidgetState.hovered)) { - return colors.surfaceHover; - } - if (states.contains(WidgetState.pressed)) { - return colors.primary.shade10; - } - if (states.contains(WidgetState.disabled)) { - return colors.surfaceDisabled; - } - return colors.warm.shade10; - }), - foregroundColor: WidgetStateProperty.resolveWith((states) { - if (states.contains(WidgetState.disabled)) { - return colors.textDisabled; - } - return colors.textDefault; - }), - shape: WidgetStatePropertyAll( - RoundedRectangleBorder( - borderRadius: (rounded ? Zeta.of(context).radius.minimal : Zeta.of(context).radius.none), + : ZetaRoundedScope( + rounded: rounded, + child: Semantics( + label: widget.semanticLabel, + button: true, + child: FilledButton( + onPressed: () { + setState(() { + _expanded = true; + }); + }, + style: ButtonStyle( + backgroundColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.hovered)) { + return colors.surfaceHover; + } + if (states.contains(WidgetState.pressed)) { + return colors.primary.shade10; + } + if (states.contains(WidgetState.disabled)) { + return colors.surfaceDisabled; + } + return colors.warm.shade10; + }), + foregroundColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.disabled)) { + return colors.textDisabled; + } + return colors.textDefault; + }), + shape: WidgetStatePropertyAll( + RoundedRectangleBorder( + borderRadius: (rounded ? Zeta.of(context).radius.minimal : Zeta.of(context).radius.none), + ), ), + side: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.focused)) { + return BorderSide( + width: ZetaBorders.medium, + color: colors.primary.shade100, + ); + } + if (states.isEmpty) { + return BorderSide(color: colors.borderDefault, width: 0.5); + } + return null; + }), + padding: WidgetStateProperty.all(EdgeInsets.zero), + minimumSize: WidgetStateProperty.all(Size.zero), + elevation: WidgetStatePropertyAll(Zeta.of(context).spacing.none), ), - side: WidgetStateProperty.resolveWith((states) { - if (states.contains(WidgetState.focused)) { - return BorderSide( - width: ZetaBorders.medium, - color: colors.primary.shade100, - ); - } - if (states.isEmpty) { - return BorderSide(color: colors.borderDefault, width: 0.5); - } - return null; - }), - padding: WidgetStateProperty.all(EdgeInsets.zero), - minimumSize: WidgetStateProperty.all(Size.zero), - elevation: WidgetStatePropertyAll(Zeta.of(context).spacing.none), + child: Icon( + rounded ? ZetaIcons.more_horizontal_round : ZetaIcons.more_horizontal_sharp, + size: Zeta.of(context).spacing.large, + ).paddingHorizontal(Zeta.of(context).spacing.small).paddingVertical(Zeta.of(context).spacing.minimum), ), - child: Icon( - rounded ? ZetaIcons.more_horizontal_round : ZetaIcons.more_horizontal_sharp, - size: Zeta.of(context).spacing.large, - ).paddingHorizontal(Zeta.of(context).spacing.small).paddingVertical(Zeta.of(context).spacing.minimum), ), ); } From cd843a63f9ac80598cd10b8add5479adaea3aaf0 Mon Sep 17 00:00:00 2001 From: Daniel Eshkeri Date: Thu, 14 Nov 2024 16:55:41 +0000 Subject: [PATCH 3/6] test: wrote content and accessibility tests --- lib/src/components/breadcrumb/breadcrumb.dart | 10 +- .../breadcrumb/breadcrumb_test.dart | 165 ++++++++++++++++++ 2 files changed, 171 insertions(+), 4 deletions(-) create mode 100644 test/src/components/breadcrumb/breadcrumb_test.dart diff --git a/lib/src/components/breadcrumb/breadcrumb.dart b/lib/src/components/breadcrumb/breadcrumb.dart index a1b9576f..397bdb1b 100644 --- a/lib/src/components/breadcrumb/breadcrumb.dart +++ b/lib/src/components/breadcrumb/breadcrumb.dart @@ -24,7 +24,7 @@ class ZetaBreadcrumb extends ZetaStatefulWidget { /// Breadcrumb children final List children; - /// Label passed to wrapping [Semantics] widget. + /// Semantic ;abel passed to [_TruncatedItem]. /// {@macro zeta-widget-semantic-label} final String? moreSemanticLabel; @@ -119,7 +119,8 @@ class _ZetaBreadcrumbsState extends State { for (final (index, element) in children.sublist(1, children.length - (widget.maxItemsShown - 1)).indexed) { truncatedChildren.add(createBreadCrumb(element, index + 1)); } - returnList.add(_TruncatedItem(semanticLabel: widget.moreSemanticLabel, children: truncatedChildren)); + returnList + .add(_TruncatedItem(semanticLabel: widget.moreSemanticLabel ?? 'View More', children: truncatedChildren)); for (final (index, element) in children.sublist(children.length - (widget.maxItemsShown - 1)).indexed) { returnList.add(createBreadCrumb(element, index + children.length - (widget.maxItemsShown))); @@ -252,7 +253,7 @@ class _TruncatedItem extends StatefulWidget { ///Constructor for [_TruncatedItem] const _TruncatedItem({ required this.children, - this.semanticLabel, + required this.semanticLabel, }); ///Breadcrumb children @@ -261,7 +262,7 @@ class _TruncatedItem extends StatefulWidget { /// Label passed to wrapping [Semantics] widget. /// /// {@macro zeta-widget-semantic-label} - final String? semanticLabel; + final String semanticLabel; @override State<_TruncatedItem> createState() => _TruncatedItemState(); @@ -287,6 +288,7 @@ class _TruncatedItemState extends State<_TruncatedItem> { child: Semantics( label: widget.semanticLabel, button: true, + excludeSemantics: true, child: FilledButton( onPressed: () { setState(() { diff --git a/test/src/components/breadcrumb/breadcrumb_test.dart b/test/src/components/breadcrumb/breadcrumb_test.dart new file mode 100644 index 00000000..f9f9779c --- /dev/null +++ b/test/src/components/breadcrumb/breadcrumb_test.dart @@ -0,0 +1,165 @@ +import 'dart:ui'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:zeta_flutter/zeta_flutter.dart'; + +import '../../../test_utils/test_app.dart'; +import '../../../test_utils/tolerant_comparator.dart'; +import '../../../test_utils/utils.dart'; + +void main() { + const String parentFolder = 'breadcrumb'; + + const goldenFile = GoldenFiles(component: parentFolder); + setUpAll(() { + goldenFileComparator = TolerantComparator(goldenFile.uri); + }); + + final List children = [ + ZetaBreadcrumbItem( + label: 'Breadcrumb', + onPressed: () {}, + icon: ZetaIcons.star, + ), + ZetaBreadcrumbItem(label: 'Item 1', onPressed: () {}), + ZetaBreadcrumbItem(label: 'Item 2', onPressed: () {}), + ZetaBreadcrumbItem( + label: 'Item 3', + onPressed: () {}, + icon: ZetaIcons.star, + ), + ZetaBreadcrumbItem(label: 'Item 4', onPressed: () {}), + ZetaBreadcrumbItem(label: 'Item 5', onPressed: () {}), + ZetaBreadcrumbItem(label: 'Item 6', onPressed: () {}), + ]; + + group('Accessibility Tests', () { + testWidgets('ZetaBreadcrumb meets accessibility standards', (tester) async { + final SemanticsHandle handle = tester.ensureSemantics(); + await tester.pumpWidget( + TestApp( + home: ZetaBreadcrumb( + children: children, + ), + ), + ); + + await expectLater(tester, meetsGuideline(androidTapTargetGuideline)); + await expectLater(tester, meetsGuideline(iOSTapTargetGuideline)); + await expectLater(tester, meetsGuideline(labeledTapTargetGuideline)); + await expectLater(tester, meetsGuideline(textContrastGuideline)); + + handle.dispose(); + }); + }); + + group('Content Tests', () { + final debugFillProperties = { + 'children': children.toString().replaceAll('[', '').replaceAll(']', ''), + }; + debugFillPropertiesTest( + ZetaBreadcrumb(children: children), + debugFillProperties, + ); + + // has the correct number of children + testWidgets('ZetaBreadcrumb has the correct number of children', (tester) async { + const maxItemsShown = 2; + + await tester.pumpWidget( + TestApp( + home: ZetaBreadcrumb( + maxItemsShown: maxItemsShown, + children: children, + ), + ), + ); + expect(find.byType(ZetaBreadcrumbItem), findsNWidgets(maxItemsShown)); + + // ignore: deprecated_member_use_from_same_package + await tester.tap(find.byType(TruncatedItem)); + await tester.pumpAndSettle(); + + expect(find.byType(ZetaBreadcrumbItem), findsNWidgets(children.length)); + }); + + // children have the correct labels + testWidgets('ZetaBreadcrumb children have the correct labels', (tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaBreadcrumb( + children: children, + ), + ), + ); + + expect(find.text('Breadcrumb'), findsOneWidget); + expect(find.text('Item ${children.length - 1}'), findsOneWidget); + + // ignore: deprecated_member_use_from_same_package + await tester.tap(find.byType(TruncatedItem)); + await tester.pumpAndSettle(); + + for (int i = 0; i < children.length; i++) { + expect(find.text(children[i].label), findsOneWidget); + } + }); + + // children have the correct icons (if any) + testWidgets(' ZetaBreadcrumb children have the correct icons', (tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaBreadcrumb( + children: children, + ), + ), + ); + + final iconFinder = find.byWidgetPredicate((widget) { + if (widget is ZetaIcon) { + return widget.icon == ZetaIcons.star; + } + return false; + }); + expect(iconFinder, findsOneWidget); + + // ignore: deprecated_member_use_from_same_package + await tester.tap(find.byType(TruncatedItem)); + await tester.pumpAndSettle(); + + final iconFinder1 = find.byWidgetPredicate((widget) { + if (widget is ZetaIcon) { + return widget.icon == ZetaIcons.star; + } + return false; + }); + expect(iconFinder1, findsNWidgets(2)); + }); + }); + + group('Dimensions Tests', () { + // each item is equally spaced + }); + + group('Styling Tests', () { + // label and icon colors are correct + // label font styles are correct + // icon sizes are correct + + // hovered state label and icon colors are correct + // selected state label and icon colors are correct + }); + + group('Interaction Tests', () { + // clicking on an item calls the onPressed callback + // clicking on an item removes the children list after it + }); + + group('Golden Tests', () { + // goldenTest(goldenFile, widget, 'PNG_FILE_NAME'); + }); + + group('Performance Tests', () {}); +} From bdcbe67df53d1468320f37f7d8d6c1feb4a08c63 Mon Sep 17 00:00:00 2001 From: Daniel Eshkeri Date: Fri, 15 Nov 2024 19:54:10 +0000 Subject: [PATCH 4/6] test: breadcrumb label and icon default colors test: breadcrumb items are spaced equally --- lib/src/components/breadcrumb/breadcrumb.dart | 7 +- .../breadcrumb/breadcrumb_test.dart | 72 +++++++++++++++++-- 2 files changed, 74 insertions(+), 5 deletions(-) diff --git a/lib/src/components/breadcrumb/breadcrumb.dart b/lib/src/components/breadcrumb/breadcrumb.dart index 397bdb1b..cc76efd1 100644 --- a/lib/src/components/breadcrumb/breadcrumb.dart +++ b/lib/src/components/breadcrumb/breadcrumb.dart @@ -82,6 +82,7 @@ class _ZetaBreadcrumbsState extends State { ZetaIcons.chevron_right, size: Zeta.of(context).spacing.xl, rounded: rounded, + color: Zeta.of(context).colors.textSubtle, ), SizedBox(width: Zeta.of(context).spacing.small), ], @@ -351,7 +352,11 @@ class _TruncatedItemState extends State<_TruncatedItem> { Row( children: [ SizedBox(width: Zeta.of(context).spacing.small), - ZetaIcon(ZetaIcons.chevron_right, size: Zeta.of(context).spacing.xl), + ZetaIcon( + ZetaIcons.chevron_right, + size: Zeta.of(context).spacing.xl, + color: Zeta.of(context).colors.textSubtle, + ), SizedBox(width: Zeta.of(context).spacing.small), ], ), diff --git a/test/src/components/breadcrumb/breadcrumb_test.dart b/test/src/components/breadcrumb/breadcrumb_test.dart index f9f9779c..9fe86950 100644 --- a/test/src/components/breadcrumb/breadcrumb_test.dart +++ b/test/src/components/breadcrumb/breadcrumb_test.dart @@ -1,6 +1,3 @@ -import 'dart:ui'; - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:zeta_flutter/zeta_flutter.dart'; @@ -141,10 +138,77 @@ void main() { group('Dimensions Tests', () { // each item is equally spaced + testWidgets('ZetaBreadcrumb items are equally spaced', (tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaBreadcrumb( + maxItemsShown: 7, + children: [ + ZetaBreadcrumbItem(label: 'Item 0', onPressed: () {}), + ZetaBreadcrumbItem(label: 'Item 1', onPressed: () {}), + ZetaBreadcrumbItem(label: 'Item 2', onPressed: () {}), + ZetaBreadcrumbItem(label: 'Item 3', onPressed: () {}), + ZetaBreadcrumbItem(label: 'Item 4', onPressed: () {}), + ZetaBreadcrumbItem(label: 'Item 5', onPressed: () {}), + ZetaBreadcrumbItem(label: 'Item 6', onPressed: () {}), + ], + ), + ), + ); + + final itemFinder = find.byType(ZetaBreadcrumbItem); + + final List itemPositions = []; + for (int i = 0; i < children.length; i++) { + expect(itemFinder.at(i), findsOneWidget); + itemPositions.add(tester.getTopLeft(itemFinder.at(i)).dx); + } + + final double distance = itemPositions[1] - itemPositions[0]; + for (int i = 1; i < itemPositions.length; i++) { + expect(itemPositions[i] - itemPositions[i - 1], distance); + } + }); }); group('Styling Tests', () { - // label and icon colors are correct + testWidgets('ZetaBreadcrumb label and icon colors are correct', (tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaBreadcrumb( + maxItemsShown: 7, + children: children, + ), + ), + ); + final context = getBuildContext(tester, ZetaBreadcrumb); + final colors = Zeta.of(context).colors; + + final labelFinder = find.byType(Text); + final iconFinder = find.byType(ZetaIcon); + + for (int i = 0; i < children.length; i++) { + if (i == children.length - 1) { + expect( + (tester.firstWidget(labelFinder.at(i)) as Text).style?.color, + colors.black, + ); + } else { + expect( + (tester.firstWidget(labelFinder.at(i)) as Text).style?.color, + colors.textSubtle, + ); + } + } + + for (int i = 0; i < iconFinder.evaluate().length; i++) { + expect( + (tester.firstWidget(iconFinder.at(i)) as ZetaIcon).color, + colors.textSubtle, + ); + } + }); + // label font styles are correct // icon sizes are correct From 6bfa3cf60b8d8f5ad68298e276a3384d9fc11907 Mon Sep 17 00:00:00 2001 From: Daniel Eshkeri Date: Mon, 18 Nov 2024 11:28:45 +0000 Subject: [PATCH 5/6] fix: breadcrumb select index --- .../pages/components/breadcrumb_example.dart | 111 +++--------------- lib/src/components/breadcrumb/breadcrumb.dart | 2 +- .../breadcrumb/breadcrumb_test.dart | 1 - 3 files changed, 20 insertions(+), 94 deletions(-) diff --git a/example/lib/pages/components/breadcrumb_example.dart b/example/lib/pages/components/breadcrumb_example.dart index 5bd82f19..948f0ceb 100644 --- a/example/lib/pages/components/breadcrumb_example.dart +++ b/example/lib/pages/components/breadcrumb_example.dart @@ -18,55 +18,14 @@ class _BreadcrumbExampleState extends State { void initState() { super.initState(); _children = [ - ZetaBreadcrumbItem( - label: 'Breadcrumb', - onPressed: () { - print("Breadcrumb clicked"); - }, - ), - ZetaBreadcrumbItem( - label: 'Item 1', - onPressed: () { - print("Breadcrumb clicked"); - }, - ), - ZetaBreadcrumbItem( - label: 'Item 2', - onPressed: () { - print("Breadcrumb clicked"); - }, - ), - ZetaBreadcrumbItem( - label: 'Item 3', - icon: ZetaIcons.star, - onPressed: () { - print("Breadcrumb clicked"); - }, - ), - ZetaBreadcrumbItem( - label: 'Item 4', - onPressed: () { - print("Breadcrumb clicked"); - }, - ), - ZetaBreadcrumbItem( - label: 'Item 5', - onPressed: () { - print("Breadcrumb clicked"); - }, - ), - ZetaBreadcrumbItem( - label: 'Item 6', - onPressed: () { - print("Breadcrumb clicked"); - }, - ), - ZetaBreadcrumbItem( - label: 'Item 7', - onPressed: () { - print("Breadcrumb clicked"); - }, - ), + ZetaBreadcrumbItem(label: 'Breadcrumb', onPressed: () {}), + ZetaBreadcrumbItem(label: 'Item 1', onPressed: () {}), + ZetaBreadcrumbItem(label: 'Item 2', onPressed: () {}), + ZetaBreadcrumbItem(label: 'Item 3', icon: ZetaIcons.star, onPressed: () {}), + ZetaBreadcrumbItem(label: 'Item 4', onPressed: () {}), + ZetaBreadcrumbItem(label: 'Item 5', onPressed: () {}), + ZetaBreadcrumbItem(label: 'Item 6', onPressed: () {}), + ZetaBreadcrumbItem(label: 'Item 7', onPressed: () {}), ]; } @@ -77,52 +36,20 @@ class _BreadcrumbExampleState extends State { child: Center( child: SingleChildScrollView( child: SizedBox( - width: double.infinity, - child: Column(children: [ + width: double.infinity, + child: Column( + children: [ ZetaBreadcrumb(children: _children.sublist(0, 1)), - SizedBox( - height: 50, - ), ZetaBreadcrumb(children: _children.sublist(0, 2)), - SizedBox( - height: 50, - ), ZetaBreadcrumb(children: _children.sublist(0, 3)), - SizedBox( - height: 50, - ), - ZetaBreadcrumb( - children: _children.sublist(0, 4), - maxItemsShown: 3, - ), - SizedBox( - height: 50, - ), - ZetaBreadcrumb( - children: _children.sublist(0, 5), - maxItemsShown: 4, - ), - SizedBox( - height: 50, - ), - ZetaBreadcrumb( - children: _children.sublist(0, 6), - maxItemsShown: 3, - ), - SizedBox( - height: 50, - ), - ZetaBreadcrumb( - children: _children.sublist(0, 7), - ), - SizedBox( - height: 50, - ), - ZetaBreadcrumb( - children: _children, - maxItemsShown: 1, - ), - ])), + ZetaBreadcrumb(children: _children.sublist(0, 4), maxItemsShown: 3), + ZetaBreadcrumb(children: _children.sublist(0, 5), maxItemsShown: 5), + ZetaBreadcrumb(children: _children.sublist(0, 6), maxItemsShown: 3), + ZetaBreadcrumb(children: _children.sublist(0, 7)), + ZetaBreadcrumb(children: _children, maxItemsShown: 1), + ].gap(50), + ), + ), ), ), ); diff --git a/lib/src/components/breadcrumb/breadcrumb.dart b/lib/src/components/breadcrumb/breadcrumb.dart index cc76efd1..d914f750 100644 --- a/lib/src/components/breadcrumb/breadcrumb.dart +++ b/lib/src/components/breadcrumb/breadcrumb.dart @@ -124,7 +124,7 @@ class _ZetaBreadcrumbsState extends State { .add(_TruncatedItem(semanticLabel: widget.moreSemanticLabel ?? 'View More', children: truncatedChildren)); for (final (index, element) in children.sublist(children.length - (widget.maxItemsShown - 1)).indexed) { - returnList.add(createBreadCrumb(element, index + children.length - (widget.maxItemsShown))); + returnList.add(createBreadCrumb(element, index + children.length - (widget.maxItemsShown) + 1)); } } else { for (final (index, element) in children.indexed) { diff --git a/test/src/components/breadcrumb/breadcrumb_test.dart b/test/src/components/breadcrumb/breadcrumb_test.dart index 9fe86950..bff2fc5f 100644 --- a/test/src/components/breadcrumb/breadcrumb_test.dart +++ b/test/src/components/breadcrumb/breadcrumb_test.dart @@ -68,7 +68,6 @@ void main() { await tester.pumpWidget( TestApp( home: ZetaBreadcrumb( - maxItemsShown: maxItemsShown, children: children, ), ), From ab4a2e2970bef640dcff79fc5622947a71490e60 Mon Sep 17 00:00:00 2001 From: Daniel Eshkeri Date: Mon, 18 Nov 2024 15:38:23 +0000 Subject: [PATCH 6/6] fix: typo ";abel" => "label" --- lib/src/components/breadcrumb/breadcrumb.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/components/breadcrumb/breadcrumb.dart b/lib/src/components/breadcrumb/breadcrumb.dart index d914f750..f52f6184 100644 --- a/lib/src/components/breadcrumb/breadcrumb.dart +++ b/lib/src/components/breadcrumb/breadcrumb.dart @@ -24,7 +24,7 @@ class ZetaBreadcrumb extends ZetaStatefulWidget { /// Breadcrumb children final List children; - /// Semantic ;abel passed to [_TruncatedItem]. + /// Semantic label passed to [_TruncatedItem]. /// {@macro zeta-widget-semantic-label} final String? moreSemanticLabel;