Просмотр исходного кода

Show "add comment" tooltip below cursor if near viewport top (#21348)

* Scroll selection anchor into view when adding new comment

* check if cursor is near viewport edge

* Show "add comment" tooltip below cursor if near viewport top

GitOrigin-RevId: 0dc2234bc03b1d88a3719ba01a4a865f218b9bfa
Domagoj Kriskovic 1 год назад
Родитель
Сommit
0329a18875

+ 7 - 4
services/web/frontend/js/features/source-editor/extensions/review-tooltip.ts

@@ -15,6 +15,7 @@ import {
 import { isSplitTestEnabled } from '@/utils/splitTestUtils'
 import { v4 as uuid } from 'uuid'
 import { textSelected, textSelectedEffect } from './text-selected'
+import { isCursorNearViewportTop } from '../utils/is-cursor-near-edge'
 
 export const addNewCommentRangeEffect = StateEffect.define<Range<Decoration>>()
 
@@ -88,14 +89,15 @@ export const reviewTooltipStateField = StateField.define<{
   ],
 })
 
-function buildTooltip(range: SelectionRange): Tooltip | null {
-  if (range.empty) {
+function buildTooltip(view: EditorView): Tooltip | null {
+  if (view.state.selection.main.empty) {
     return null
   }
 
+  const pos = view.state.selection.main.head
   return {
-    pos: range.assoc < 0 ? range.to : range.from,
-    above: true,
+    pos,
+    above: !isCursorNearViewportTop(view, pos, 50),
     strictSide: true,
     arrow: false,
     create() {
@@ -113,6 +115,7 @@ const reviewTooltipTheme = EditorView.baseTheme({
   '.review-tooltip-menu-container.cm-tooltip': {
     backgroundColor: 'transparent',
     border: 'none',
+    zIndex: 0,
   },
 
   '&light': {

+ 5 - 5
services/web/frontend/js/features/source-editor/extensions/text-selected.ts

@@ -1,13 +1,13 @@
-import { SelectionRange, StateEffect } from '@codemirror/state'
-import { ViewPlugin } from '@codemirror/view'
+import { StateEffect } from '@codemirror/state'
+import { EditorView, ViewPlugin } from '@codemirror/view'
 
-export const textSelectedEffect = StateEffect.define<SelectionRange>()
+export const textSelectedEffect = StateEffect.define<EditorView>()
 
 export const textSelected = ViewPlugin.define(view => {
   function mouseUpListener() {
     if (!view.state.selection.main.empty) {
       view.dispatch({
-        effects: textSelectedEffect.of(view.state.selection.main),
+        effects: textSelectedEffect.of(view),
       })
     }
   }
@@ -17,7 +17,7 @@ export const textSelected = ViewPlugin.define(view => {
       !view.state.selection.main.empty
     ) {
       view.dispatch({
-        effects: textSelectedEffect.of(view.state.selection.main),
+        effects: textSelectedEffect.of(view),
       })
     }
   }

+ 25 - 5
services/web/frontend/js/features/source-editor/utils/is-cursor-near-edge.ts

@@ -4,6 +4,16 @@ const TOP_EDGE_THRESHOLD = 100
 const BOTTOM_EDGE_THRESHOLD = 200
 
 export function isCursorNearViewportEdge(view: EditorView, pos: number) {
+  return (
+    isCursorNearViewportTop(view, pos) || isCursorNearViewportBottom(view, pos)
+  )
+}
+
+export function isCursorNearViewportTop(
+  view: EditorView,
+  pos: number,
+  threshold = TOP_EDGE_THRESHOLD
+) {
   const cursorCoords = view.coordsAtPos(pos)
 
   if (!cursorCoords) {
@@ -12,12 +22,22 @@ export function isCursorNearViewportEdge(view: EditorView, pos: number) {
 
   const scrollInfo = view.scrollDOM.getBoundingClientRect()
 
-  // check if the cursor is near the top of the viewport
-  if (Math.abs(cursorCoords.bottom - scrollInfo.top) <= TOP_EDGE_THRESHOLD) {
-    return true
+  return Math.abs(cursorCoords.bottom - scrollInfo.top) <= threshold
+}
+
+export function isCursorNearViewportBottom(
+  view: EditorView,
+  pos: number,
+  threshold = BOTTOM_EDGE_THRESHOLD
+) {
+  const cursorCoords = view.coordsAtPos(pos)
+
+  if (!cursorCoords) {
+    return false
   }
-  // check if the cursor is near the bottom of the viewport
+
+  const scrollInfo = view.scrollDOM.getBoundingClientRect()
   const viewportHeight = view.scrollDOM.clientHeight
   const viewportBottom = scrollInfo.top + viewportHeight
-  return Math.abs(cursorCoords.bottom - viewportBottom) <= BOTTOM_EDGE_THRESHOLD
+  return Math.abs(cursorCoords.bottom - viewportBottom) <= threshold
 }