fix: [Obs Create dashboard][KEYBOARD]: Focus must be trapped when the Add from library popover is open (#191440)

Closes:
https://github.com/elastic/observability-accessibility/issues/116

Initial description sounds like: 

> The Obs Create Dashboard view has an "Add from library" popover that
allows keyboard focus to escape behind the smoke layer, which can be
confusing for screen reader users.

During local testing, I didn't find any issues related to focus.
However, we can slightly improve accessibility by providing the
`aria-labelledby` attribute for the `EuiModal`, as recommended by EUI
here: https://eui.elastic.co/#/layout/modal.


## Screens 
### EUI modal with correct title:
<img width="1393" alt="image"
src="https://github.com/user-attachments/assets/1a2cbf7e-e865-432b-98d0-5a15bf313cd1">

### Focus


https://github.com/user-attachments/assets/3bd6e689-110b-4917-b831-75a965d28fa9
This commit is contained in:
Alexey Antonov 2024-08-29 22:25:46 +03:00 committed by GitHub
parent b5dbcd8fb8
commit 6826eafe17
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 15 additions and 4 deletions

View file

@ -82,9 +82,11 @@ const runAddTelemetry = (
export const AddPanelFlyout = ({
container,
onAddPanel,
modalTitleId,
}: {
container: PresentationContainer;
onAddPanel?: (id: string) => void;
modalTitleId?: string;
}) => {
const legacyFactoriesBySavedObjectType: LegacyFactoryMap = useMemo(() => {
return [...embeddableStart.getEmbeddableFactories()]
@ -187,7 +189,7 @@ export const AddPanelFlyout = ({
<>
<EuiFlyoutHeader hasBorder>
<EuiTitle size="m">
<h2>
<h2 id={modalTitleId}>
{i18n.translate('embeddableApi.addPanel.Title', { defaultMessage: 'Add from library' })}
</h2>
</EuiTitle>

View file

@ -9,7 +9,7 @@
import React, { Suspense } from 'react';
import { OverlayRef } from '@kbn/core/public';
import { EuiLoadingSpinner } from '@elastic/eui';
import { EuiLoadingSpinner, htmlIdGenerator } from '@elastic/eui';
import { toMountPoint } from '@kbn/react-kibana-mount';
import { PresentationContainer } from '@kbn/presentation-containers';
@ -20,6 +20,8 @@ const LazyAddPanelFlyout = React.lazy(async () => {
return { default: module.AddPanelFlyout };
});
const htmlId = htmlIdGenerator('modalTitleId');
export const openAddPanelFlyout = ({
container,
onAddPanel,
@ -29,21 +31,28 @@ export const openAddPanelFlyout = ({
onAddPanel?: (id: string) => void;
onClose?: () => void;
}): OverlayRef => {
const modalTitleId = htmlId();
// send the overlay ref to the root embeddable if it is capable of tracking overlays
const flyoutSession = core.overlays.openFlyout(
toMountPoint(
<Suspense fallback={<EuiLoadingSpinner />}>
<LazyAddPanelFlyout container={container} onAddPanel={onAddPanel} />
<LazyAddPanelFlyout
container={container}
onAddPanel={onAddPanel}
modalTitleId={modalTitleId}
/>
</Suspense>,
core
),
{
'data-test-subj': 'dashboardAddPanel',
ownFocus: true,
onClose: (overlayRef) => {
if (onClose) onClose();
overlayRef.close();
},
'data-test-subj': 'dashboardAddPanel',
'aria-labelledby': modalTitleId,
}
);