import { FC, useCallback, useEffect, useState } from 'react' import { AnyOperation } from '../../../../../types/change' import { useCodeMirrorStateContext, useCodeMirrorViewContext, } from '@/features/source-editor/components/codemirror-context' import { isSelectionWithinOp } from '../utils/is-selection-within-op' import classNames from 'classnames' import { clearHighlightRanges, highlightRanges, } from '@/features/source-editor/extensions/ranges' import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context' import { useLayoutContext } from '@/shared/context/layout-context' import { EditorSelection } from '@codemirror/state' import { EditorView } from '@codemirror/view' import MaterialIcon from '@/shared/components/material-icon' export const ReviewPanelEntry: FC<{ position: number op: AnyOperation docId: string top?: number className?: string selectLineOnFocus?: boolean hoverRanges?: boolean disabled?: boolean onEnterEntryIndicator?: () => void onLeaveEntryIndicator?: () => void entryIndicator?: 'comment' | 'edit' }> = ({ children, position, top, op, className, selectLineOnFocus = true, docId, hoverRanges = true, disabled, onEnterEntryIndicator, onLeaveEntryIndicator, entryIndicator, }) => { const state = useCodeMirrorStateContext() const view = useCodeMirrorViewContext() const { openDocId, getCurrentDocId } = useEditorManagerContext() const [selected, setSelected] = useState(false) const [focused, setFocused] = useState(false) const { setReviewPanelOpen, reviewPanelOpen } = useLayoutContext() const highlighted = isSelectionWithinOp(op, state.selection.main) const openReviewPanel = useCallback(() => { setReviewPanelOpen(true) }, [setReviewPanelOpen]) const focusHandler = useCallback( event => { setFocused(true) if ( event.target instanceof HTMLButtonElement || event.target instanceof HTMLLinkElement || event.target instanceof HTMLAnchorElement || (event.target instanceof HTMLTextAreaElement && !reviewPanelOpen) ) { // Ignore focus events on certain elements so as to not affect // their behavior return } setSelected(true) if (!selectLineOnFocus) { return } if (getCurrentDocId() !== docId) { const focusIsOnTextarea = event.target instanceof HTMLTextAreaElement if (focusIsOnTextarea === false) { openDocId(docId, { gotoOffset: position, keepCurrentView: true }) } } else { setTimeout(() => view.dispatch({ selection: EditorSelection.cursor(position), effects: EditorView.scrollIntoView(position, { y: 'center' }), }) ) } }, [ getCurrentDocId, docId, selectLineOnFocus, view, position, openDocId, reviewPanelOpen, ] ) // Clear op highlight on dismount useEffect(() => { return () => { if (hoverRanges) { setTimeout(() => { view.dispatch(clearHighlightRanges(op)) }) } } }, []) // eslint-disable-line react-hooks/exhaustive-deps return (