Skip to content

Commit 1ffd28d

Browse files
authored
[FEATURE] - Allow vertical scrolling of a multi-line SuperTextField when its text overflows (Resolves #2140)(Resolves #1795) (#2139)
1 parent 4b7b864 commit 1ffd28d

File tree

2 files changed

+97
-1
lines changed

2 files changed

+97
-1
lines changed

super_editor/lib/src/super_textfield/infrastructure/text_scrollview.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,11 @@ class _TextScrollViewState extends State<TextScrollView>
423423
child: SingleChildScrollView(
424424
key: _textFieldViewportKey,
425425
controller: _scrollController,
426-
physics: const NeverScrollableScrollPhysics(),
426+
// For single-line text fields, we do not allow horizontal scrolling,
427+
// therefor we apply NeverScrollableScrollPhysics. For multi-line text
428+
// fields, we pass null to allow the SingleChildScrollView to default
429+
// to the appropriate scroll physics based on the host platform.
430+
physics: isMultiline ? null : const NeverScrollableScrollPhysics(),
427431
scrollDirection: isMultiline ? Axis.vertical : Axis.horizontal,
428432
child: Padding(
429433
padding: widget.padding ?? EdgeInsets.zero,

super_editor/test/super_textfield/super_textfield_gesture_scrolling_test.dart

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,98 @@ void main() {
249249
// Ensure the selection didn't change.
250250
expect(SuperTextFieldInspector.findSelection(), TextRange.empty);
251251
});
252+
253+
testWidgetsOnMobile("multi-line is vertically scrollable when text spans more lines than maxLines", (tester) async {
254+
final initialText = "The first line of text in the field\n"
255+
"The second line of text in the field\n"
256+
"The third line of text in the field";
257+
final controller = AttributedTextEditingController(
258+
text: AttributedText(initialText),
259+
);
260+
261+
// Pump the widget tree with a SuperTextField with a maxHeight of 2 lines
262+
// of text, which should overflow considering there are 3 lines of text.
263+
await _pumpTestApp(
264+
tester,
265+
textController: controller,
266+
minLines: 1,
267+
maxLines: 2,
268+
maxHeight: 40,
269+
);
270+
271+
// Ensure the text field has not yet scrolled.
272+
var textTop = tester.getTopRight(find.byType(SuperTextField)).dy;
273+
var viewportTop = tester.getTopRight(find.byType(SuperText)).dy;
274+
expect(textTop, moreOrLessEquals(viewportTop));
275+
276+
// Scroll down to reveal the last line of text.
277+
await tester.drag(find.byType(SuperTextField), const Offset(0, -1000.0));
278+
await tester.pumpAndSettle();
279+
280+
// Ensure the text field has scrolled to the bottom.
281+
var textBottom = tester.getBottomRight(find.byType(SuperTextField)).dy;
282+
var viewportBottom = tester.getBottomRight(find.byType(SuperText)).dy;
283+
expect(textBottom, moreOrLessEquals(viewportBottom));
284+
285+
// Scroll back up to the top of the text field.
286+
await tester.drag(find.byType(SuperTextField), const Offset(0, 1000.0));
287+
await tester.pumpAndSettle();
288+
289+
// Ensure the text field has scrolled back to the top.
290+
textTop = tester.getTopRight(find.byType(SuperTextField)).dy;
291+
viewportTop = tester.getTopRight(find.byType(SuperText)).dy;
292+
expect(textTop, moreOrLessEquals(viewportTop));
293+
});
294+
295+
testWidgetsOnDesktop("multi-line is vertically scrollable when text spans more lines than maxLines", (tester) async {
296+
final initialText = "The first line of text in the field\n"
297+
"The second line of text in the field\n"
298+
"The third line of text in the field";
299+
final controller = AttributedTextEditingController(
300+
text: AttributedText(initialText),
301+
);
302+
303+
// Pump the widget tree with a SuperTextField with a maxHeight of 2 lines
304+
// of text, which should overflow considering there are 3 lines of text.
305+
await _pumpTestApp(
306+
tester,
307+
textController: controller,
308+
minLines: 1,
309+
maxLines: 2,
310+
maxHeight: 40,
311+
);
312+
313+
// Ensure the text field has not yet scrolled.
314+
var textTop = tester.getTopRight(find.byType(SuperTextField)).dy;
315+
var viewportTop = tester.getTopRight(find.byType(SuperText)).dy;
316+
expect(textTop, moreOrLessEquals(viewportTop));
317+
318+
// Scroll down to reveal the last line of text.
319+
await tester.drag(
320+
find.byType(SuperTextField),
321+
const Offset(0, -1000.0),
322+
kind: PointerDeviceKind.trackpad,
323+
);
324+
await tester.pumpAndSettle();
325+
326+
// Ensure the text field has scrolled to the bottom.
327+
var textBottom = tester.getBottomRight(find.byType(SuperTextField)).dy;
328+
var viewportBottom = tester.getBottomRight(find.byType(SuperText)).dy;
329+
expect(textBottom, moreOrLessEquals(viewportBottom));
330+
331+
// Scroll back up to the top of the text field.
332+
await tester.drag(
333+
find.byType(SuperTextField),
334+
const Offset(0, 1000.0),
335+
kind: PointerDeviceKind.trackpad,
336+
);
337+
await tester.pumpAndSettle();
338+
339+
// Ensure the text field has scrolled back to the top.
340+
textTop = tester.getTopRight(find.byType(SuperTextField)).dy;
341+
viewportTop = tester.getTopRight(find.byType(SuperText)).dy;
342+
expect(textTop, moreOrLessEquals(viewportTop));
343+
});
252344
});
253345
}
254346

0 commit comments

Comments
 (0)