diff --git a/packages/flutter/lib/src/cupertino/dialog.dart b/packages/flutter/lib/src/cupertino/dialog.dart index 5998325f13..8673733113 100644 --- a/packages/flutter/lib/src/cupertino/dialog.dart +++ b/packages/flutter/lib/src/cupertino/dialog.dart @@ -703,25 +703,28 @@ class CupertinoActionSheetAction extends StatelessWidget { style = style.copyWith(fontWeight: FontWeight.w600); } - return GestureDetector( - onTap: onPressed, - behavior: HitTestBehavior.opaque, - child: ConstrainedBox( - constraints: const BoxConstraints( - minHeight: _kActionSheetButtonHeight, - ), - child: Semantics( - button: true, - child: Container( - alignment: Alignment.center, - padding: const EdgeInsets.symmetric( - vertical: 16.0, - horizontal: 10.0, - ), - child: DefaultTextStyle( - style: style, - textAlign: TextAlign.center, - child: child, + return MouseRegion( + cursor: onPressed != null && kIsWeb ? SystemMouseCursors.click : MouseCursor.defer, + child: GestureDetector( + onTap: onPressed, + behavior: HitTestBehavior.opaque, + child: ConstrainedBox( + constraints: const BoxConstraints( + minHeight: _kActionSheetButtonHeight, + ), + child: Semantics( + button: true, + child: Container( + alignment: Alignment.center, + padding: const EdgeInsets.symmetric( + vertical: 16.0, + horizontal: 10.0, + ), + child: DefaultTextStyle( + style: style, + textAlign: TextAlign.center, + child: child, + ), ), ), ), @@ -1751,18 +1754,21 @@ class CupertinoDialogAction extends StatelessWidget { content: child, ); - return GestureDetector( - excludeFromSemantics: true, - onTap: onPressed, - behavior: HitTestBehavior.opaque, - child: ConstrainedBox( - constraints: const BoxConstraints( - minHeight: _kDialogMinButtonHeight, - ), - child: Container( - alignment: Alignment.center, - padding: EdgeInsets.all(_calculatePadding(context)), - child: sizedContent, + return MouseRegion( + cursor: onPressed != null && kIsWeb ? SystemMouseCursors.click : MouseCursor.defer, + child: GestureDetector( + excludeFromSemantics: true, + onTap: onPressed, + behavior: HitTestBehavior.opaque, + child: ConstrainedBox( + constraints: const BoxConstraints( + minHeight: _kDialogMinButtonHeight, + ), + child: Container( + alignment: Alignment.center, + padding: EdgeInsets.all(_calculatePadding(context)), + child: sizedContent, + ), ), ), ); diff --git a/packages/flutter/test/cupertino/action_sheet_test.dart b/packages/flutter/test/cupertino/action_sheet_test.dart index 1859a1b809..6ca2486d4e 100644 --- a/packages/flutter/test/cupertino/action_sheet_test.dart +++ b/packages/flutter/test/cupertino/action_sheet_test.dart @@ -9,7 +9,10 @@ @Tags(['no-shuffle']) import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -1070,6 +1073,39 @@ void main() { // one for the content. expect(find.byType(CupertinoScrollbar), findsNWidgets(2)); }, variant: TargetPlatformVariant.all()); + + testWidgets('Hovering over Cupertino action sheet action updates cursor to clickable on Web', (WidgetTester tester) async { + await tester.pumpWidget( + createAppWithButtonThatLaunchesActionSheet( + CupertinoActionSheet( + title: const Text('The title'), + message: const Text('Message'), + actions: [ + CupertinoActionSheetAction( + child: const Text('One'), + onPressed: () { }, + ), + ], + ) + ), + ); + await tester.tap(find.text('Go')); + await tester.pump(); + + final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1); + await gesture.addPointer(location: const Offset(10, 10)); + await tester.pumpAndSettle(); + expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); + + final Offset actionSheetAction = tester.getCenter(find.text('One')); + await gesture.moveTo(actionSheetAction); + addTearDown(gesture.removePointer); + await tester.pumpAndSettle(); + expect( + RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), + kIsWeb ? SystemMouseCursors.click : SystemMouseCursors.basic, + ); + }); } RenderBox findScrollableActionsSectionRenderBox(WidgetTester tester) { diff --git a/packages/flutter/test/cupertino/dialog_test.dart b/packages/flutter/test/cupertino/dialog_test.dart index 1d867f2275..222bd15877 100644 --- a/packages/flutter/test/cupertino/dialog_test.dart +++ b/packages/flutter/test/cupertino/dialog_test.dart @@ -12,6 +12,7 @@ import 'dart:ui'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../rendering/mock_canvas.dart'; @@ -1441,6 +1442,51 @@ void main() { expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(390.0, 600.0)); }); }); + + testWidgets('Hovering over Cupertino alert dialog action updates cursor to clickable on Web', (WidgetTester tester) async { + await tester.pumpWidget( + createAppWithButtonThatLaunchesDialog( + dialogBuilder: (BuildContext context) { + return MediaQuery( + data: MediaQuery.of(context).copyWith(textScaleFactor: 3.0), + child: RepaintBoundary( + child: CupertinoAlertDialog( + title: const Text('Title'), + content: const Text('text'), + actions: [ + CupertinoDialogAction( + onPressed: () {}, + child: const Text('NO'), + ), + CupertinoDialogAction( + onPressed: () {}, + child: const Text('OK'), + ), + ], + ), + ), + ); + }, + ), + ); + + await tester.tap(find.text('Go')); + await tester.pumpAndSettle(); + + final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1); + await gesture.addPointer(location: const Offset(10, 10)); + await tester.pumpAndSettle(); + expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); + + final Offset dialogAction = tester.getCenter(find.text('OK')); + await gesture.moveTo(dialogAction); + addTearDown(gesture.removePointer); + await tester.pumpAndSettle(); + expect( + RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), + kIsWeb ? SystemMouseCursors.click : SystemMouseCursors.basic, + ); + }); } RenderBox findActionButtonRenderBoxByTitle(WidgetTester tester, String title) {