Skip to content

Commit

Permalink
Fix escape key events in customizer closing the editor (#32175)
Browse files Browse the repository at this point in the history
  • Loading branch information
kevin940726 authored May 27, 2021
1 parent 4725f81 commit da0d78a
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export default function useTabNav() {
const ref = useRefEffect( ( node ) => {
function onKeyDown( event ) {
if ( event.keyCode === ESCAPE && ! hasMultiSelection() ) {
event.stopPropagation();
setNavigationMode( true );
return;
}
Expand Down
39 changes: 23 additions & 16 deletions packages/components/src/popover/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
useConstrainedTabbing,
useFocusReturn,
useMergeRefs,
useRefEffect,
} from '@wordpress/compose';
import { close } from '@wordpress/icons';

Expand Down Expand Up @@ -232,7 +233,6 @@ const Popover = (
{
headerTitle,
onClose,
onKeyDown,
children,
className,
noArrow = true,
Expand Down Expand Up @@ -477,32 +477,40 @@ const Popover = (
__unstableBoundaryParent,
] );

// Event handlers for closing the popover.
const closeEventRef = useRefEffect(
( node ) => {
function maybeClose( event ) {
// Close on escape.
if ( event.keyCode === ESCAPE && onClose ) {
event.stopPropagation();
onClose();
}
}

node.addEventListener( 'keydown', maybeClose );

return () => {
node.removeEventListener( 'keydown', maybeClose );
};
},
[ onClose ]
);

const constrainedTabbingRef = useConstrainedTabbing();
const focusReturnRef = useFocusReturn();
const focusOnMountRef = useFocusOnMount( focusOnMount );
const focusOutsideProps = useFocusOutside( handleOnFocusOutside );
const mergedRefs = useMergeRefs( [
ref,
containerRef,
// Don't register the event at all if there's no onClose callback.
onClose ? closeEventRef : null,
focusOnMount ? constrainedTabbingRef : null,
focusOnMount ? focusReturnRef : null,
focusOnMount ? focusOnMountRef : null,
] );

// Event handlers
const maybeClose = ( event ) => {
// Close on escape
if ( event.keyCode === ESCAPE && onClose ) {
event.stopPropagation();
onClose();
}

// Preserve original content prop behavior
if ( onKeyDown ) {
onKeyDown( event );
}
};

/**
* Shims an onFocusOutside callback to be compatible with a deprecated
* onClickOutside prop function, if provided.
Expand Down Expand Up @@ -587,7 +595,6 @@ const Popover = (
}
) }
{ ...contentProps }
onKeyDown={ maybeClose }
{ ...focusOutsideProps }
ref={ mergedRefs }
tabIndex="-1"
Expand Down
51 changes: 51 additions & 0 deletions packages/e2e-tests/specs/widgets/customizing-widgets.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,57 @@ describe( 'Widgets Customizer', () => {
"The page delivered both an 'X-Frame-Options' header and a 'Content-Security-Policy' header with a 'frame-ancestors' directive. Although the 'X-Frame-Options' header alone would have blocked embedding, it has been ignored."
);
} );

it( 'should handle esc key events', async () => {
const widgetsPanel = await find( {
role: 'heading',
name: /Widgets/,
level: 3,
} );
await widgetsPanel.click();

const footer1Section = await find( {
role: 'heading',
name: /^Footer #1/,
level: 3,
} );
await footer1Section.click();

const paragraphBlock = await addBlock( 'Paragraph' );
await page.keyboard.type( 'First Paragraph' );
await showBlockToolbar();

// Open the more menu dropdown in block toolbar.
await clickBlockToolbarButton( 'Options' );
await expect( {
role: 'menu',
name: 'Options',
} ).toBeFound();

// Expect pressing the Escape key to close the dropdown,
// but not close the editor.
await page.keyboard.press( 'Escape' );
await expect( {
role: 'menu',
name: 'Options',
} ).not.toBeFound();
await expect( paragraphBlock ).toBeVisible();

await paragraphBlock.focus();

// Expect pressing the Escape key to enter navigation mode,
// but not close the editor.
await page.keyboard.press( 'Escape' );
await expect( {
text: /^You are currently in navigation mode\./,
selector: '*[aria-live="polite"][aria-relevant="additions text"]',
} ).toBeFound();
await expect( paragraphBlock ).toBeVisible();

expect( console ).toHaveWarned(
"The page delivered both an 'X-Frame-Options' header and a 'Content-Security-Policy' header with a 'frame-ancestors' directive. Although the 'X-Frame-Options' header alone would have blocked embedding, it has been ignored."
);
} );
} );

/**
Expand Down

0 comments on commit da0d78a

Please sign in to comment.