♿️(frontend) fix more options menu feedback for screen readers
Pin/unpin: vocal announce only. Duplicate, copy: toast only.
This commit is contained in:
@@ -10,6 +10,7 @@ and this project adheres to
|
||||
|
||||
- 💫(frontend) fix the help button to the bottom in tree #2073
|
||||
- ♿️(frontend) improve version history list accessibility #2033
|
||||
- ♿️(frontend) fix more options menu feedback for screen readers #2071
|
||||
|
||||
## [v4.8.2] - 2026-03-19
|
||||
|
||||
|
||||
@@ -474,7 +474,9 @@ test.describe('Doc Header', () => {
|
||||
// Copy content to clipboard
|
||||
await page.getByLabel('Open the document options').click();
|
||||
await getMenuItem(page, 'Copy as Markdown').click();
|
||||
await expect(page.getByText('Copied to clipboard')).toBeVisible();
|
||||
await expect(
|
||||
page.getByText('Copied as Markdown to clipboard'),
|
||||
).toBeVisible();
|
||||
|
||||
// Test that clipboard is in Markdown format
|
||||
const handle = await page.evaluateHandle(() =>
|
||||
|
||||
+14
-3
@@ -13,7 +13,8 @@ export const useCopyCurrentEditorToClipboard = () => {
|
||||
|
||||
return async (asFormat: 'html' | 'markdown') => {
|
||||
if (!editor) {
|
||||
toast(t('Editor unavailable'), VariantType.ERROR, { duration: 3000 });
|
||||
const message = t('Editor unavailable');
|
||||
toast(message, VariantType.ERROR, { duration: 3000 });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -23,10 +24,20 @@ export const useCopyCurrentEditorToClipboard = () => {
|
||||
? await editor.blocksToHTMLLossy()
|
||||
: await editor.blocksToMarkdownLossy();
|
||||
await navigator.clipboard.writeText(editorContentFormatted);
|
||||
toast(t('Copied to clipboard'), VariantType.SUCCESS, { duration: 3000 });
|
||||
const successMessage =
|
||||
asFormat === 'markdown'
|
||||
? t('Copied as Markdown to clipboard')
|
||||
: t('Copied to clipboard');
|
||||
|
||||
toast(successMessage, VariantType.SUCCESS, { duration: 3000 });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
toast(t('Failed to copy to clipboard'), VariantType.ERROR, {
|
||||
const errorMessage =
|
||||
asFormat === 'markdown'
|
||||
? t('Failed to copy as Markdown to clipboard')
|
||||
: t('Failed to copy to clipboard');
|
||||
|
||||
toast(errorMessage, VariantType.ERROR, {
|
||||
duration: 3000,
|
||||
});
|
||||
}
|
||||
|
||||
+12
@@ -1,4 +1,6 @@
|
||||
import { announce } from '@react-aria/live-announcer';
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { APIError, errorCauses, fetchAPI } from '@/api';
|
||||
|
||||
@@ -29,6 +31,8 @@ export function useCreateFavoriteDoc({
|
||||
listInvalidQueries,
|
||||
}: CreateFavoriteDocProps) {
|
||||
const queryClient = useQueryClient();
|
||||
const { t } = useTranslation();
|
||||
|
||||
return useMutation<void, APIError, CreateFavoriteDocParams>({
|
||||
mutationFn: createFavoriteDoc,
|
||||
onSuccess: () => {
|
||||
@@ -37,7 +41,15 @@ export function useCreateFavoriteDoc({
|
||||
queryKey: [queryKey],
|
||||
});
|
||||
});
|
||||
|
||||
const message = t('Document pinned successfully!');
|
||||
announce(message, 'polite');
|
||||
|
||||
onSuccess?.();
|
||||
},
|
||||
onError: () => {
|
||||
const message = t('Failed to pin the document.');
|
||||
announce(message, 'assertive');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
+12
@@ -1,4 +1,6 @@
|
||||
import { announce } from '@react-aria/live-announcer';
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { APIError, errorCauses, fetchAPI } from '@/api';
|
||||
|
||||
@@ -29,6 +31,8 @@ export function useDeleteFavoriteDoc({
|
||||
listInvalidQueries,
|
||||
}: DeleteFavoriteDocProps) {
|
||||
const queryClient = useQueryClient();
|
||||
const { t } = useTranslation();
|
||||
|
||||
return useMutation<void, APIError, DeleteFavoriteDocParams>({
|
||||
mutationFn: deleteFavoriteDoc,
|
||||
onSuccess: () => {
|
||||
@@ -37,7 +41,15 @@ export function useDeleteFavoriteDoc({
|
||||
queryKey: [queryKey],
|
||||
});
|
||||
});
|
||||
|
||||
const message = t('Document unpinned successfully!');
|
||||
announce(message, 'polite');
|
||||
|
||||
onSuccess?.();
|
||||
},
|
||||
onError: () => {
|
||||
const message = t('Failed to unpin the document.');
|
||||
announce(message, 'assertive');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -88,14 +88,16 @@ export function useDuplicateDoc(options?: DuplicateDocOptions) {
|
||||
queryKey: [KEY_LIST_DOC],
|
||||
});
|
||||
|
||||
toast(t('Document duplicated successfully!'), VariantType.SUCCESS, {
|
||||
const message = t('Document duplicated successfully!');
|
||||
toast(message, VariantType.SUCCESS, {
|
||||
duration: 3000,
|
||||
});
|
||||
|
||||
void options?.onSuccess?.(data, variables, onMutateResult, context);
|
||||
},
|
||||
onError: (error, variables, onMutateResult, context) => {
|
||||
toast(t('Failed to duplicate the document...'), VariantType.ERROR, {
|
||||
const message = t('Failed to duplicate the document...');
|
||||
toast(message, VariantType.ERROR, {
|
||||
duration: 3000,
|
||||
});
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ import {
|
||||
VariantType,
|
||||
useToastProvider,
|
||||
} from '@gouvfr-lasuite/cunningham-react';
|
||||
import { announce } from '@react-aria/live-announcer';
|
||||
import { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
@@ -19,14 +18,12 @@ export const useClipboard = () => {
|
||||
toast(message, VariantType.SUCCESS, {
|
||||
duration: 3000,
|
||||
});
|
||||
announce(message, 'polite');
|
||||
})
|
||||
.catch(() => {
|
||||
const message = errorMessage ?? t('Failed to copy to clipboard');
|
||||
toast(message, VariantType.ERROR, {
|
||||
duration: 3000,
|
||||
});
|
||||
announce(message, 'assertive');
|
||||
});
|
||||
},
|
||||
[t, toast],
|
||||
|
||||
Reference in New Issue
Block a user