mirror of
https://github.com/immich-app/immich.git
synced 2025-11-28 13:59:45 +09:00
feat(web): announce notifications to screen readers (#12071)
This commit is contained in:
@@ -39,6 +39,29 @@ describe('NotificationCard component', () => {
|
||||
expect(sut.getByTestId('message')).toHaveTextContent('Notification message');
|
||||
});
|
||||
|
||||
it('makes all buttons non-focusable and hidden from screen readers', () => {
|
||||
sut = render(NotificationCard, {
|
||||
notification: {
|
||||
id: 1234,
|
||||
message: 'Notification message',
|
||||
timeout: 1000,
|
||||
type: NotificationType.Info,
|
||||
action: { type: 'discard' },
|
||||
button: {
|
||||
text: 'button',
|
||||
onClick: vi.fn(),
|
||||
},
|
||||
},
|
||||
});
|
||||
const buttons = sut.container.querySelectorAll('button');
|
||||
|
||||
expect(buttons).toHaveLength(2);
|
||||
for (const button of buttons) {
|
||||
expect(button.getAttribute('tabindex')).toBe('-1');
|
||||
expect(button.getAttribute('aria-hidden')).toBe('true');
|
||||
}
|
||||
});
|
||||
|
||||
it('shows title and renders component', () => {
|
||||
sut = render(NotificationCard, {
|
||||
notification: {
|
||||
|
||||
@@ -9,8 +9,6 @@ function _getNotificationListElement(sut: RenderResult<NotificationList>): HTMLA
|
||||
}
|
||||
|
||||
describe('NotificationList component', () => {
|
||||
const sut: RenderResult<NotificationList> = render(NotificationList);
|
||||
|
||||
beforeAll(() => {
|
||||
// https://testing-library.com/docs/svelte-testing-library/faq#why-arent-transition-events-running
|
||||
vi.stubGlobal('requestAnimationFrame', (fn: FrameRequestCallback) => {
|
||||
@@ -23,6 +21,10 @@ describe('NotificationList component', () => {
|
||||
});
|
||||
|
||||
it('shows a notification when added and closes it automatically after the delay timeout', async () => {
|
||||
const sut: RenderResult<NotificationList> = render(NotificationList);
|
||||
const status = await sut.findAllByRole('status');
|
||||
|
||||
expect(status).toHaveLength(1);
|
||||
expect(_getNotificationListElement(sut)).not.toBeInTheDocument();
|
||||
|
||||
notificationController.show({
|
||||
|
||||
@@ -91,6 +91,8 @@
|
||||
size="20"
|
||||
padding="2"
|
||||
on:click={discard}
|
||||
aria-hidden="true"
|
||||
tabindex={-1}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -108,6 +110,8 @@
|
||||
type="button"
|
||||
class="{buttonStyle[notification.type]} rounded px-3 pt-1.5 pb-1 transition-all duration-200"
|
||||
on:click={handleButtonClick}
|
||||
aria-hidden="true"
|
||||
tabindex={-1}
|
||||
>
|
||||
{notification.button.text}
|
||||
</button>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { notificationController } from './notification';
|
||||
import { fade } from 'svelte/transition';
|
||||
|
||||
import { t } from 'svelte-i18n';
|
||||
import NotificationCard from './notification-card.svelte';
|
||||
import { flip } from 'svelte/animate';
|
||||
import { quintOut } from 'svelte/easing';
|
||||
@@ -9,12 +9,14 @@
|
||||
const { notificationList } = notificationController;
|
||||
</script>
|
||||
|
||||
{#if $notificationList.length > 0}
|
||||
<section transition:fade={{ duration: 250 }} id="notification-list" class="fixed right-5 top-[80px] z-[99999999]">
|
||||
{#each $notificationList as notification (notification.id)}
|
||||
<div animate:flip={{ duration: 250, easing: quintOut }}>
|
||||
<NotificationCard {notification} />
|
||||
</div>
|
||||
{/each}
|
||||
</section>
|
||||
{/if}
|
||||
<div role="status" aria-relevant="additions" aria-label={$t('notifications')}>
|
||||
{#if $notificationList.length > 0}
|
||||
<section transition:fade={{ duration: 250 }} id="notification-list" class="fixed right-5 top-[80px] z-[99999999]">
|
||||
{#each $notificationList as notification (notification.id)}
|
||||
<div animate:flip={{ duration: 250, easing: quintOut }}>
|
||||
<NotificationCard {notification} />
|
||||
</div>
|
||||
{/each}
|
||||
</section>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user