import React, { CSSProperties, RefObject, useCallback } from "react"; import useKeyEvent from "../../hooks/useKeyEvent"; import Flex from "../Flex/Flex"; import Avatar, { AvatarProps } from "../Avatar/Avatar"; import ClickableWrapper from "../Clickable/ClickableWrapper"; import avatarGroupCounterTooltipContentStyles from "./AvatarGroupCounterTooltipContent.module.scss"; import useEventListener from "../../hooks/useEventListener"; import useListenFocusTriggers from "../../hooks/useListenFocusTriggers"; import { AvatarType } from "../Avatar/AvatarConstants"; import { ElementContent } from "src/types/ElementContent"; import { AVATAR_GROUP_COUNTER_AVATAR_SIZE, AVATAR_GROUP_COUNTER_TOOLTIP_SHOW_DELAY } from "./AvatarGroupConstants"; import { keyCodes } from "../../constants"; const TAB = [keyCodes.TAB]; const ESC = [keyCodes.ESCAPE]; export function useTooltipContentTabNavigation({ counterContainerRef = undefined, tooltipContentContainerRef, focusPrevPlaceholderRef, focusNextPlaceholderRef, isKeyboardTooltipVisible, setIsKeyboardTooltipVisible }: { counterContainerRef: RefObject; tooltipContentContainerRef: RefObject; focusPrevPlaceholderRef: RefObject; focusNextPlaceholderRef: RefObject; isKeyboardTooltipVisible: boolean; setIsKeyboardTooltipVisible: (value: boolean) => void; }) { const showKeyboardTooltip = useCallback(() => { if (!isKeyboardTooltipVisible) { // temp hack for display tooltip with delay after timeout because refactoring the tooltip with open mechanism is out of scope setTimeout(() => setIsKeyboardTooltipVisible(true), AVATAR_GROUP_COUNTER_TOOLTIP_SHOW_DELAY); } }, [isKeyboardTooltipVisible, setIsKeyboardTooltipVisible]); const hideKeyboardTooltip = useCallback(() => { if (isKeyboardTooltipVisible) setIsKeyboardTooltipVisible(false); }, [isKeyboardTooltipVisible, setIsKeyboardTooltipVisible]); // Open tooltip manually when keyboard focusing on counter useListenFocusTriggers({ ref: counterContainerRef, onFocusByKeyboard: showKeyboardTooltip }); useEventListener({ eventName: "blur", ref: tooltipContentContainerRef, callback: hideKeyboardTooltip }); //Move focus to content by keyboard useKeyEvent({ keys: TAB, ref: counterContainerRef, withoutAnyModifier: true, preventDefault: true, callback: useCallback(() => { if (isKeyboardTooltipVisible) tooltipContentContainerRef?.current && tooltipContentContainerRef.current.focus(); }, [isKeyboardTooltipVisible, tooltipContentContainerRef]) }); // Close tooltip by keyboard useKeyEvent({ keys: TAB, modifier: useKeyEvent.modifiers.SHIFT, ref: counterContainerRef, callback: hideKeyboardTooltip }); useKeyEvent({ keys: TAB, ref: tooltipContentContainerRef, withoutAnyModifier: true, callback: useCallback(() => { // We are not preventing default behaviour here and that's why after pressing tab and after moving focus to here // the browser will move the focus to the next element in the focus order. focusNextPlaceholderRef?.current && focusNextPlaceholderRef.current.focus(); if (isKeyboardTooltipVisible) setIsKeyboardTooltipVisible(false); }, [focusNextPlaceholderRef, isKeyboardTooltipVisible, setIsKeyboardTooltipVisible]) }); useKeyEvent({ keys: TAB, ref: tooltipContentContainerRef, modifier: useKeyEvent.modifiers.SHIFT, callback: useCallback(() => { // We are not preventing default behaviour here and that's why after pressing tab and after moving focus to here // the browser will move the focus to the next element in the focus order. focusPrevPlaceholderRef?.current && focusPrevPlaceholderRef.current.focus(); if (isKeyboardTooltipVisible) setIsKeyboardTooltipVisible(false); }, [focusPrevPlaceholderRef, isKeyboardTooltipVisible, setIsKeyboardTooltipVisible]) }); useKeyEvent({ keys: ESC, ref: tooltipContentContainerRef, callback: useCallback(() => { counterContainerRef?.current && counterContainerRef.current.focus(); if (isKeyboardTooltipVisible) setIsKeyboardTooltipVisible(false); }, [counterContainerRef, isKeyboardTooltipVisible, setIsKeyboardTooltipVisible]) }); useKeyEvent({ keys: ESC, ref: counterContainerRef, callback: hideKeyboardTooltip }); // Close tooltip when moving focus to next element useEventListener({ eventName: "focus", ref: focusNextPlaceholderRef, callback: hideKeyboardTooltip }); } export const avatarRenderer = ( item: { value: AvatarProps & { tooltipContent: ElementContent } }, index: number, style: CSSProperties, type: AvatarType, displayAsGrid: boolean ) => { const avatarProps = item.value; const overrideStyle: CSSProperties = { ...style, width: displayAsGrid ? undefined : "100%" }; const labelId = `tooltip-item-${index}-label`; return ( avatarProps.onClick(event, avatarProps.id), tabIndex: "-1" }} >
{!displayAsGrid && (
{avatarProps.tooltipContent}
)}
); };