mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
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
This commit is contained in:
parent
44b2ca1830
commit
0329a18875
3 changed files with 37 additions and 14 deletions
|
@ -15,6 +15,7 @@ import {
|
||||||
import { isSplitTestEnabled } from '@/utils/splitTestUtils'
|
import { isSplitTestEnabled } from '@/utils/splitTestUtils'
|
||||||
import { v4 as uuid } from 'uuid'
|
import { v4 as uuid } from 'uuid'
|
||||||
import { textSelected, textSelectedEffect } from './text-selected'
|
import { textSelected, textSelectedEffect } from './text-selected'
|
||||||
|
import { isCursorNearViewportTop } from '../utils/is-cursor-near-edge'
|
||||||
|
|
||||||
export const addNewCommentRangeEffect = StateEffect.define<Range<Decoration>>()
|
export const addNewCommentRangeEffect = StateEffect.define<Range<Decoration>>()
|
||||||
|
|
||||||
|
@ -88,14 +89,15 @@ export const reviewTooltipStateField = StateField.define<{
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
function buildTooltip(range: SelectionRange): Tooltip | null {
|
function buildTooltip(view: EditorView): Tooltip | null {
|
||||||
if (range.empty) {
|
if (view.state.selection.main.empty) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const pos = view.state.selection.main.head
|
||||||
return {
|
return {
|
||||||
pos: range.assoc < 0 ? range.to : range.from,
|
pos,
|
||||||
above: true,
|
above: !isCursorNearViewportTop(view, pos, 50),
|
||||||
strictSide: true,
|
strictSide: true,
|
||||||
arrow: false,
|
arrow: false,
|
||||||
create() {
|
create() {
|
||||||
|
@ -113,6 +115,7 @@ const reviewTooltipTheme = EditorView.baseTheme({
|
||||||
'.review-tooltip-menu-container.cm-tooltip': {
|
'.review-tooltip-menu-container.cm-tooltip': {
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: 'transparent',
|
||||||
border: 'none',
|
border: 'none',
|
||||||
|
zIndex: 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
'&light': {
|
'&light': {
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { SelectionRange, StateEffect } from '@codemirror/state'
|
import { StateEffect } from '@codemirror/state'
|
||||||
import { ViewPlugin } from '@codemirror/view'
|
import { EditorView, ViewPlugin } from '@codemirror/view'
|
||||||
|
|
||||||
export const textSelectedEffect = StateEffect.define<SelectionRange>()
|
export const textSelectedEffect = StateEffect.define<EditorView>()
|
||||||
|
|
||||||
export const textSelected = ViewPlugin.define(view => {
|
export const textSelected = ViewPlugin.define(view => {
|
||||||
function mouseUpListener() {
|
function mouseUpListener() {
|
||||||
if (!view.state.selection.main.empty) {
|
if (!view.state.selection.main.empty) {
|
||||||
view.dispatch({
|
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.state.selection.main.empty
|
||||||
) {
|
) {
|
||||||
view.dispatch({
|
view.dispatch({
|
||||||
effects: textSelectedEffect.of(view.state.selection.main),
|
effects: textSelectedEffect.of(view),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,16 @@ const TOP_EDGE_THRESHOLD = 100
|
||||||
const BOTTOM_EDGE_THRESHOLD = 200
|
const BOTTOM_EDGE_THRESHOLD = 200
|
||||||
|
|
||||||
export function isCursorNearViewportEdge(view: EditorView, pos: number) {
|
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)
|
const cursorCoords = view.coordsAtPos(pos)
|
||||||
|
|
||||||
if (!cursorCoords) {
|
if (!cursorCoords) {
|
||||||
|
@ -12,12 +22,22 @@ export function isCursorNearViewportEdge(view: EditorView, pos: number) {
|
||||||
|
|
||||||
const scrollInfo = view.scrollDOM.getBoundingClientRect()
|
const scrollInfo = view.scrollDOM.getBoundingClientRect()
|
||||||
|
|
||||||
// check if the cursor is near the top of the viewport
|
return Math.abs(cursorCoords.bottom - scrollInfo.top) <= threshold
|
||||||
if (Math.abs(cursorCoords.bottom - scrollInfo.top) <= TOP_EDGE_THRESHOLD) {
|
}
|
||||||
return true
|
|
||||||
|
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 viewportHeight = view.scrollDOM.clientHeight
|
||||||
const viewportBottom = scrollInfo.top + viewportHeight
|
const viewportBottom = scrollInfo.top + viewportHeight
|
||||||
return Math.abs(cursorCoords.bottom - viewportBottom) <= BOTTOM_EDGE_THRESHOLD
|
return Math.abs(cursorCoords.bottom - viewportBottom) <= threshold
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue