diff --git a/packages/blockly/core/toast.ts b/packages/blockly/core/toast.ts index 72559279f57..12ffbb0d05d 100644 --- a/packages/blockly/core/toast.ts +++ b/packages/blockly/core/toast.ts @@ -45,7 +45,7 @@ export interface ToastOptions { * How prominently/interrupting the readout of the toast should be for * screenreaders. Corresponds to aria-live and defaults to polite. */ - assertiveness?: Toast.Assertiveness; + assertiveness?: aria.LiveRegionAssertiveness; } /** @@ -89,15 +89,13 @@ export class Toast { const { message, duration = 5, - assertiveness = Toast.Assertiveness.POLITE, + assertiveness = aria.LiveRegionAssertiveness.POLITE, } = options; const toast = document.createElement('div'); workspace.getInjectionDiv().appendChild(toast); toast.dataset.toastId = options.id; toast.className = CLASS_NAME; - aria.setRole(toast, aria.Role.STATUS); - aria.setState(toast, aria.State.LIVE, assertiveness); const messageElement = toast.appendChild(document.createElement('div')); messageElement.className = MESSAGE_CLASS_NAME; @@ -157,6 +155,11 @@ export class Toast { toast.addEventListener('mouseleave', setToastTimeout); setToastTimeout(); + aria.announceDynamicAriaState(message, { + assertiveness, + role: aria.Role.STATUS, + }); + return toast; } @@ -174,17 +177,6 @@ export class Toast { } } -/** - * Options for how aggressively toasts should be read out by screenreaders. - * Values correspond to those for aria-live. - */ -export namespace Toast { - export enum Assertiveness { - ASSERTIVE = 'assertive', - POLITE = 'polite', - } -} - Css.register(` .${CLASS_NAME} { font-size: 1.2rem; diff --git a/packages/blockly/tests/mocha/toast_test.js b/packages/blockly/tests/mocha/toast_test.js index afb7f7f6cb9..a1d03da94aa 100644 --- a/packages/blockly/tests/mocha/toast_test.js +++ b/packages/blockly/tests/mocha/toast_test.js @@ -14,6 +14,7 @@ suite('Toasts', function () { setup(function () { sharedTestSetup.call(this); this.workspace = Blockly.inject('blocklyDiv', {}); + this.liveRegion = document.getElementById('blocklyAriaAnnounce'); this.toastIsVisible = (message) => { const toast = this.workspace .getInjectionDiv() @@ -97,16 +98,20 @@ suite('Toasts', function () { clock.restore(); }); - test('default to polite assertiveness', function () { + test('toast announces message with status role and polite assertiveness', function () { const message = 'texas toast'; Blockly.Toast.show(this.workspace, {message, id: 'test'}); - const toast = this.workspace - .getInjectionDiv() - .querySelector('.blocklyToast'); + this.clock.tick(11); + + assert.include(this.liveRegion.textContent, message); assert.equal( - toast.getAttribute('aria-live'), - Blockly.Toast.Assertiveness.POLITE, + this.liveRegion.getAttribute('role'), + Blockly.utils.aria.Role.STATUS, + ); + assert.equal( + this.liveRegion.getAttribute('aria-live'), + Blockly.utils.aria.LiveRegionAssertiveness.POLITE, ); }); @@ -115,15 +120,26 @@ suite('Toasts', function () { Blockly.Toast.show(this.workspace, { message, id: 'test', - assertiveness: Blockly.Toast.Assertiveness.ASSERTIVE, + assertiveness: Blockly.utils.aria.LiveRegionAssertiveness.ASSERTIVE, }); + + this.clock.tick(11); + + assert.equal( + this.liveRegion.getAttribute('aria-live'), + Blockly.utils.aria.LiveRegionAssertiveness.ASSERTIVE, + ); + }); + + test('toast is not itself a live region', function () { + const message = 'texas toast'; + Blockly.Toast.show(this.workspace, {message, id: 'test'}); + const toast = this.workspace .getInjectionDiv() .querySelector('.blocklyToast'); - assert.equal( - toast.getAttribute('aria-live'), - Blockly.Toast.Assertiveness.ASSERTIVE, - ); + assert.isNull(toast.getAttribute('aria-live')); + assert.notEqual(toast.getAttribute('role'), Blockly.utils.aria.Role.STATUS); }); });