Unverified Commit 971881c8 authored by Justin McCandless's avatar Justin McCandless Committed by GitHub

Fix web text field shortcuts (#79056)

parent dfc134dd
......@@ -4,7 +4,7 @@
import 'dart:ui' as ui show BoxHeightStyle, BoxWidthStyle;
import 'package:flutter/foundation.dart' show defaultTargetPlatform, kIsWeb;
import 'package:flutter/foundation.dart' show defaultTargetPlatform;
import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
......@@ -18,16 +18,6 @@ import 'theme.dart';
export 'package:flutter/services.dart' show TextInputType, TextInputAction, TextCapitalization, SmartQuotesType, SmartDashesType;
// This is a temporary fix for: https://github.com/flutter/flutter/issues/79012
/// A map used to disable scrolling shortcuts in text fields.
final Map<LogicalKeySet, Intent> _webScrollShortcutOverrides = <LogicalKeySet, Intent>{
LogicalKeySet(LogicalKeyboardKey.space): DoNothingAndStopPropagationIntent(),
LogicalKeySet(LogicalKeyboardKey.arrowUp): DoNothingAndStopPropagationIntent(),
LogicalKeySet(LogicalKeyboardKey.arrowDown): DoNothingAndStopPropagationIntent(),
LogicalKeySet(LogicalKeyboardKey.arrowLeft): DoNothingAndStopPropagationIntent(),
LogicalKeySet(LogicalKeyboardKey.arrowRight): DoNothingAndStopPropagationIntent(),
};
const TextStyle _kDefaultPlaceholderStyle = TextStyle(
fontWeight: FontWeight.w400,
color: CupertinoColors.placeholderText,
......@@ -1222,7 +1212,7 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
),
);
final Widget child = Semantics(
return Semantics(
enabled: enabled,
onTap: !enabled || widget.readOnly ? null : () {
if (!controller.selection.isValid) {
......@@ -1248,13 +1238,5 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
),
),
);
if (kIsWeb) {
return Shortcuts(
shortcuts: _webScrollShortcutOverrides,
child: child,
);
}
return child;
}
}
......@@ -24,16 +24,6 @@ import 'theme.dart';
export 'package:flutter/services.dart' show TextInputType, TextInputAction, TextCapitalization, SmartQuotesType, SmartDashesType;
// This is a temporary fix for: https://github.com/flutter/flutter/issues/79012
/// A map used to disable scrolling shortcuts in text fields.
final Map<LogicalKeySet, Intent> _webScrollShortcutOverrides = <LogicalKeySet, Intent>{
LogicalKeySet(LogicalKeyboardKey.space): DoNothingAndStopPropagationIntent(),
LogicalKeySet(LogicalKeyboardKey.arrowUp): DoNothingAndStopPropagationIntent(),
LogicalKeySet(LogicalKeyboardKey.arrowDown): DoNothingAndStopPropagationIntent(),
LogicalKeySet(LogicalKeyboardKey.arrowLeft): DoNothingAndStopPropagationIntent(),
LogicalKeySet(LogicalKeyboardKey.arrowRight): DoNothingAndStopPropagationIntent(),
};
/// Signature for the [TextField.buildCounter] callback.
typedef InputCounterWidgetBuilder = Widget? Function(
/// The build context for the TextField.
......@@ -1311,7 +1301,7 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
semanticsMaxValueLength = null;
}
child = MouseRegion(
return MouseRegion(
cursor: effectiveMouseCursor,
onEnter: (PointerEnterEvent event) => _handleHover(true),
onExit: (PointerExitEvent event) => _handleHover(false),
......@@ -1339,13 +1329,5 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
),
),
);
if (kIsWeb) {
return Shortcuts(
shortcuts: _webScrollShortcutOverrides,
child: child,
);
}
return child;
}
}
......@@ -72,7 +72,7 @@ class _DoNothingAndStopPropagationTextAction extends TextEditingAction<DoNothing
_DoNothingAndStopPropagationTextAction();
@override
bool consumesKey(Intent intent) => true;
bool consumesKey(Intent intent) => false;
@override
void invoke(DoNothingAndStopPropagationTextIntent intent, [BuildContext? context]) {}
......
......@@ -61,8 +61,7 @@ abstract class TextEditingAction<T extends Intent> extends ContextAction<T> {
@override
bool isEnabled(T intent) {
// The Action is disabled if there is no focused TextEditingActionTarget, or
// if the platform is web, because web lets the browser handle text editing.
return !kIsWeb && textEditingActionTarget != null;
// The Action is disabled if there is no focused TextEditingActionTarget.
return textEditingActionTarget != null;
}
}
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:flutter/foundation.dart';
class TestLeftIntent extends Intent {}
class TestRightIntent extends Intent {}
void main() {
testWidgets('DoNothingAndStopPropagationTextIntent', (WidgetTester tester) async {
bool leftCalled = false;
bool rightCalled = false;
final TextEditingController controller = TextEditingController(
text: 'blah1 blah2',
);
final FocusNode focusNodeTarget = FocusNode();
final FocusNode focusNodeNonTarget = FocusNode();
await tester.pumpWidget(MaterialApp(
theme: ThemeData(),
home: Scaffold(
body: Builder(
builder: (BuildContext context) {
return Shortcuts(
shortcuts: <LogicalKeySet, Intent>{
LogicalKeySet(LogicalKeyboardKey.arrowLeft): TestLeftIntent(),
LogicalKeySet(LogicalKeyboardKey.arrowRight): TestRightIntent(),
},
child: Shortcuts(
shortcuts: <LogicalKeySet, Intent>{
LogicalKeySet(LogicalKeyboardKey.arrowRight): const DoNothingAndStopPropagationTextIntent(),
},
child: Actions(
// These Actions intercept default Intents, set a flag that they
// were called, and then call through to the default Action.
actions: <Type, Action<Intent>>{
TestLeftIntent: CallbackAction<TestLeftIntent>(onInvoke: (Intent intent) {
leftCalled = true;
}),
TestRightIntent: CallbackAction<TestRightIntent>(onInvoke: (Intent intent) {
rightCalled = true;
}),
},
child: Center(
child: Column(
children: <Widget>[
EditableText(
controller: controller,
focusNode: focusNodeTarget,
style: Typography.material2018(platform: TargetPlatform.android).black.subtitle1!,
cursorColor: Colors.blue,
backgroundCursorColor: Colors.grey,
),
Focus(
focusNode: focusNodeNonTarget,
child: const Text('focusable'),
),
],
),
),
),
),
);
},
),
),
));
// Focus on the EditableText, which is a TextEditingActionTarget.
focusNodeTarget.requestFocus();
await tester.pump();
expect(focusNodeTarget.hasFocus, isTrue);
expect(focusNodeNonTarget.hasFocus, isFalse);
expect(controller.selection.isCollapsed, isTrue);
expect(controller.selection.baseOffset, 11);
// The left arrow key's Action is called.
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.pump();
expect(leftCalled, isTrue);
expect(rightCalled, isFalse);
leftCalled = false;
// The right arrow key is blocked by DoNothingAndStopPropagationTextIntent.
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.pump();
expect(rightCalled, isFalse);
expect(leftCalled, isFalse);
// Focus on the other node, which is not a TextEditingActionTarget.
focusNodeNonTarget.requestFocus();
await tester.pump();
expect(focusNodeTarget.hasFocus, isFalse);
expect(focusNodeNonTarget.hasFocus, isTrue);
// The left arrow key's Action is called as normal.
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.pump();
expect(leftCalled, isTrue);
expect(rightCalled, isFalse);
leftCalled = false;
// The right arrow key's Action is also called. That's because
// DoNothingAndStopPropagationTextIntent only applies if a
// TextEditingActionTarget is currently focused.
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.pump();
expect(leftCalled, isFalse);
expect(rightCalled, isTrue);
});
}
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