diff --git a/lib/shared/widgets/querya_dropdown.dart b/lib/shared/widgets/querya_dropdown.dart index 53c9b942..b917d6d2 100644 --- a/lib/shared/widgets/querya_dropdown.dart +++ b/lib/shared/widgets/querya_dropdown.dart @@ -88,6 +88,10 @@ class _QueryaDropdownState extends material.State> { var _closingWithExit = false; var _exitGeneration = 0; + /// Keys the trigger so the open menu can be at least as wide as it (#1444). + final material.GlobalKey _triggerKey = material.GlobalKey(); + double _menuMinWidth = 0; + @override void initState() { super.initState(); @@ -359,6 +363,8 @@ class _QueryaDropdownState extends material.State> { _exitGeneration++; _closingWithExit = false; _menuOpen.value = true; + final width = _triggerKey.currentContext?.size?.width ?? 0; + if (width != _menuMinWidth) setState(() => _menuMinWidth = width); }, onClose: () { // Outside-tap / focus loss: overlay already gone — snap state only. @@ -381,6 +387,9 @@ class _QueryaDropdownState extends material.State> { shadowColor: const material.WidgetStatePropertyAll( QueryaDropdownTokens.menuShadowColor, ), + minimumSize: material.WidgetStatePropertyAll( + material.Size(_menuMinWidth, 0), + ), maximumSize: material.WidgetStatePropertyAll( material.Size(double.infinity, effectiveMaxHeight), ), @@ -412,10 +421,11 @@ class _QueryaDropdownState extends material.State> { label: label, fieldWidth: fieldWidth, ); + final keyed = material.KeyedSubtree(key: _triggerKey, child: trigger); if (widget.expandToParent) { - return material.SizedBox(width: double.infinity, child: trigger); + return material.SizedBox(width: double.infinity, child: keyed); } - return trigger; + return keyed; }, ); diff --git a/test/shared/querya_dropdown_test.dart b/test/shared/querya_dropdown_test.dart index 63998360..91e8d5b3 100644 --- a/test/shared/querya_dropdown_test.dart +++ b/test/shared/querya_dropdown_test.dart @@ -46,6 +46,46 @@ void main() { expect(box.height, QueryaDropdownTokens.triggerHeight); }); + testWidgets('the open menu is at least as wide as the trigger', + (tester) async { + await tester.pumpWidget( + queryaThemeTestShell( + child: material.Scaffold( + body: material.Align( + alignment: material.Alignment.topLeft, + child: QueryaDropdown( + value: 1, + width: 320, + items: const [ + QueryaDropdownItem(value: 1, label: 'One'), + QueryaDropdownItem(value: 2, label: 'Two'), + ], + onSelected: (_) {}, + ), + ), + ), + ), + ); + await tester.pump(); + + final triggerWidth = tester.getSize(find.byType(QueryaDropdown)).width; + expect(triggerWidth, 320); + + await tester.tap(find.text('One')); + await tester.pumpAndSettle(); + + final surfaces = find.ancestor( + of: find.text('Two'), + matching: find.byType(material.Material), + ); + final widest = surfaces + .evaluate() + .map((e) => tester.getSize(find.byWidget(e.widget)).width) + .reduce((a, b) => a > b ? a : b); + + expect(widest, greaterThanOrEqualTo(triggerWidth)); + }); + testWidgets('opens menu and reports selection', (tester) async { int? picked; await tester.pumpWidget(