Focused and selected states for ReviewPanelEntry (#21354)

GitOrigin-RevId: 41e5ed1110d71eae51cbbde1e874dda133d666c8
This commit is contained in:
Domagoj Kriskovic 2024-10-25 15:05:44 +02:00 committed by Copybot
parent db23262611
commit 29c5bc8206
4 changed files with 29 additions and 7 deletions

View file

@ -38,6 +38,7 @@ export const ReviewPanelEntry: FC<{
const state = useCodeMirrorStateContext() const state = useCodeMirrorStateContext()
const view = useCodeMirrorViewContext() const view = useCodeMirrorViewContext()
const { openDocId, getCurrentDocId } = useEditorManagerContext() const { openDocId, getCurrentDocId } = useEditorManagerContext()
const [selected, setSelected] = useState(false)
const [focused, setFocused] = useState(false) const [focused, setFocused] = useState(false)
const { setReviewPanelOpen } = useLayoutContext() const { setReviewPanelOpen } = useLayoutContext()
@ -49,6 +50,8 @@ export const ReviewPanelEntry: FC<{
const focusHandler = useCallback( const focusHandler = useCallback(
event => { event => {
setFocused(true)
if ( if (
event.target instanceof HTMLButtonElement || event.target instanceof HTMLButtonElement ||
event.target instanceof HTMLLinkElement || event.target instanceof HTMLLinkElement ||
@ -59,7 +62,7 @@ export const ReviewPanelEntry: FC<{
return return
} }
setFocused(true) setSelected(true)
if (!selectLineOnFocus) { if (!selectLineOnFocus) {
return return
@ -97,7 +100,10 @@ export const ReviewPanelEntry: FC<{
<div <div
onMouseDown={openReviewPanel} // Using onMouseDown rather than onClick to guarantee that it fires before onFocus onMouseDown={openReviewPanel} // Using onMouseDown rather than onClick to guarantee that it fires before onFocus
onFocus={focusHandler} onFocus={focusHandler}
onBlur={() => setFocused(false)} onBlur={() => {
setSelected(false)
setFocused(false)
}}
onMouseEnter={() => { onMouseEnter={() => {
if (hoverRanges) { if (hoverRanges) {
view.dispatch(highlightRanges(op)) view.dispatch(highlightRanges(op))
@ -113,7 +119,15 @@ export const ReviewPanelEntry: FC<{
className={classNames( className={classNames(
'review-panel-entry', 'review-panel-entry',
{ {
// 'selected' is used to manually select an entry
// useful if the range is within range and you want to show the one outside the viewport
// it is not enough to just check isSelectionWithinOp for that
'review-panel-entry-selected': selected,
// 'focused' is set even when an entry was clicked but not selected (like clicking on a menu option)
// used to set z-index above other entries (since entries are not ordered the same way visually and in the DOM)
'review-panel-entry-focused': focused, 'review-panel-entry-focused': focused,
// 'highlighted' is set if the selection is within op but that doesn't necessarily mean it should be selected
// multiple entries can be highlighted at the same time
'review-panel-entry-highlighted': highlighted, 'review-panel-entry-highlighted': highlighted,
'review-panel-entry-disabled': disabled, 'review-panel-entry-disabled': disabled,
}, },

View file

@ -26,14 +26,14 @@ export const positionItems = debounce(
if (activeItemIndex === -1) { if (activeItemIndex === -1) {
// if there is no action available // if there is no action available
// check if there is a focused entry // check if there is manually selected entry
activeItemIndex = items.findIndex(item => activeItemIndex = items.findIndex(item =>
item.classList.contains('review-panel-entry-focused') item.classList.contains('review-panel-entry-selected')
) )
} }
if (activeItemIndex === -1) { if (activeItemIndex === -1) {
// if entry was not focused manually // if entry was not selected manually
// check if there is an entry in selection and use that as the focused item // check if there is an entry in selection and use that as the focused item
activeItemIndex = items.findIndex(item => activeItemIndex = items.findIndex(item =>
item.classList.contains('review-panel-entry-highlighted') item.classList.contains('review-panel-entry-highlighted')

View file

@ -51,7 +51,7 @@
gap: @spacing-04; gap: @spacing-04;
} }
.review-panel-entry.review-panel-entry-focused, .review-panel-entry.review-panel-entry-selected,
.review-panel-entry.review-panel-entry-highlighted { .review-panel-entry.review-panel-entry-highlighted {
margin-left: @spacing-01; margin-left: @spacing-01;
border: 1px solid @blue-50; border: 1px solid @blue-50;
@ -61,6 +61,10 @@
0px 2px 4px rgba(30, 37, 48, 0.08); 0px 2px 4px rgba(30, 37, 48, 0.08);
} }
.review-panel-entry.review-panel-entry-focused {
z-index: 2;
}
.review-panel-entry-header { .review-panel-entry-header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;

View file

@ -56,7 +56,7 @@
gap: var(--spacing-04); gap: var(--spacing-04);
} }
.review-panel-entry.review-panel-entry-focused, .review-panel-entry.review-panel-entry-selected,
.review-panel-entry.review-panel-entry-highlighted { .review-panel-entry.review-panel-entry-highlighted {
margin-left: var(--spacing-01); margin-left: var(--spacing-01);
border: 1px solid var(--border-active); border: 1px solid var(--border-active);
@ -64,6 +64,10 @@
@include shadow-md; @include shadow-md;
} }
.review-panel-entry.review-panel-entry-focused {
z-index: 2;
}
.review-panel-entry-header { .review-panel-entry-header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;