Skip to content

Commit 8649513

Browse files
t-hamanokarthick-muruganjeffpaulellatrixMamaduka
authored
Notes: Collapse note on blur (#73158)
* Notes: Collapse note on blur * Update comment * WIP * Don't debounce onBlur and onFocus * Avoid prop drilling * Simplify conditional statement * Update packages/editor/src/components/collab-sidebar/comments.js Co-authored-by: George Mamadashvili <georgemamadashvili@gmail.com> * Correctly handle onBlur event * Add comment * Fix comment * Fix double space Co-authored-by: George Mamadashvili <georgemamadashvili@gmail.com> * Always toggle block spotlight on note selection --------- Co-authored-by: karthick-murugan <karthickmurugan@git.wordpress.org> Co-authored-by: t-hamano <wildworks@git.wordpress.org> Co-authored-by: jeffpaul <jeffpaul@git.wordpress.org> Co-authored-by: ellatrix <ellatrix@git.wordpress.org> Co-authored-by: Mamaduka <mamaduka@git.wordpress.org> Co-authored-by: desrosj <desrosj@git.wordpress.org> Co-authored-by: Mamaduka <mamaduka@git.wordpress.org> Co-authored-by: roseg43 <gabertronic@git.wordpress.org>
1 parent bae645e commit 8649513

File tree

2 files changed

+82
-5
lines changed

2 files changed

+82
-5
lines changed

packages/editor/src/components/collab-sidebar/comments.js

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,7 @@ function Thread( {
470470
selectedThread,
471471
commentLastUpdated,
472472
} );
473+
const isKeyboardTabbingRef = useRef( false );
473474

474475
const onMouseEnter = () => {
475476
debouncedToggleBlockHighlight( thread.blockClientId, true );
@@ -479,13 +480,48 @@ function Thread( {
479480
debouncedToggleBlockHighlight( thread.blockClientId, false );
480481
};
481482

483+
const onFocus = () => {
484+
toggleBlockHighlight( thread.blockClientId, true );
485+
};
486+
487+
const onBlur = ( event ) => {
488+
const isNoteFocused = event.relatedTarget?.closest(
489+
'.editor-collab-sidebar-panel__thread'
490+
);
491+
const isDialogFocused =
492+
event.relatedTarget?.closest( '[role="dialog"]' );
493+
const isTabbing = isKeyboardTabbingRef.current;
494+
495+
// When another note is clicked, do nothing because the current note is automatically closed.
496+
if ( isNoteFocused && ! isTabbing ) {
497+
return;
498+
}
499+
// When deleting a note, a dialog appears, but the note should not be collapsed.
500+
if ( isDialogFocused ) {
501+
return;
502+
}
503+
// When tabbing, do nothing if the focus is within the current note.
504+
if (
505+
isTabbing &&
506+
event.currentTarget.contains( event.relatedTarget )
507+
) {
508+
return;
509+
}
510+
511+
// Closes a note that has lost focus when any of the following conditions are met:
512+
// - An element other than a note is clicked.
513+
// - Focus was lost by tabbing.
514+
toggleBlockHighlight( thread.blockClientId, false );
515+
unselectThread();
516+
};
517+
482518
const handleCommentSelect = () => {
483519
setNewNoteFormState( 'closed' );
484520
setSelectedThread( thread.id );
521+
toggleBlockSpotlight( thread.blockClientId, true );
485522
if ( !! thread.blockClientId ) {
486523
// Pass `null` as the second parameter to prevent focusing the block.
487524
selectBlock( thread.blockClientId, null );
488-
toggleBlockSpotlight( thread.blockClientId, true );
489525
}
490526
};
491527

@@ -547,9 +583,20 @@ function Thread( {
547583
onClick={ handleCommentSelect }
548584
onMouseEnter={ onMouseEnter }
549585
onMouseLeave={ onMouseLeave }
550-
onFocus={ onMouseEnter }
551-
onBlur={ onMouseLeave }
552-
onKeyDown={ onKeyDown }
586+
onFocus={ onFocus }
587+
onBlur={ onBlur }
588+
onKeyUp={ ( event ) => {
589+
if ( event.key === 'Tab' ) {
590+
isKeyboardTabbingRef.current = false;
591+
}
592+
} }
593+
onKeyDown={ ( event ) => {
594+
if ( event.key === 'Tab' ) {
595+
isKeyboardTabbingRef.current = true;
596+
} else {
597+
onKeyDown( event );
598+
}
599+
} }
553600
tabIndex={ 0 }
554601
role="treeitem"
555602
aria-label={ ariaLabel }
@@ -836,7 +883,12 @@ const CommentBoard = ( {
836883
/>
837884
}
838885
/>
839-
<Menu.Popover>
886+
<Menu.Popover
887+
// The menu popover is rendered in a portal, which causes focus to be
888+
// lost and the note to be collapsed unintentionally. To prevent this,
889+
// the popover should be rendered as an inline.
890+
modal={ false }
891+
>
840892
{ moreActions.map( ( action ) => (
841893
<Menu.Item
842894
key={ action.id }

test/e2e/specs/editor/various/block-comments.spec.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,31 @@ test.describe( 'Block Comments', () => {
477477
await expect( thread ).toBeFocused();
478478
} );
479479

480+
test( 'should collapse a comment when the focus moves outside the note', async ( {
481+
page,
482+
blockCommentUtils,
483+
} ) => {
484+
await blockCommentUtils.addBlockWithComment( {
485+
type: 'core/heading',
486+
attributes: { content: 'Testing block comments' },
487+
comment: 'Test comment',
488+
} );
489+
490+
const thread = page
491+
.getByRole( 'region', {
492+
name: 'Editor settings',
493+
} )
494+
.getByRole( 'treeitem', {
495+
name: 'Note: Test comment',
496+
} );
497+
498+
await thread.click();
499+
await expect( thread ).toHaveAttribute( 'aria-expanded', 'true' );
500+
await page.keyboard.press( 'Shift+Tab' );
501+
await expect( thread ).not.toBeFocused();
502+
await expect( thread ).toHaveAttribute( 'aria-expanded', 'false' );
503+
} );
504+
480505
test( 'should have accessible name for the comment threads', async ( {
481506
page,
482507
blockCommentUtils,

0 commit comments

Comments
 (0)