diff --git a/super_editor/lib/src/default_editor/document_gestures_touch_ios.dart b/super_editor/lib/src/default_editor/document_gestures_touch_ios.dart index 53f5ce521..399ab1449 100644 --- a/super_editor/lib/src/default_editor/document_gestures_touch_ios.dart +++ b/super_editor/lib/src/default_editor/document_gestures_touch_ios.dart @@ -130,6 +130,7 @@ class SuperEditorIosControlsController { _shouldShowToolbar.dispose(); } + /// {@template ios_use_selection_heuristics} /// Whether to adjust the user's selection similar to the way iOS does. /// /// For example: iOS doesn't let users tap directly on a text offset. Instead, @@ -139,6 +140,7 @@ class SuperEditorIosControlsController { /// When this property is `true`, iOS-style heuristics should be used. When /// this value is `false`, the user's gestures should directly impact the /// area they touched. + /// {@endtemplate} final bool useIosSelectionHeuristics; /// Color of the text selection drag handles on iOS. @@ -935,7 +937,7 @@ class _IosDocumentTouchInteractorState extends State } final extentRect = _docLayout.getRectForPosition(collapsedPosition)!; - final caretRect = Rect.fromLTRB( + final caretHitArea = Rect.fromLTRB( extentRect.left - 24, extentRect.top, extentRect.right + 24, @@ -943,7 +945,7 @@ class _IosDocumentTouchInteractorState extends State ); final docOffset = _interactorOffsetToDocumentOffset(interactorOffset); - return caretRect.contains(docOffset); + return caretHitArea.contains(docOffset); } bool _isOverBaseHandle(Offset interactorOffset) { diff --git a/super_editor/lib/src/super_textfield/ios/user_interaction.dart b/super_editor/lib/src/super_textfield/ios/user_interaction.dart index fd05ff20a..2c8214755 100644 --- a/super_editor/lib/src/super_textfield/ios/user_interaction.dart +++ b/super_editor/lib/src/super_textfield/ios/user_interaction.dart @@ -37,6 +37,10 @@ final _log = iosTextFieldLog; /// /// Selection changes are made via the given [textController]. class IOSTextFieldTouchInteractor extends StatefulWidget { + /// {@macro ios_use_selection_heuristics} + @visibleForTesting + static bool useIosSelectionHeuristics = true; + const IOSTextFieldTouchInteractor({ Key? key, required this.focusNode, @@ -52,9 +56,6 @@ class IOSTextFieldTouchInteractor extends StatefulWidget { required this.child, }) : super(key: key); - @visibleForTesting - static bool useIosSelectionHeuristics = true; - /// [FocusNode] for the text field that contains this [IOSTextFieldInteractor]. /// /// [IOSTextFieldInteractor] only shows editing controls, and listens for drag diff --git a/super_editor/test/flutter_test_config.dart b/super_editor/test/flutter_test_config.dart index c50e8ba2a..261f71038 100644 --- a/super_editor/test/flutter_test_config.dart +++ b/super_editor/test/flutter_test_config.dart @@ -8,7 +8,8 @@ Future testExecutable(FutureOr Function() testMain) async { // Disable indeterminate animations BlinkController.indeterminateAnimationsEnabled = false; - // Disable iOS selection heuristics. + // Disable iOS selection heuristics, i.e, place the caret at the exact + // tapped position instead of placing it at word boundaries. IOSTextFieldTouchInteractor.useIosSelectionHeuristics = false; Testing.isInTest = true; diff --git a/super_editor/test/super_editor/mobile/super_editor_ios_overlay_controls_test.dart b/super_editor/test/super_editor/mobile/super_editor_ios_overlay_controls_test.dart index eb8b42675..539800fab 100644 --- a/super_editor/test/super_editor/mobile/super_editor_ios_overlay_controls_test.dart +++ b/super_editor/test/super_editor/mobile/super_editor_ios_overlay_controls_test.dart @@ -256,7 +256,7 @@ void main() { )), ); - // Tap at the caret. + // Tap on the caret. await tester.tapInParagraph("1", 32); // Ensure the selection was kept at "con|sectetur". diff --git a/super_editor/test/super_textfield/ios/super_textfield_ios_selection_test.dart b/super_editor/test/super_textfield/ios/super_textfield_ios_selection_test.dart index 7b6e581ba..462273c7f 100644 --- a/super_editor/test/super_textfield/ios/super_textfield_ios_selection_test.dart +++ b/super_editor/test/super_textfield/ios/super_textfield_ios_selection_test.dart @@ -72,7 +72,8 @@ void main() { const TextSelection.collapsed(offset: -1), ); - // Tap at "ips|um" to place the caret at the end of the word. + // Tap at "ips|um" to place the caret at the end of the word, + // because on iOS the caret is always placed at word boundaries. await tester.placeCaretInSuperTextField(9); await tester.pump(kDoubleTapTimeout);