diff --git a/web/packages/new/photos/components/FocusVisibleButton.tsx b/web/packages/new/photos/components/FocusVisibleButton.tsx index b5ceb7a320..1e49e53272 100644 --- a/web/packages/new/photos/components/FocusVisibleButton.tsx +++ b/web/packages/new/photos/components/FocusVisibleButton.tsx @@ -12,5 +12,6 @@ export const RippleDisabledButton: React.FC = (props) => ( export const FocusVisibleButton = styled(RippleDisabledButton)` &.Mui-focusVisible { outline: 1px solid ${(props) => props.theme.colors.stroke.base}; + outline-offset: 2px; } `; diff --git a/web/packages/shared/components/DialogBox/index.tsx b/web/packages/shared/components/DialogBox/index.tsx index 14d2c8e4c4..e02db2fda8 100644 --- a/web/packages/shared/components/DialogBox/index.tsx +++ b/web/packages/shared/components/DialogBox/index.tsx @@ -5,9 +5,10 @@ import { DialogContent, DialogProps, Typography, + type ButtonBaseActions, } from "@mui/material"; import { t } from "i18next"; -import React from "react"; +import React, { useRef } from "react"; import DialogIcon from "./DialogIcon"; import DialogTitleWithCloseButton, { dialogCloseHandler, @@ -33,6 +34,21 @@ export default function DialogBox({ titleCloseButton, ...props }: IProps) { + // Sometimes we wish to autoFocus on the primary action button in the dialog + // (e.g. in the delete confirmation) so that the user can use their keyboard + // to quickly select it. + // + // To allow this, MUI buttons provide an `autoFocus` prop. However, while + // the button does get auto focused, it doesn't show the visual + // focus-visible state until the user does an keyboard action. + // + // Below is the current best workaround to get the focused button to also + // show the focus-visible state. It uses the onEnter callback of the + // transition to focus on the ref to the auto focused button (if any). + // + // https://github.com/mui/material-ui/issues/8438 + const proceedButtonRef = useRef(null); + if (!attributes) { return <>; } @@ -43,11 +59,17 @@ export default function DialogBox({ onClose: onClose, }); + const handleDialogEnter = () => { + if (attributes.proceed.autoFocus) + proceedButtonRef?.current.focusVisible(); + }; + return ( {attributes.icon && } @@ -87,6 +109,7 @@ export default function DialogBox({ )} {attributes.proceed && ( {