mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #15819 from overleaf/td-review-panel-comment-selection
Prevent selection within review panel entry being immediately cleared GitOrigin-RevId: cca7206a6620bed8cae1bb55a064102204a00751
This commit is contained in:
parent
2807a35e24
commit
4f13470345
4 changed files with 36 additions and 49 deletions
|
@ -11,6 +11,7 @@ import comparePropsWithShallowArrayCompare from '../utils/compare-props-with-sha
|
||||||
import { BaseChangeEntryProps } from '../types/base-change-entry-props'
|
import { BaseChangeEntryProps } from '../types/base-change-entry-props'
|
||||||
import useIndicatorHover from '../hooks/use-indicator-hover'
|
import useIndicatorHover from '../hooks/use-indicator-hover'
|
||||||
import EntryIndicator from './entry-indicator'
|
import EntryIndicator from './entry-indicator'
|
||||||
|
import { useEntryClick } from '@/features/source-editor/components/review-panel/hooks/use-entry-click'
|
||||||
|
|
||||||
interface AggregateChangeEntryProps extends BaseChangeEntryProps {
|
interface AggregateChangeEntryProps extends BaseChangeEntryProps {
|
||||||
replacedContent: string
|
replacedContent: string
|
||||||
|
@ -30,7 +31,7 @@ function AggregateChangeEntry({
|
||||||
contentLimit = 17,
|
contentLimit = 17,
|
||||||
}: AggregateChangeEntryProps) {
|
}: AggregateChangeEntryProps) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { acceptChanges, rejectChanges, gotoEntry, handleLayoutChange } =
|
const { acceptChanges, rejectChanges, handleLayoutChange } =
|
||||||
useReviewPanelUpdaterFnsContext()
|
useReviewPanelUpdaterFnsContext()
|
||||||
const [isDeletionCollapsed, setIsDeletionCollapsed] = useState(true)
|
const [isDeletionCollapsed, setIsDeletionCollapsed] = useState(true)
|
||||||
const [isInsertionCollapsed, setIsInsertionCollapsed] = useState(true)
|
const [isInsertionCollapsed, setIsInsertionCollapsed] = useState(true)
|
||||||
|
@ -53,21 +54,7 @@ function AggregateChangeEntry({
|
||||||
? content.substring(0, contentLimit)
|
? content.substring(0, contentLimit)
|
||||||
: content
|
: content
|
||||||
|
|
||||||
const handleEntryClick = (e: React.MouseEvent<HTMLDivElement>) => {
|
const handleEntryClick = useEntryClick(docId, offset)
|
||||||
const target = e.target as Element
|
|
||||||
|
|
||||||
for (const selector of [
|
|
||||||
'.rp-entry',
|
|
||||||
'.rp-entry-description',
|
|
||||||
'.rp-entry-body',
|
|
||||||
'.rp-entry-action-icon i',
|
|
||||||
]) {
|
|
||||||
if (target.matches(selector)) {
|
|
||||||
gotoEntry(docId, offset)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleDeletionToggleCollapse = () => {
|
const handleDeletionToggleCollapse = () => {
|
||||||
setIsDeletionCollapsed(value => !value)
|
setIsDeletionCollapsed(value => !value)
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { BaseChangeEntryProps } from '../types/base-change-entry-props'
|
||||||
import comparePropsWithShallowArrayCompare from '../utils/compare-props-with-shallow-array-compare'
|
import comparePropsWithShallowArrayCompare from '../utils/compare-props-with-shallow-array-compare'
|
||||||
import useIndicatorHover from '../hooks/use-indicator-hover'
|
import useIndicatorHover from '../hooks/use-indicator-hover'
|
||||||
import EntryIndicator from './entry-indicator'
|
import EntryIndicator from './entry-indicator'
|
||||||
|
import { useEntryClick } from '@/features/source-editor/components/review-panel/hooks/use-entry-click'
|
||||||
|
|
||||||
interface ChangeEntryProps extends BaseChangeEntryProps {
|
interface ChangeEntryProps extends BaseChangeEntryProps {
|
||||||
type: ReviewPanelChangeEntry['type']
|
type: ReviewPanelChangeEntry['type']
|
||||||
|
@ -31,7 +32,7 @@ function ChangeEntry({
|
||||||
contentLimit = 40,
|
contentLimit = 40,
|
||||||
}: ChangeEntryProps) {
|
}: ChangeEntryProps) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { handleLayoutChange, acceptChanges, rejectChanges, gotoEntry } =
|
const { handleLayoutChange, acceptChanges, rejectChanges } =
|
||||||
useReviewPanelUpdaterFnsContext()
|
useReviewPanelUpdaterFnsContext()
|
||||||
const [isCollapsed, setIsCollapsed] = useState(true)
|
const [isCollapsed, setIsCollapsed] = useState(true)
|
||||||
const {
|
const {
|
||||||
|
@ -49,21 +50,7 @@ function ChangeEntry({
|
||||||
const needsCollapsing = content.length > contentLimit
|
const needsCollapsing = content.length > contentLimit
|
||||||
const isInsert = type === 'insert'
|
const isInsert = type === 'insert'
|
||||||
|
|
||||||
const handleEntryClick = (e: React.MouseEvent<HTMLDivElement>) => {
|
const handleEntryClick = useEntryClick(docId, offset)
|
||||||
const target = e.target as Element
|
|
||||||
|
|
||||||
for (const selector of [
|
|
||||||
'.rp-entry',
|
|
||||||
'.rp-entry-description',
|
|
||||||
'.rp-entry-body',
|
|
||||||
'.rp-entry-action-icon i',
|
|
||||||
]) {
|
|
||||||
if (target.matches(selector)) {
|
|
||||||
gotoEntry(docId, offset)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleToggleCollapse = () => {
|
const handleToggleCollapse = () => {
|
||||||
setIsCollapsed(value => !value)
|
setIsCollapsed(value => !value)
|
||||||
|
|
|
@ -17,6 +17,7 @@ import { ReviewPanelCommentThread } from '../../../../../../../types/review-pane
|
||||||
import { ReviewPanelCommentEntry } from '../../../../../../../types/review-panel/entry'
|
import { ReviewPanelCommentEntry } from '../../../../../../../types/review-panel/entry'
|
||||||
import useIndicatorHover from '../hooks/use-indicator-hover'
|
import useIndicatorHover from '../hooks/use-indicator-hover'
|
||||||
import EntryIndicator from './entry-indicator'
|
import EntryIndicator from './entry-indicator'
|
||||||
|
import { useEntryClick } from '@/features/source-editor/components/review-panel/hooks/use-entry-click'
|
||||||
|
|
||||||
type CommentEntryProps = {
|
type CommentEntryProps = {
|
||||||
docId: DocId
|
docId: DocId
|
||||||
|
@ -36,7 +37,7 @@ function CommentEntry({
|
||||||
permissions,
|
permissions,
|
||||||
}: CommentEntryProps) {
|
}: CommentEntryProps) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { gotoEntry, resolveComment, submitReply, handleLayoutChange } =
|
const { resolveComment, submitReply, handleLayoutChange } =
|
||||||
useReviewPanelUpdaterFnsContext()
|
useReviewPanelUpdaterFnsContext()
|
||||||
const [replyContent, setReplyContent] = useState('')
|
const [replyContent, setReplyContent] = useState('')
|
||||||
const [animating, setAnimating] = useState(false)
|
const [animating, setAnimating] = useState(false)
|
||||||
|
@ -50,22 +51,7 @@ function CommentEntry({
|
||||||
handleIndicatorClick,
|
handleIndicatorClick,
|
||||||
} = useIndicatorHover()
|
} = useIndicatorHover()
|
||||||
|
|
||||||
const handleEntryClick = (e: React.MouseEvent<HTMLDivElement>) => {
|
const handleEntryClick = useEntryClick(docId, offset)
|
||||||
const target = e.target as Element
|
|
||||||
|
|
||||||
for (const selector of [
|
|
||||||
'.rp-entry',
|
|
||||||
'.rp-comment-loaded',
|
|
||||||
'.rp-comment-content',
|
|
||||||
'.rp-comment-reply',
|
|
||||||
'.rp-entry-metadata',
|
|
||||||
]) {
|
|
||||||
if (target.matches(selector)) {
|
|
||||||
gotoEntry(docId, offset)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleAnimateAndCallOnResolve = () => {
|
const handleAnimateAndCallOnResolve = () => {
|
||||||
setAnimating(true)
|
setAnimating(true)
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { useReviewPanelUpdaterFnsContext } from '@/features/source-editor/context/review-panel/review-panel-context'
|
||||||
|
import { DocId } from '../../../../../../../types/project-settings'
|
||||||
|
|
||||||
|
export function useEntryClick(docId: DocId, offset: number) {
|
||||||
|
const { gotoEntry } = useReviewPanelUpdaterFnsContext()
|
||||||
|
|
||||||
|
return (e: React.MouseEvent<HTMLDivElement>) => {
|
||||||
|
const target = e.target as Element
|
||||||
|
|
||||||
|
// Ignore clicks inside interactive elements
|
||||||
|
if (!target.closest('textarea, button, a')) {
|
||||||
|
// If the user was making a selection within the entry rather than
|
||||||
|
// clicking it, ignore the click. Do this by checking whether there is a
|
||||||
|
// selection that intersects with the target, in which case we assume
|
||||||
|
// the user was making a selection
|
||||||
|
const selection = window.getSelection()
|
||||||
|
if (
|
||||||
|
!selection ||
|
||||||
|
selection.isCollapsed ||
|
||||||
|
selection.rangeCount === 0 ||
|
||||||
|
!selection.getRangeAt(0).intersectsNode(target)
|
||||||
|
) {
|
||||||
|
gotoEntry(docId, offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue