@@ -1222,6 +1222,71 @@ class RenderEditor extends RenderEditableContainerBox
12221222 );
12231223 }
12241224
1225+ /// Returns the y-offset of the editor at which [selection] is visible.
1226+ ///
1227+ /// The offset is the distance from the top of the editor and is the minimum
1228+ /// from the current scroll position until [selection] becomes visible.
1229+ /// Returns null if [selection] is already visible.
1230+ ///
1231+ /// Finds the closest scroll offset that fully reveals the editing cursor.
1232+ ///
1233+ /// The `scrollOffset` parameter represents current scroll offset in the
1234+ /// parent viewport.
1235+ ///
1236+ /// The `offsetInViewport` parameter represents the editor's vertical offset
1237+ /// in the parent viewport. This value should normally be 0.0 if this editor
1238+ /// is the only child of the viewport or if it's the topmost child. Otherwise
1239+ /// it should be a positive value equal to total height of all siblings of
1240+ /// this editor from above it.
1241+ ///
1242+ /// Returns `null` if the cursor is currently visible.
1243+ double ? getOffsetToRevealCursor (
1244+ double viewportHeight, double scrollOffset, double offsetInViewport) {
1245+ // Endpoints coordinates represents lower left or lower right corner of
1246+ // the selection. If we want to scroll up to reveal the caret we need to
1247+ // adjust the dy value by the height of the line. We also add a small margin
1248+ // so that the caret is not too close to the edge of the viewport.
1249+ final endpoints = getEndpointsForSelection (selection);
1250+
1251+ // when we drag the right handle, we should get the last point
1252+ TextSelectionPoint endpoint;
1253+ if (selection.isCollapsed) {
1254+ endpoint = endpoints.first;
1255+ } else {
1256+ if (selection is DragTextSelection ) {
1257+ endpoint = (selection as DragTextSelection ).first
1258+ ? endpoints.first
1259+ : endpoints.last;
1260+ } else {
1261+ endpoint = endpoints.first;
1262+ }
1263+ }
1264+
1265+ // Collapsed selection => caret
1266+ final child = childAtPosition (selection.extent);
1267+ const kMargin = 8.0 ;
1268+
1269+ final caretTop = endpoint.point.dy -
1270+ child.preferredLineHeight (TextPosition (
1271+ offset: selection.extentOffset - child.container.documentOffset)) -
1272+ kMargin +
1273+ offsetInViewport +
1274+ scrollBottomInset;
1275+ final caretBottom =
1276+ endpoint.point.dy + kMargin + offsetInViewport + scrollBottomInset;
1277+ double ? dy;
1278+ if (caretTop < scrollOffset) {
1279+ dy = caretTop;
1280+ } else if (caretBottom > scrollOffset + viewportHeight) {
1281+ dy = caretBottom - viewportHeight;
1282+ }
1283+ if (dy == null ) {
1284+ return null ;
1285+ }
1286+ // Clamping to 0.0 so that the content does not jump unnecessarily.
1287+ return math.max (dy, 0 );
1288+ }
1289+
12251290 @override
12261291 Rect getLocalRectForCaret (TextPosition position) {
12271292 final targetChild = childAtPosition (position);
@@ -1233,10 +1298,6 @@ class RenderEditor extends RenderEditableContainerBox
12331298 return childLocalRect.shift (Offset (0 , boxParentData.offset.dy));
12341299 }
12351300
1236- TextPosition get caretTextPosition => _floatingCursorRect == null
1237- ? selection.extent
1238- : _floatingCursorTextPosition;
1239-
12401301 // Start floating cursor
12411302
12421303 FloatingCursorPainter get _floatingCursorPainter => FloatingCursorPainter (
0 commit comments