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:
Tim Down 2023-11-21 14:29:01 +00:00 committed by Copybot
parent 2807a35e24
commit 4f13470345
4 changed files with 36 additions and 49 deletions

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)
}
}
}
}