-
Notifications
You must be signed in to change notification settings - Fork 30.1k
Closed
flutter/engine
#36616Labels
a: text inputEntering text in a text field or keyboard related problemsEntering text in a text field or keyboard related problemsengineflutter/engine related. See also e: labels.flutter/engine related. See also e: labels.found in release: 3.4Found to occur in 3.4Found to occur in 3.4has reproducible stepsThe issue has been confirmed reproducible and is ready to work onThe issue has been confirmed reproducible and is ready to work onplatform-webWeb applications specificallyWeb applications specifically
Description
Steps to Reproduce
Code sample
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(const TextInputDeltaApp());
}
// This demo app simulates a very basic text field.
// Edition relies on text editing deltas.
//
// Limitations:
// - Caret and current selection are not displayed.
// - Several keys (delete, backspace, ect) are not handled so they will work only
// on web where they are handled on the engine side.
class TextInputDeltaApp extends StatelessWidget {
const TextInputDeltaApp({super.key});
@override
Widget build(BuildContext context) {
// MaterialApp is not used here to be as minimal as possible
// This is possible when running on Web but not on Desktop because
// many keys (for instance `delete`, `backspace`, etc) are not handled
// by the engine on Desktop. They are handled by framework shortcuts
// (see `DefaultTextEditingShortcuts`).
return const Directionality(
textDirection: TextDirection.ltr,
child: TextInputDeltaDemo(),
);
}
}
typedef ContentChangedCallback = void Function(String);
class TextInputDeltaDemo extends StatefulWidget {
const TextInputDeltaDemo({Key? key}) : super(key: key);
@override
State<TextInputDeltaDemo> createState() => _TextInputDeltaDemo();
}
class _TextInputDeltaDemo extends State<TextInputDeltaDemo> {
String content = "Flutter!";
MinimalTextInputClient? inputClient;
@override
void initState() {
super.initState();
_attachTextInputClient();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(
child: Center(
child: Semantics(
textField: true,
child: Container(
color: Colors.amber,
width: 300,
height: 100,
child: Text(content),
),
),
),
),
],
);
}
void _attachTextInputClient() {
inputClient ??= MinimalTextInputClient();
inputClient!.attach(content, (String value) {
setState(() {
content = value;
});
});
}
}
class MinimalTextInputClient implements DeltaTextInputClient {
TextInputConnection? _textInputConnection;
TextEditingValue _value = TextEditingValue.empty;
ContentChangedCallback? onChange;
void attach(String initialText, ContentChangedCallback onChange) {
this.onChange = onChange;
_value = TextEditingValue(text: initialText);
_textInputConnection = TextInput.attach(
this,
const TextInputConfiguration(
enableDeltaModel: true,
inputAction: TextInputAction.newline,
inputType: TextInputType.multiline,
),
);
_textInputConnection!.setEditingState(_value);
_textInputConnection!.show();
}
@override
void connectionClosed() {
_textInputConnection!.close();
}
@override
// TODO: implement currentAutofillScope
AutofillScope? get currentAutofillScope => throw UnimplementedError();
@override
// TODO: implement currentTextEditingValue
TextEditingValue? get currentTextEditingValue => _value;
@override
void insertTextPlaceholder(Size size) {
// TODO: implement insertTextPlaceholder
}
@override
void performAction(TextInputAction action) {
// TODO: implement performAction
}
@override
void performPrivateCommand(String action, Map<String, dynamic> data) {
// TODO: implement performPrivateCommand
}
@override
void performSelector(String selectorName) {
// TODO: implement performSelector
}
@override
void removeTextPlaceholder() {
// TODO: implement removeTextPlaceholder
}
@override
void showAutocorrectionPromptRect(int start, int end) {
// TODO: implement showAutocorrectionPromptRect
}
@override
void showToolbar() {
// TODO: implement showToolbar
}
@override
void updateEditingValue(TextEditingValue value) {
// TODO: implement updateEditingValue
}
@override
void updateEditingValueWithDeltas(List<TextEditingDelta> textEditingDeltas) {
for (var delta in textEditingDeltas) {
_value = delta.apply(_value);
onChange?.call(_value.text);
}
}
@override
void updateFloatingCursor(RawFloatingCursorPoint point) {
// TODO: implement updateFloatingCursor
}
@override
void didChangeInputControl(TextInputControl? oldControl, TextInputControl? newControl) {
// TODO: implement didChangeInputControl
}
}
- Run the code sample on Web (
flutter run -d chrome). - Hit the
deletekey.
Expected results: the first character is deleted
Actual results: an exception is thrown
Error log
Error: Assertion failed: org-dartlang-sdk:///flutter_web_sdk/lib/_engine/engine/text_editing/text_editing.dart:429:10
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 266:49 throw_
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 29:3 assertFailed
lib/_engine/engine/text_editing/text_editing.dart 429:23 _replace
lib/_engine/engine/text_editing/text_editing.dart 511:37 inferDeltaState
lib/_engine/engine/text_editing/text_editing.dart 1290:56 handleChange
(This error was first reported in flutter/samples#1424 which uses the simplistic_editor sample for reproducible steps).
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
a: text inputEntering text in a text field or keyboard related problemsEntering text in a text field or keyboard related problemsengineflutter/engine related. See also e: labels.flutter/engine related. See also e: labels.found in release: 3.4Found to occur in 3.4Found to occur in 3.4has reproducible stepsThe issue has been confirmed reproducible and is ready to work onThe issue has been confirmed reproducible and is ready to work onplatform-webWeb applications specificallyWeb applications specifically
Type
Projects
Status
Done (PR merged)