diff --git a/packages/lib/src/toast/Toast.tsx b/packages/lib/src/toast/Toast.tsx index 9d26f2cec..c667188f6 100644 --- a/packages/lib/src/toast/Toast.tsx +++ b/packages/lib/src/toast/Toast.tsx @@ -1,4 +1,4 @@ -import { memo, useContext, useState } from "react"; +import { memo, useContext, useState, useRef, useEffect } from "react"; import styled, { keyframes } from "styled-components"; import DxcActionIcon from "../action-icon/ActionIcon"; import DxcButton from "../button/Button"; @@ -51,6 +51,10 @@ const Toast = styled.output<{ semantic: ToastPropsType["semantic"]; isClosing: b @media (max-width: ${responsiveSizes.medium}rem) { max-width: 100%; } + + &:focus { + outline: none; + } `; const ContentContainer = styled.div<{ loading: ToastPropsType["loading"]; semantic: ToastPropsType["semantic"] }>` @@ -87,24 +91,69 @@ const DxcToast = ({ semantic, }: ToastPropsType) => { const [isClosing, setIsClosing] = useState(false); + const toastRef = useRef(null); + const previouslyFocusedElement = useRef(null); const translatedLabels = useContext(HalstackLanguageContext); - const clearClosingAnimationTimer = useTimeout( - () => { - setIsClosing(true); - }, - loading ? undefined : duration - 300 - ); + // Timeouts + const clearClosingAnimationTimer = useTimeout(() => setIsClosing(true), loading ? undefined : duration - 300); - const clearTimer = useTimeout( - () => { - onClear(); - }, - loading ? undefined : duration - ); + const clearTimer = useTimeout(() => onClear(), loading ? undefined : duration); + + useEffect(() => { + previouslyFocusedElement.current = document.activeElement as HTMLElement; + + toastRef.current?.focus(); + + return () => { + previouslyFocusedElement.current?.focus?.(); + }; + }, []); + + const handleOnKeyDown = (event: React.KeyboardEvent) => { + if (event.key === "Tab") { + event.preventDefault(); + + const focusableElements = toastRef.current?.querySelectorAll( + 'button, [tabindex]:not([tabindex="-1"])' + ); + if (!focusableElements || focusableElements.length === 0) return; + + const firstElement = focusableElements?.[0]; + const lastElement = focusableElements?.[focusableElements.length - 1]; + const activeElement = document.activeElement; + + const elementsArray = Array.from(focusableElements); + + if (!event.shiftKey) { + if (activeElement === lastElement) { + previouslyFocusedElement.current?.focus?.(); + } else { + const currentIndex = elementsArray.indexOf(activeElement as HTMLElement); + const nextElement = focusableElements[currentIndex + 1]; + nextElement?.focus(); + } + } else { + if (activeElement === firstElement) { + previouslyFocusedElement.current?.focus?.(); + } else { + const currentIndex = elementsArray.indexOf(activeElement as HTMLElement); + const prevElement = focusableElements[currentIndex - 1]; + prevElement?.focus(); + } + } + } + }; return ( - + {message}