From 25cf11c90f18c6f12e340f3ead250a54122e9d2c Mon Sep 17 00:00:00 2001 From: Cyril Date: Wed, 4 Mar 2026 10:05:56 +0100 Subject: [PATCH] =?UTF-8?q?=E2=99=BF=EF=B8=8F(frontend)=20add=20focus=20on?= =?UTF-8?q?=20open=20to=20modals?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use autoFocus on primary button when opening modals. Made-with: Cursor --- CHANGELOG.md | 1 + .../app-impress/doc-grid-move.spec.ts | 4 +++- .../ModalConfirmDownloadUnsafe.tsx | 1 + .../doc-export/components/ModalExport.tsx | 1 + .../doc-header/components/AlertNetwork.tsx | 7 ++++++- .../components/ModalRemoveDoc.tsx | 19 +++++++++---------- .../components/ModalConfirmationVersion.tsx | 1 + .../components/ModalSelectVersion.tsx | 1 + 8 files changed, 23 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b78304a5..4f811c24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ and this project adheres to - 🚸(backend) sort user search results by proximity with the active user #1802 - 🚸(oidc) ignore case when fallback on email #1880 - ⚡️(CI) optimize Docker Hub workflow #1919 +- ♿️(frontend) add focus on open to modals #1948 ### Fixed diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-grid-move.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-grid-move.spec.ts index d8bb732f..09d157ec 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-grid-move.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-grid-move.spec.ts @@ -380,7 +380,9 @@ test.describe('Doc grid move', () => { await verifyDocName(page, titleDoc2); const docTree = page.getByTestId('doc-tree'); - await expect(docTree.getByText(titleDoc1)).toBeVisible(); + await expect(docTree.getByText(titleDoc1)).toBeVisible({ + timeout: 15000, + }); await cleanup(); }); diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteToolBar/ModalConfirmDownloadUnsafe.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteToolBar/ModalConfirmDownloadUnsafe.tsx index 9ac38b9f..1998ad83 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteToolBar/ModalConfirmDownloadUnsafe.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteToolBar/ModalConfirmDownloadUnsafe.tsx @@ -24,6 +24,7 @@ export const ModalConfirmDownloadUnsafe = ({ <> diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/components/ModalRemoveDoc.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/components/ModalRemoveDoc.tsx index 7b8d283b..fe5063ee 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/components/ModalRemoveDoc.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-management/components/ModalRemoveDoc.tsx @@ -38,6 +38,7 @@ export const ModalRemoveDoc = ({ const { push } = useRouter(); const { hasChildren } = useDocUtils(doc); const cancelButtonRef = useRef(null); + const { mutate: removeDoc, isError, @@ -60,17 +61,14 @@ export const ModalRemoveDoc = ({ }, }, }); - + // react-aria Popover restores focus to its trigger asynchronously + // when closing, which races with autoFocus when the modal is opened + // from a dropdown. This ensures focus wins after that restoration. useEffect(() => { - const TIMEOUT_MODAL_MOUNTING = 100; - const timeoutId = setTimeout(() => { - const buttonElement = cancelButtonRef.current; - if (buttonElement) { - buttonElement.focus(); - } - }, TIMEOUT_MODAL_MOUNTING); - - return () => clearTimeout(timeoutId); + const id = requestAnimationFrame(() => { + cancelButtonRef.current?.focus(); + }); + return () => cancelAnimationFrame(id); }, []); const keyboardAction = useKeyboardAction(); @@ -100,6 +98,7 @@ export const ModalRemoveDoc = ({ aria-label={t('Cancel the deletion')} variant="secondary" fullWidth + autoFocus onClick={handleClose} onKeyDown={handleCloseKeyDown} > diff --git a/src/frontend/apps/impress/src/features/docs/doc-versioning/components/ModalConfirmationVersion.tsx b/src/frontend/apps/impress/src/features/docs/doc-versioning/components/ModalConfirmationVersion.tsx index 6d9a30e2..c5d3b1ae 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-versioning/components/ModalConfirmationVersion.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-versioning/components/ModalConfirmationVersion.tsx @@ -76,6 +76,7 @@ export const ModalConfirmationVersion = ({ aria-label={`${t('Cancel')} - ${t('Warning')}`} variant="secondary" fullWidth + autoFocus onClick={() => onClose()} > {t('Cancel')} diff --git a/src/frontend/apps/impress/src/features/docs/doc-versioning/components/ModalSelectVersion.tsx b/src/frontend/apps/impress/src/features/docs/doc-versioning/components/ModalSelectVersion.tsx index 39c4556e..7ac5dc57 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-versioning/components/ModalSelectVersion.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-versioning/components/ModalSelectVersion.tsx @@ -132,6 +132,7 @@ export const ModalSelectVersion = ({