diff --git a/package.json b/package.json index 78c980805..36ab7086e 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ }, { "path": "./build/releases/OneSignalSDK.page.es6.js", - "limit": "42.65 kB", + "limit": "42.7 kB", "gzip": true }, { diff --git a/src/page/bell/Bell.test.ts b/src/page/bell/Bell.test.ts index 39f850f19..6bb2f7092 100644 --- a/src/page/bell/Bell.test.ts +++ b/src/page/bell/Bell.test.ts @@ -156,6 +156,36 @@ describe('Bell', () => { ); } + test('launcher button has a default accessible name', async () => { + mockCreateDeps(); + const bell = new Bell({ enable: true, showLauncherAfter: 0 }); + await bell._create(); + + expect(bell._button._element!.getAttribute('aria-label')).toBe('Manage notifications'); + }); + + test('launcher button accessible name is configurable via text', async () => { + mockCreateDeps(); + const bell = new Bell({ + enable: true, + showLauncherAfter: 0, + // @ts-expect-error - partial text config + text: { 'launcher.button.aria-label': 'Notification preferences' }, + }); + await bell._create(); + + expect(bell._button._element!.getAttribute('aria-label')).toBe('Notification preferences'); + }); + + test('bell svg is hidden from the accessibility tree', async () => { + mockCreateDeps(); + const bell = new Bell({ enable: true, showLauncherAfter: 0 }); + await bell._create(); + + const svg = bell._button._element!.querySelector('svg')!; + expect(svg.getAttribute('aria-hidden')).toBe('true'); + }); + test('mouseleave on launcher blurs the button', async () => { mockCreateDeps(); const bell = new Bell({ enable: true, showLauncherAfter: 0 }); diff --git a/src/page/bell/Bell.ts b/src/page/bell/Bell.ts index 57b485bd8..4efd2e194 100755 --- a/src/page/bell/Bell.ts +++ b/src/page/bell/Bell.ts @@ -21,7 +21,7 @@ import Dialog from './Dialog'; import Launcher from './Launcher'; import Message from './Message'; -const logoSvg = ``; +const logoSvg = ``; const DEFAULT_SIZE: BellSize = 'medium'; const DEFAULT_POSITION: BellPosition = 'bottom-right'; @@ -31,7 +31,10 @@ const VALID_SIZES: readonly string[] = ['small', 'medium', 'large']; const VALID_POSITIONS: readonly string[] = ['bottom-left', 'bottom-right']; const VALID_THEMES: readonly string[] = ['default', 'inverse']; +const DEFAULT_LAUNCHER_LABEL = 'Manage notifications'; + const DEFAULT_TEXT: BellText = { + 'launcher.button.aria-label': DEFAULT_LAUNCHER_LABEL, 'tip.state.unsubscribed': 'Subscribe to notifications', 'tip.state.subscribed': "You're subscribed to notifications", 'tip.state.blocked': "You've blocked notifications", @@ -213,6 +216,10 @@ export default class Bell { 'beforeend', '', ); + this._button._element?.setAttribute( + 'aria-label', + this._options.text['launcher.button.aria-label'] || DEFAULT_LAUNCHER_LABEL, + ); addDomElement( this._launcher._selector, 'beforeend', diff --git a/src/page/bell/Message.ts b/src/page/bell/Message.ts index d1491beb5..d0a80d806 100755 --- a/src/page/bell/Message.ts +++ b/src/page/bell/Message.ts @@ -64,6 +64,6 @@ export default class Message { _getTipForState(): string { const key = TIP_KEYS[this._bell._state]; - return key ? this._bell._options.text[key] : ''; + return key ? (this._bell._options.text[key] ?? '') : ''; } } diff --git a/src/shared/prompts/types.ts b/src/shared/prompts/types.ts index ca095a72a..d1404ca01 100644 --- a/src/shared/prompts/types.ts +++ b/src/shared/prompts/types.ts @@ -116,6 +116,7 @@ export type BellSize = 'small' | 'medium' | 'large'; export type BellPosition = 'bottom-left' | 'bottom-right'; export interface BellText { + 'launcher.button.aria-label'?: string; 'tip.state.unsubscribed': string; 'tip.state.subscribed': string; 'tip.state.blocked': string;