Skip to content

Commit e9cde2a

Browse files
committed
♿️(frontend) improve the accessibility of the upload loader block
The loader used Card, adding an unnamed region per upload, and neither the analysis start nor the antivirus warning was announced. Use Box again, announce both through announce(), hide the decorative warning icon and keep upload error toasts 10s so the cause can be read.
1 parent aff00ca commit e9cde2a

4 files changed

Lines changed: 32 additions & 9 deletions

File tree

‎src/frontend/apps/impress/src/features/docs/doc-editor/assets/warning.svg‎

Lines changed: 1 addition & 0 deletions
Loading

‎src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-blocks/UploadLoaderBlock.tsx‎

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ import {
66
StyleSchema,
77
} from '@blocknote/core';
88
import { createReactBlockSpec } from '@blocknote/react';
9+
import { announce } from '@react-aria/live-announcer';
910
import { t } from 'i18next';
1011
import { useEffect } from 'react';
1112

12-
import { Card, Icon, Text } from '@/components';
13+
import { Box, Icon, Text } from '@/components';
1314
import { useMediaUrl } from '@/core';
1415
import { isSafeUrl } from '@/utils/url';
1516

@@ -114,16 +115,19 @@ const UploadLoaderBlockComponent = ({
114115

115116
console.error('Error analyzing file:', error);
116117

118+
const information = t(
119+
'The antivirus has detected an anomaly in your file.',
120+
);
121+
117122
try {
118123
editor.updateBlock(block.id, {
119124
type: 'uploadLoader',
120125
props: {
121126
type: 'warning',
122-
information: t(
123-
'The antivirus has detected an anomaly in your file.',
124-
),
127+
information,
125128
},
126129
});
130+
announce(information, 'assertive');
127131
} catch {
128132
/* During collaboration, another user might have updated the block */
129133
}
@@ -135,14 +139,16 @@ const UploadLoaderBlockComponent = ({
135139
}, [block, editor, mediaUrl, isEditable]);
136140

137141
return (
138-
<Card
142+
<Box
139143
className="bn-visual-media-wrapper"
140144
$direction="row"
141145
$gap="xs"
142146
$withThemeBG
143147
$border="none"
148+
$radius="var(--c--globals--spacings--st)"
144149
$theme="neutral"
145150
$scope="semantic"
151+
$variation="tertiary"
146152
$width="100%"
147153
$padding="xs"
148154
>
@@ -158,7 +164,7 @@ const UploadLoaderBlockComponent = ({
158164
<Text $variation="tertiary" $weight={500}>
159165
{block.props.information}
160166
</Text>
161-
</Card>
167+
</Box>
162168
);
163169
};
164170

‎src/frontend/apps/impress/src/features/docs/doc-editor/hook/__tests__/useUploadFile.test.tsx‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ describe('useUploadFile', () => {
6969
expect(mockToast).toHaveBeenCalledWith(
7070
'The file "video.mp4" is too large. Maximum file size is 1KB.',
7171
'error',
72+
{ duration: 10000 },
7273
);
7374
});
7475

@@ -89,6 +90,7 @@ describe('useUploadFile', () => {
8990
expect(mockToast).toHaveBeenCalledWith(
9091
'A problem occurred while uploading the file, cause: File type not allowed.',
9192
'error',
93+
{ duration: 10000 },
9294
);
9395
});
9496
});

‎src/frontend/apps/impress/src/features/docs/doc-editor/hook/useUploadFile.tsx‎

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Block } from '@blocknote/core';
22
import { VariantType } from '@gouvfr-lasuite/ui-components';
3+
import { announce } from '@react-aria/live-announcer';
34
import { captureException } from '@sentry/nextjs';
45
import { useCallback, useEffect } from 'react';
56
import { useTranslation } from 'react-i18next';
@@ -16,6 +17,9 @@ import { DocsBlockNoteEditor } from '../types';
1617

1718
const DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024; // Default to 10MB
1819

20+
// Upload errors carry a cause the user has to read: keep them longer than the default toast.
21+
const UPLOAD_ERROR_TOAST_DURATION = 10000;
22+
1923
const TEXT_ALIGNMENTS = ['left', 'center', 'right', 'justify'] as const;
2024

2125
type TextAlignment = (typeof TEXT_ALIGNMENTS)[number];
@@ -63,6 +67,7 @@ export const useUploadFile = (docId: string) => {
6367
},
6468
),
6569
VariantType.ERROR,
70+
{ duration: UPLOAD_ERROR_TOAST_DURATION },
6671
);
6772

6873
throw new Error('File is too large');
@@ -88,6 +93,7 @@ export const useUploadFile = (docId: string) => {
8893
'A problem occurred while uploading the file, please try again.',
8994
),
9095
VariantType.ERROR,
96+
{ duration: UPLOAD_ERROR_TOAST_DURATION },
9197
);
9298

9399
throw error;
@@ -114,7 +120,7 @@ export const useUploadStatus = (editor: DocsBlockNoteEditor) => {
114120
* Replace the resource block by a uploadLoader block to show analyzing status
115121
*/
116122
const replaceBlockWithUploadLoader = useCallback(
117-
(block: Block) => {
123+
(block: Block, shouldAnnounce = false) => {
118124
if (
119125
!block ||
120126
!('url' in block.props) ||
@@ -133,13 +139,15 @@ export const useUploadStatus = (editor: DocsBlockNoteEditor) => {
133139
const blockUploadTextAlignment = fileTextAlignment(block.props);
134140

135141
try {
142+
const information = t('Analyzing the file');
143+
136144
editor.replaceBlocks(
137145
[block.id],
138146
[
139147
{
140148
type: 'uploadLoader',
141149
props: {
142-
information: t('Analyzing the file'),
150+
information,
143151
type: 'loading',
144152
blockUploadName,
145153
blockUploadType,
@@ -151,6 +159,12 @@ export const useUploadStatus = (editor: DocsBlockNoteEditor) => {
151159
},
152160
],
153161
);
162+
163+
// Only the user who uploaded the file hears it, not the collaborators
164+
// nor a page reload.
165+
if (shouldAnnounce) {
166+
announce(information, 'polite');
167+
}
154168
} catch (error) {
155169
captureException(error, {
156170
extra: { info: 'Error replacing block for upload loader' },
@@ -194,7 +208,7 @@ export const useUploadStatus = (editor: DocsBlockNoteEditor) => {
194208
const innerTimeoutId = setTimeout(() => {
195209
const block = editor.getBlock({ id: blockId });
196210

197-
replaceBlockWithUploadLoader(block as Block);
211+
replaceBlockWithUploadLoader(block as Block, true);
198212
}, 300);
199213

200214
return () => {

0 commit comments

Comments
 (0)