mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
fix: [Obs Synthetics > Monitor detail][KEYBOARD]: Thumbnail images must take keyboard focus, open modal on keypress, and manage focus correctly (#187446)
Closes: https://github.com/elastic/observability-dev/issues/3687 ## Description The synthetics monitors include thumbnail screenshots that open a larger preview window. These thumbnails must take keyboard focus, manage the `Enter` and `Space` keypresses to open the modal, and return focus to the originating thumbnail when the modal is closed. Screenshots attached below. ### Steps to recreate 1. Open the [Synthetics](https://keep-serverless-fyzdg-f07c50.kb.eu-west-1.aws.qa.elastic.cloud/app/synthetics) view 2. Create a monitor if none exist 3. Click on that monitor and navigate to the [full monitor detail](8b88e937
-f917-4f12-9325-8ab005cffea5?locationId=us_central_qa) view 4. Click on a thumbnail and verify the modal opens 5. Press `ESC` or the Close "X" and then press `TAB` to verify focus is not on the thumbnail ### What was changed?: 1. Added `tabIndex=0` was for ScreenshotImage for handle keyboard navigation 2. `ScreenshotImage` API was sightly changed: `onMouseEnter` -> `onFocus`; `onMouseLeave` -> `onBlur` ### Screen:a68df4b0
-71c7-47ec-add7-41536027613c
This commit is contained in:
parent
490bbdb3f6
commit
2ebd0ed3c4
3 changed files with 30 additions and 25 deletions
|
@ -5,13 +5,13 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useState, MouseEvent } from 'react';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { EuiPopover, useEuiTheme } from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { POPOVER_SCREENSHOT_SIZE, ScreenshotImageSize } from '../screenshot/screenshot_size';
|
||||
import { JourneyScreenshotDialog } from '../screenshot/journey_screenshot_dialog';
|
||||
import { ScreenshotImage } from '../screenshot/screenshot_image';
|
||||
import { ScreenshotImage, ScreenshotImageProps } from '../screenshot/screenshot_image';
|
||||
|
||||
export interface StepImagePopoverProps {
|
||||
timestamp?: string;
|
||||
|
@ -47,24 +47,24 @@ export const JourneyScreenshotPreview: React.FC<StepImagePopoverProps> = ({
|
|||
// Only render the dialog if the image is at least once clicked
|
||||
const [isImageEverClick, setIsImageEverClicked] = useState(false);
|
||||
|
||||
const onMouseEnter = useCallback(
|
||||
(_evt: MouseEvent<HTMLImageElement>) => {
|
||||
const onImgFocus: ScreenshotImageProps['onFocus'] = useCallback(
|
||||
(_evt) => {
|
||||
setIsImagePopoverOpen(true);
|
||||
},
|
||||
[setIsImagePopoverOpen]
|
||||
);
|
||||
|
||||
const onMouseLeave = useCallback(
|
||||
(_evt: MouseEvent<HTMLImageElement>) => {
|
||||
const onImgBlur: ScreenshotImageProps['onBlur'] = useCallback(
|
||||
(_evt) => {
|
||||
setIsImagePopoverOpen(false);
|
||||
},
|
||||
[setIsImagePopoverOpen]
|
||||
);
|
||||
|
||||
const onImgClick = useCallback(
|
||||
(evt: MouseEvent<HTMLImageElement>) => {
|
||||
// needed to prevent propagation to the table row click
|
||||
const onImgClick: ScreenshotImageProps['onClick'] = useCallback(
|
||||
(evt) => {
|
||||
evt.stopPropagation();
|
||||
|
||||
setIsImageEverClicked(true);
|
||||
setIsImageDialogOpen(true);
|
||||
setIsImagePopoverOpen(false);
|
||||
|
@ -92,8 +92,8 @@ export const JourneyScreenshotPreview: React.FC<StepImagePopoverProps> = ({
|
|||
unavailableMessage={unavailableMessage}
|
||||
borderColor={isStepFailed ? euiTheme.colors.danger : undefined}
|
||||
borderRadius={borderRadius}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
onFocus={onImgFocus}
|
||||
onBlur={onImgBlur}
|
||||
onClick={onImgClick}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -133,10 +133,6 @@ export const JourneyScreenshotDialog = ({
|
|||
animateLoading={false}
|
||||
hasBorder={false}
|
||||
size={'full'}
|
||||
onClick={(evt) => {
|
||||
// for table row click to work
|
||||
evt.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
</ModalBodyStyled>
|
||||
|
||||
|
|
|
@ -5,14 +5,16 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useState, MouseEventHandler } from 'react';
|
||||
import { useEuiTheme, EuiThemeComputed } from '@elastic/eui';
|
||||
import React, { useState } from 'react';
|
||||
import { useEuiTheme, EuiThemeComputed, keys } from '@elastic/eui';
|
||||
|
||||
import { EmptyThumbnail } from './empty_thumbnail';
|
||||
import { getConfinedScreenshotSize, ScreenshotImageSize } from './screenshot_size';
|
||||
|
||||
const DEFAULT_SIZE: [number, number] = [512, 512];
|
||||
|
||||
type ScreenshotImageCallback = (e: { stopPropagation(): void }) => void;
|
||||
|
||||
export interface ScreenshotImageProps {
|
||||
label?: string;
|
||||
isLoading: boolean;
|
||||
|
@ -22,9 +24,9 @@ export interface ScreenshotImageProps {
|
|||
borderColor?: EuiThemeComputed['border']['color'];
|
||||
borderRadius?: string | number;
|
||||
hasBorder?: boolean;
|
||||
onMouseEnter?: MouseEventHandler<HTMLImageElement>;
|
||||
onMouseLeave?: MouseEventHandler<HTMLImageElement>;
|
||||
onClick?: MouseEventHandler<HTMLImageElement>;
|
||||
onFocus?: ScreenshotImageCallback;
|
||||
onBlur?: ScreenshotImageCallback;
|
||||
onClick?: ScreenshotImageCallback;
|
||||
}
|
||||
|
||||
export const ScreenshotImage: React.FC<ScreenshotImageProps & { imgSrc?: string }> = ({
|
||||
|
@ -37,8 +39,8 @@ export const ScreenshotImage: React.FC<ScreenshotImageProps & { imgSrc?: string
|
|||
borderRadius,
|
||||
hasBorder = true,
|
||||
size = [100, 64],
|
||||
onMouseEnter,
|
||||
onMouseLeave,
|
||||
onFocus,
|
||||
onBlur,
|
||||
onClick,
|
||||
}) => {
|
||||
const { euiTheme } = useEuiTheme();
|
||||
|
@ -70,10 +72,17 @@ export const ScreenshotImage: React.FC<ScreenshotImageProps & { imgSrc?: string
|
|||
];
|
||||
setNaturalSize(updatedSize);
|
||||
}}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
onMouseEnter={onFocus}
|
||||
onMouseLeave={onBlur}
|
||||
onFocus={onFocus}
|
||||
onBlur={onBlur}
|
||||
onClick={onClick}
|
||||
onKeyDown={undefined}
|
||||
onKeyDown={(evt) => {
|
||||
if (onClick && evt.key === keys.ENTER) {
|
||||
onClick(evt);
|
||||
}
|
||||
}}
|
||||
tabIndex={onClick ? 0 : undefined}
|
||||
/>
|
||||
) : (
|
||||
<EmptyThumbnail
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue