From 5589a1a27c6aac277399f0a1f5e56a8715a66289 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Wed, 1 Feb 2023 16:45:39 -0800 Subject: [PATCH] Add screen reader instructions on interacting with the flyout - allow for custom `role`s that consumers pass in that aren't `dialog`s (likely very rare, may need more testing) - remove `closeButtonAriaLabel`. Consumers can use `closeButtonProps['aria-label']` instead + misc cleanup - remove `Fragment` TODO: write tests --- src/components/flyout/flyout.test.tsx | 25 +-------- src/components/flyout/flyout.tsx | 80 +++++++++++++++++++-------- 2 files changed, 58 insertions(+), 47 deletions(-) diff --git a/src/components/flyout/flyout.test.tsx b/src/components/flyout/flyout.test.tsx index 90c5e6fb7d42..0010ac2e2680 100644 --- a/src/components/flyout/flyout.test.tsx +++ b/src/components/flyout/flyout.test.tsx @@ -7,7 +7,7 @@ */ import React from 'react'; -import { render, mount } from 'enzyme'; +import { mount } from 'enzyme'; import { requiredProps, takeMountedSnapshot } from '../../test'; import { shouldRenderCustomStyles } from '../../test/internal'; @@ -76,29 +76,6 @@ describe('EuiFlyout', () => { ).toMatchSnapshot(); }); - describe('closeButtonAriaLabel', () => { - test('has a default label for the close button', () => { - const component = render( {}} />); - const label = component - .find('[data-test-subj="euiFlyoutCloseButton"]') - .prop('aria-label'); - expect(label).toBe('Close this dialog'); - }); - - test('sets a custom label for the close button', () => { - const component = render( - {}} - closeButtonAriaLabel="Closes specific flyout" - /> - ); - const label = component - .find('[data-test-subj="euiFlyoutCloseButton"]') - .prop('aria-label'); - expect(label).toBe('Closes specific flyout'); - }); - }); - test('accepts div props', () => { const component = mount( {}} id="imaflyout" />); diff --git a/src/components/flyout/flyout.tsx b/src/components/flyout/flyout.tsx index 90f05ad2ae37..d2eab98a43f1 100644 --- a/src/components/flyout/flyout.tsx +++ b/src/components/flyout/flyout.tsx @@ -14,7 +14,6 @@ import React, { ComponentPropsWithRef, CSSProperties, ElementType, - Fragment, FunctionComponent, MouseEvent as ReactMouseEvent, MutableRefObject, @@ -28,6 +27,7 @@ import { EuiBreakpointSize, useIsWithinMinBreakpoint, useEuiTheme, + useGeneratedHtmlId, } from '../../services'; import { logicalStyle } from '../../global_styling'; @@ -38,6 +38,7 @@ import { EuiButtonIcon, EuiButtonIconPropsForButton } from '../button'; import { EuiI18n } from '../i18n'; import { useResizeObserver } from '../observer/resize_observer'; import { EuiPortal } from '../portal'; +import { EuiScreenReaderOnly } from '../accessibility'; import { euiFlyoutStyles, euiFlyoutCloseButtonStyles } from './flyout.styles'; @@ -93,11 +94,6 @@ interface _EuiFlyoutProps { * @default false */ hideCloseButton?: boolean; - /** - * Specify a custom aria-label for the close button of the flyout. - * @default "Close this dialog" - */ - closeButtonAriaLabel?: string; /** * Extends EuiButtonIconProps onto the close button */ @@ -180,7 +176,6 @@ export const EuiFlyout = forwardRef( as, hideCloseButton = false, closeButtonProps, - closeButtonAriaLabel, closeButtonPosition = 'inside', onClose, ownFocus = true, @@ -305,14 +300,18 @@ export const EuiFlyout = forwardRef( ]; closeButton = ( - + {(closeAriaLabel: string) => ( +

+ {' '} + {hasOverlayMask && ( + + )}{' '} + {fixedHeaders.length > 0 && ( + + )} +

+ + ); + + /* + * Trap focus even when `ownFocus={false}`, otherwise closing + * the flyout won't return focus to the originating button. + * + * Set `clickOutsideDisables={true}` when `ownFocus={false}` + * to allow non-keyboard users the ability to interact with + * elements outside the flyout. + * + * Set `onClickOutside={onClose}` when `ownFocus` and `type` are the defaults, + * or if `outsideClickCloses={true}` to close on clicks that target + * (both mousedown and mouseup) the overlay mask. + */ const onClickOutside = (event: MouseEvent | TouchEvent) => { // Do not close the flyout for any external click if (outsideClickCloses === false) return undefined; @@ -369,18 +412,7 @@ export const EuiFlyout = forwardRef( // Otherwise if ownFocus is false and outsideClickCloses is undefined, outside clicks should not close the flyout return undefined; }; - /* - * Trap focus even when `ownFocus={false}`, otherwise closing - * the flyout won't return focus to the originating button. - * - * Set `clickOutsideDisables={true}` when `ownFocus={false}` - * to allow non-keyboard users the ability to interact with - * elements outside the flyout. - * - * Set `onClickOutside={onClose}` when `ownFocus` and `type` are the defaults, - * or if `outsideClickCloses={true}` to close on clicks that target - * (both mousedown and mouseup) the overlay mask. - */ + let flyout = ( + {screenReaderDescription} {closeButton} {children} @@ -421,10 +455,10 @@ export const EuiFlyout = forwardRef( } return ( - + <> {flyout} - + ); } // React.forwardRef interferes with the inferred element type