Unverified Commit 575ced6c authored by Justin McCandless's avatar Justin McCandless Committed by GitHub

Fix context menu web examples (#120104)

The context menu examples on the docs site now work on the web.
parent ec524ed0
...@@ -7,15 +7,21 @@ ...@@ -7,15 +7,21 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(const MyApp()); void main() => runApp(const MyApp());
/// A builder that includes an Offset to draw the context menu at. /// A builder that includes an Offset to draw the context menu at.
typedef ContextMenuBuilder = Widget Function(BuildContext context, Offset offset); typedef ContextMenuBuilder = Widget Function(BuildContext context, Offset offset);
class MyApp extends StatelessWidget { class MyApp extends StatefulWidget {
const MyApp({super.key}); const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
void _showDialog (BuildContext context) { void _showDialog (BuildContext context) {
Navigator.of(context).push( Navigator.of(context).push(
DialogRoute<void>( DialogRoute<void>(
...@@ -26,6 +32,24 @@ class MyApp extends StatelessWidget { ...@@ -26,6 +32,24 @@ class MyApp extends StatelessWidget {
); );
} }
@override
void initState() {
super.initState();
// On web, disable the browser's context menu since this example uses a custom
// Flutter-rendered context menu.
if (kIsWeb) {
BrowserContextMenu.disableContextMenu();
}
}
@override
void dispose() {
if (kIsWeb) {
BrowserContextMenu.enableContextMenu();
}
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
...@@ -58,7 +82,7 @@ class MyApp extends StatelessWidget { ...@@ -58,7 +82,7 @@ class MyApp extends StatelessWidget {
child: ListView( child: ListView(
children: <Widget>[ children: <Widget>[
Container(height: 20.0), Container(height: 20.0),
const Text('Right click or long press anywhere (not just on this text!) to show the custom menu.'), const Text('Right click (desktop) or long press (mobile) anywhere, not just on this text, to show the custom menu.'),
], ],
), ),
), ),
......
...@@ -6,17 +6,42 @@ ...@@ -6,17 +6,42 @@
// appearance. // appearance.
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(MyApp()); void main() => runApp(const MyApp());
class MyApp extends StatelessWidget { class MyApp extends StatefulWidget {
MyApp({super.key}); const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final TextEditingController _controller = TextEditingController( final TextEditingController _controller = TextEditingController(
text: 'Right click or long press to see the menu with custom buttons.', text: 'Right click (desktop) or long press (mobile) to see the menu with custom buttons.',
); );
@override
void initState() {
super.initState();
// On web, disable the browser's context menu since this example uses a custom
// Flutter-rendered context menu.
if (kIsWeb) {
BrowserContextMenu.disableContextMenu();
}
}
@override
void dispose() {
if (kIsWeb) {
BrowserContextMenu.enableContextMenu();
}
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
......
...@@ -5,15 +5,23 @@ ...@@ -5,15 +5,23 @@
// This example demonstrates showing a custom context menu only when some // This example demonstrates showing a custom context menu only when some
// narrowly defined text is selected. // narrowly defined text is selected.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(MyApp()); void main() => runApp(const MyApp());
const String emailAddress = 'me@example.com'; const String emailAddress = 'me@example.com';
const String text = 'Select the email address and open the menu: $emailAddress'; const String text = 'Select the email address and open the menu: $emailAddress';
class MyApp extends StatelessWidget { class MyApp extends StatefulWidget {
MyApp({super.key}); const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final TextEditingController _controller = TextEditingController( final TextEditingController _controller = TextEditingController(
text: text, text: text,
...@@ -29,6 +37,24 @@ class MyApp extends StatelessWidget { ...@@ -29,6 +37,24 @@ class MyApp extends StatelessWidget {
); );
} }
@override
void initState() {
super.initState();
// On web, disable the browser's context menu since this example uses a custom
// Flutter-rendered context menu.
if (kIsWeb) {
BrowserContextMenu.disableContextMenu();
}
}
@override
void dispose() {
if (kIsWeb) {
BrowserContextMenu.enableContextMenu();
}
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
......
...@@ -5,17 +5,42 @@ ...@@ -5,17 +5,42 @@
// This example demonstrates how to create a custom toolbar that retains the // This example demonstrates how to create a custom toolbar that retains the
// look of the default buttons for the current platform. // look of the default buttons for the current platform.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(MyApp()); void main() => runApp(const MyApp());
class MyApp extends StatelessWidget { class MyApp extends StatefulWidget {
MyApp({super.key}); const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final TextEditingController _controller = TextEditingController( final TextEditingController _controller = TextEditingController(
text: 'Right click or long press to see the menu with a custom toolbar.', text: 'Right click (desktop) or long press (mobile) to see the menu with a custom toolbar.',
); );
@override
void initState() {
super.initState();
// On web, disable the browser's context menu since this example uses a custom
// Flutter-rendered context menu.
if (kIsWeb) {
BrowserContextMenu.disableContextMenu();
}
}
@override
void dispose() {
if (kIsWeb) {
BrowserContextMenu.enableContextMenu();
}
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
......
...@@ -5,15 +5,22 @@ ...@@ -5,15 +5,22 @@
// This example demonstrates a custom context menu in non-editable text using // This example demonstrates a custom context menu in non-editable text using
// SelectionArea. // SelectionArea.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(const MyApp()); void main() => runApp(const MyApp());
const String text = 'I am some text inside of SelectionArea. Right click or long press me to show the customized context menu.'; const String text = 'I am some text inside of SelectionArea. Right click (desktop) or long press (mobile) me to show the customized context menu.';
class MyApp extends StatelessWidget { class MyApp extends StatefulWidget {
const MyApp({super.key}); const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
void _showDialog (BuildContext context) { void _showDialog (BuildContext context) {
Navigator.of(context).push( Navigator.of(context).push(
DialogRoute<void>( DialogRoute<void>(
...@@ -24,6 +31,24 @@ class MyApp extends StatelessWidget { ...@@ -24,6 +31,24 @@ class MyApp extends StatelessWidget {
); );
} }
@override
void initState() {
super.initState();
// On web, disable the browser's context menu since this example uses a custom
// Flutter-rendered context menu.
if (kIsWeb) {
BrowserContextMenu.disableContextMenu();
}
}
@override
void dispose() {
if (kIsWeb) {
BrowserContextMenu.enableContextMenu();
}
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
......
...@@ -2,8 +2,10 @@ ...@@ -2,8 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_api_samples/material/context_menu/context_menu_controller.0.dart' as example; import 'package:flutter_api_samples/material/context_menu/context_menu_controller.0.dart' as example;
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
...@@ -13,6 +15,8 @@ void main() { ...@@ -13,6 +15,8 @@ void main() {
const example.MyApp(), const example.MyApp(),
); );
expect(BrowserContextMenu.enabled, !kIsWeb);
expect(find.byType(AdaptiveTextSelectionToolbar), findsNothing); expect(find.byType(AdaptiveTextSelectionToolbar), findsNothing);
// Right clicking the middle of the app shows the custom context menu. // Right clicking the middle of the app shows the custom context menu.
......
...@@ -3,16 +3,20 @@ ...@@ -3,16 +3,20 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_api_samples/material/context_menu/editable_text_toolbar_builder.0.dart' as example; import 'package:flutter_api_samples/material/context_menu/editable_text_toolbar_builder.0.dart' as example;
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
void main() { void main() {
testWidgets('showing and hiding the context menu in TextField with custom buttons', (WidgetTester tester) async { testWidgets('showing and hiding the context menu in TextField with custom buttons', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
example.MyApp(), const example.MyApp(),
); );
expect(BrowserContextMenu.enabled, !kIsWeb);
await tester.tap(find.byType(EditableText)); await tester.tap(find.byType(EditableText));
await tester.pump(); await tester.pump();
......
...@@ -2,17 +2,21 @@ ...@@ -2,17 +2,21 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_api_samples/material/context_menu/editable_text_toolbar_builder.1.dart' as example; import 'package:flutter_api_samples/material/context_menu/editable_text_toolbar_builder.1.dart' as example;
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
void main() { void main() {
testWidgets('showing and hiding the custom context menu in TextField with a specific selection', (WidgetTester tester) async { testWidgets('showing and hiding the custom context menu in TextField with a specific selection', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
example.MyApp(), const example.MyApp(),
); );
expect(BrowserContextMenu.enabled, !kIsWeb);
expect(find.byType(AdaptiveTextSelectionToolbar), findsNothing); expect(find.byType(AdaptiveTextSelectionToolbar), findsNothing);
// Right clicking the Text in the TextField shows the custom context menu, // Right clicking the Text in the TextField shows the custom context menu,
......
...@@ -5,15 +5,18 @@ ...@@ -5,15 +5,18 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_api_samples/material/context_menu/editable_text_toolbar_builder.2.dart' as example; import 'package:flutter_api_samples/material/context_menu/editable_text_toolbar_builder.2.dart' as example;
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
void main() { void main() {
testWidgets('showing and hiding the context menu in TextField with a custom toolbar', (WidgetTester tester) async { testWidgets('showing and hiding the context menu in TextField with a custom toolbar', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
example.MyApp(), const example.MyApp(),
); );
expect(BrowserContextMenu.enabled, !kIsWeb);
await tester.tap(find.byType(EditableText)); await tester.tap(find.byType(EditableText));
await tester.pump(); await tester.pump();
......
...@@ -2,8 +2,10 @@ ...@@ -2,8 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_api_samples/material/context_menu/selectable_region_toolbar_builder.0.dart' as example; import 'package:flutter_api_samples/material/context_menu/selectable_region_toolbar_builder.0.dart' as example;
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
...@@ -13,6 +15,8 @@ void main() { ...@@ -13,6 +15,8 @@ void main() {
const example.MyApp(), const example.MyApp(),
); );
expect(BrowserContextMenu.enabled, !kIsWeb);
// Allow the selection overlay geometry to be created. // Allow the selection overlay geometry to be created.
await tester.pump(); await tester.pump();
......
...@@ -18,6 +18,11 @@ import 'overlay.dart'; ...@@ -18,6 +18,11 @@ import 'overlay.dart';
/// ///
/// ** See code in examples/api/lib/material/context_menu/context_menu_controller.0.dart ** /// ** See code in examples/api/lib/material/context_menu/context_menu_controller.0.dart **
/// {@end-tool} /// {@end-tool}
///
/// See also:
///
/// * [BrowserContextMenu], which allows the browser's context menu on web to
/// be disabled and Flutter-rendered context menus to appear.
class ContextMenuController { class ContextMenuController {
/// Creates a context menu that can be shown with [show]. /// Creates a context menu that can be shown with [show].
ContextMenuController({ ContextMenuController({
......
...@@ -1773,6 +1773,8 @@ class EditableText extends StatefulWidget { ...@@ -1773,6 +1773,8 @@ class EditableText extends StatefulWidget {
/// * [AdaptiveTextSelectionToolbar.getAdaptiveButtons], which builds the /// * [AdaptiveTextSelectionToolbar.getAdaptiveButtons], which builds the
/// button Widgets for the current platform given /// button Widgets for the current platform given
/// [ContextMenuButtonItem]s. /// [ContextMenuButtonItem]s.
/// * [BrowserContextMenu], which allows the browser's context menu on web
/// to be disabled and Flutter-rendered context menus to appear.
/// {@endtemplate} /// {@endtemplate}
/// ///
/// If not provided, no context menu will be shown. /// If not provided, no context menu will be shown.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment