Skip to content

Commit

Permalink
RAC and S2 Pending Button (adobe#7002)
Browse files Browse the repository at this point in the history
RAC and S2 Pending Button
  • Loading branch information
snowystinger committed Sep 19, 2024
1 parent 25c9d16 commit 988b4d4
Show file tree
Hide file tree
Showing 51 changed files with 638 additions and 76 deletions.
5 changes: 4 additions & 1 deletion packages/@react-aria/dnd/src/DragManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,10 @@ class DragSession {
// Announce first drop target after drag start announcement finishes.
// Otherwise, it will never get announced because drag start announcement is assertive.
if (!this.initialFocused) {
announce(item?.element.getAttribute('aria-label'), 'polite');
let label = item?.element.getAttribute('aria-label');
if (label) {
announce(label, 'polite');
}
this.initialFocused = true;
}
}
Expand Down
101 changes: 66 additions & 35 deletions packages/@react-aria/live-announcer/src/LiveAnnouncer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,38 @@ const LIVEREGION_TIMEOUT_DELAY = 7000;

let liveAnnouncer: LiveAnnouncer | null = null;

type Message = string | {'aria-labelledby': string};

/**
* Announces the message using screen reader technology.
*/
export function announce(
message: string,
message: Message,
assertiveness: Assertiveness = 'assertive',
timeout = LIVEREGION_TIMEOUT_DELAY
) {
if (!liveAnnouncer) {
liveAnnouncer = new LiveAnnouncer();
// wait for the live announcer regions to be added to the dom, then announce
// otherwise Safari won't announce the message if it's added too quickly
// found most times less than 100ms were not consistent when announcing with Safari

// IS_REACT_ACT_ENVIRONMENT is used by React 18. Previous versions checked for the `jest` global.
// https://github.com/reactwg/react-18/discussions/102
// if we're in a test environment, announce without waiting
// @ts-ignore
if (!(typeof IS_REACT_ACT_ENVIRONMENT === 'boolean' ? IS_REACT_ACT_ENVIRONMENT : typeof jest !== 'undefined')) {
setTimeout(() => {
if (liveAnnouncer?.isAttached()) {
liveAnnouncer?.announce(message, assertiveness, timeout);
}
}, 100);
} else {
liveAnnouncer.announce(message, assertiveness, timeout);
}
} else {
liveAnnouncer.announce(message, assertiveness, timeout);
}

liveAnnouncer.announce(message, assertiveness, timeout);
}

/**
Expand Down Expand Up @@ -58,34 +77,40 @@ export function destroyAnnouncer() {
// is simple enough to implement without React, so that's what we do here.
// See this discussion for more details: https://github.com/reactwg/react-18/discussions/125#discussioncomment-2382638
class LiveAnnouncer {
node: HTMLElement | null;
assertiveLog: HTMLElement;
politeLog: HTMLElement;
node: HTMLElement | null = null;
assertiveLog: HTMLElement | null = null;
politeLog: HTMLElement | null = null;

constructor() {
this.node = document.createElement('div');
this.node.dataset.liveAnnouncer = 'true';
// copied from VisuallyHidden
Object.assign(this.node.style, {
border: 0,
clip: 'rect(0 0 0 0)',
clipPath: 'inset(50%)',
height: '1px',
margin: '-1px',
overflow: 'hidden',
padding: 0,
position: 'absolute',
width: '1px',
whiteSpace: 'nowrap'
});

this.assertiveLog = this.createLog('assertive');
this.node.appendChild(this.assertiveLog);

this.politeLog = this.createLog('polite');
this.node.appendChild(this.politeLog);

document.body.prepend(this.node);
if (typeof document !== 'undefined') {
this.node = document.createElement('div');
this.node.dataset.liveAnnouncer = 'true';
// copied from VisuallyHidden
Object.assign(this.node.style, {
border: 0,
clip: 'rect(0 0 0 0)',
clipPath: 'inset(50%)',
height: '1px',
margin: '-1px',
overflow: 'hidden',
padding: 0,
position: 'absolute',
width: '1px',
whiteSpace: 'nowrap'
});

this.assertiveLog = this.createLog('assertive');
this.node.appendChild(this.assertiveLog);

this.politeLog = this.createLog('polite');
this.node.appendChild(this.politeLog);

document.body.prepend(this.node);
}
}

isAttached() {
return this.node?.isConnected;
}

createLog(ariaLive: string) {
Expand All @@ -105,18 +130,24 @@ class LiveAnnouncer {
this.node = null;
}

announce(message: string, assertiveness = 'assertive', timeout = LIVEREGION_TIMEOUT_DELAY) {
announce(message: Message, assertiveness = 'assertive', timeout = LIVEREGION_TIMEOUT_DELAY) {
if (!this.node) {
return;
}

let node = document.createElement('div');
node.textContent = message;
if (typeof message === 'object') {
// To read an aria-labelledby, the element must have an appropriate role, such as img.
node.setAttribute('role', 'img');
node.setAttribute('aria-labelledby', message['aria-labelledby']);
} else {
node.textContent = message;
}

if (assertiveness === 'assertive') {
this.assertiveLog.appendChild(node);
this.assertiveLog?.appendChild(node);
} else {
this.politeLog.appendChild(node);
this.politeLog?.appendChild(node);
}

if (message !== '') {
Expand All @@ -131,11 +162,11 @@ class LiveAnnouncer {
return;
}

if (!assertiveness || assertiveness === 'assertive') {
if ((!assertiveness || assertiveness === 'assertive') && this.assertiveLog) {
this.assertiveLog.innerHTML = '';
}

if (!assertiveness || assertiveness === 'polite') {
if ((!assertiveness || assertiveness === 'polite') && this.politeLog) {
this.politeLog.innerHTML = '';
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*/

jest.mock('@react-aria/live-announcer');
import {act, fireEvent, pointerMap, render, screen, simulateDesktop, simulateMobile, waitFor, within} from '@react-spectrum/test-utils-internal';
import {act, fireEvent, pointerMap, render, simulateDesktop, simulateMobile, waitFor, within} from '@react-spectrum/test-utils-internal';
import {announce} from '@react-aria/live-announcer';
import {Button} from '@react-spectrum/button';
import Filter from '@spectrum-icons/workflow/Filter';
Expand Down Expand Up @@ -3228,7 +3228,9 @@ describe('SearchAutocomplete', function () {

let listbox = getByRole('listbox');
expect(listbox).toBeVisible();
expect(screen.getAllByRole('log')).toHaveLength(2);
expect(announce).toHaveBeenCalledTimes(2);
expect(announce).toHaveBeenNthCalledWith(1, '3 options available.');
expect(announce).toHaveBeenNthCalledWith(2, 'One');
platformMock.mockRestore();
});

Expand Down
8 changes: 4 additions & 4 deletions packages/@react-spectrum/color/test/ColorPicker.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ describe('ColorPicker', function () {

let button = getByRole('button');
expect(button).toHaveTextContent('Fill');
expect(within(button).getByRole('img')).toHaveAttribute('aria-label', 'vibrant red');
expect(within(button).getByLabelText('vibrant red')).toBeInTheDocument();

await user.click(button);

Expand All @@ -67,7 +67,7 @@ describe('ColorPicker', function () {
act(() => dialog.focus());
await user.keyboard('{Escape}');
act(() => {jest.runAllTimers();});
expect(within(button).getByRole('img')).toHaveAttribute('aria-label', 'dark vibrant blue');
expect(within(button).getByLabelText('dark vibrant blue')).toBeInTheDocument();
});

it('should have default value of black', async function () {
Expand All @@ -81,7 +81,7 @@ describe('ColorPicker', function () {

let button = getByRole('button');
expect(button).toHaveTextContent('Fill');
expect(within(button).getByRole('img')).toHaveAttribute('aria-label', 'black');
expect(within(button).getByLabelText('black')).toBeInTheDocument();

await user.click(button);

Expand Down Expand Up @@ -132,6 +132,6 @@ describe('ColorPicker', function () {
act(() => getByRole('dialog').focus());
await user.keyboard('{Escape}');
act(() => {jest.runAllTimers();});
expect(within(button).getByRole('img')).toHaveAttribute('aria-label', 'vibrant orange');
expect(within(button).getByLabelText('vibrant orange')).toBeInTheDocument();
});
});
6 changes: 4 additions & 2 deletions packages/@react-spectrum/combobox/test/ComboBox.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*/

jest.mock('@react-aria/live-announcer');
import {act, fireEvent, pointerMap, render, screen, simulateDesktop, simulateMobile, waitFor, within} from '@react-spectrum/test-utils-internal';
import {act, fireEvent, pointerMap, render, simulateDesktop, simulateMobile, waitFor, within} from '@react-spectrum/test-utils-internal';
import {announce} from '@react-aria/live-announcer';
import {Button} from '@react-spectrum/button';
import {chain} from '@react-aria/utils';
Expand Down Expand Up @@ -5149,7 +5149,9 @@ describe('ComboBox', function () {

let listbox = getByRole('listbox');
expect(listbox).toBeVisible();
expect(screen.getAllByRole('log')).toHaveLength(2);
expect(announce).toHaveBeenCalledTimes(2);
expect(announce).toHaveBeenNthCalledWith(1, '3 options available.');
expect(announce).toHaveBeenNthCalledWith(2, 'One');
platformMock.mockRestore();
});

Expand Down
5 changes: 1 addition & 4 deletions packages/@react-spectrum/provider/test/Provider.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,10 @@
* governing permissions and limitations under the License.
*/

// needs to be imported first
// eslint-disable-next-line
import MatchMediaMock from 'jest-matchmedia-mock';
// eslint-disable-next-line rsp-rules/sort-imports
import {act, fireEvent, pointerMap, render} from '@react-spectrum/test-utils-internal';
import {ActionButton, Button} from '@react-spectrum/button';
import {Checkbox} from '@react-spectrum/checkbox';
import MatchMediaMock from 'jest-matchmedia-mock';
import {Provider} from '../';
// eslint-disable-next-line rulesdir/useLayoutEffectRule
import React, {useLayoutEffect, useRef} from 'react';
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/ar-AE.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "قيد الانتظار",
"contextualhelp.help": "مساعدة",
"contextualhelp.info": "معلومات",
"dialog.alert": "تنبيه",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/bg-BG.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "недовършено",
"contextualhelp.help": "Помощ",
"contextualhelp.info": "Информация",
"dialog.alert": "Сигнал",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/cs-CZ.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "čeká na vyřízení",
"contextualhelp.help": "Nápověda",
"contextualhelp.info": "Informace",
"dialog.alert": "Výstraha",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/da-DK.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "afventende",
"contextualhelp.help": "Hjælp",
"contextualhelp.info": "Oplysninger",
"dialog.alert": "Advarsel",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/de-DE.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "Ausstehend",
"contextualhelp.help": "Hilfe",
"contextualhelp.info": "Informationen",
"dialog.alert": "Warnhinweis",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/el-GR.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "σε εκκρεμότητα",
"contextualhelp.help": "Βοήθεια",
"contextualhelp.info": "Πληροφορίες",
"dialog.alert": "Ειδοποίηση",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/en-US.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "pending",
"contextualhelp.info": "Information",
"contextualhelp.help": "Help",
"dialog.dismiss": "Dismiss",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/es-ES.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "pendiente",
"contextualhelp.help": "Ayuda",
"contextualhelp.info": "Información",
"dialog.alert": "Alerta",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/et-EE.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "ootel",
"contextualhelp.help": "Spikker",
"contextualhelp.info": "Teave",
"dialog.alert": "Teade",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/fi-FI.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "odottaa",
"contextualhelp.help": "Ohje",
"contextualhelp.info": "Tiedot",
"dialog.alert": "Hälytys",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/fr-FR.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "En attente",
"contextualhelp.help": "Aide",
"contextualhelp.info": "Informations",
"dialog.alert": "Alerte",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/he-IL.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "ממתין ל",
"contextualhelp.help": "עזרה",
"contextualhelp.info": "מידע",
"dialog.alert": "התראה",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/hr-HR.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "u tijeku",
"contextualhelp.help": "Pomoć",
"contextualhelp.info": "Informacije",
"dialog.alert": "Upozorenje",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/hu-HU.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "függőben levő",
"contextualhelp.help": "Súgó",
"contextualhelp.info": "Információ",
"dialog.alert": "Figyelmeztetés",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/it-IT.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "in sospeso",
"contextualhelp.help": "Aiuto",
"contextualhelp.info": "Informazioni",
"dialog.alert": "Avviso",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/ja-JP.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "保留",
"contextualhelp.help": "ヘルプ",
"contextualhelp.info": "情報",
"dialog.alert": "アラート",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/ko-KR.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "보류 중",
"contextualhelp.help": "도움말",
"contextualhelp.info": "정보",
"dialog.alert": "경고",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/lt-LT.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "laukiama",
"contextualhelp.help": "Žinynas",
"contextualhelp.info": "Informacija",
"dialog.alert": "Įspėjimas",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/lv-LV.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "gaida",
"contextualhelp.help": "Palīdzība",
"contextualhelp.info": "Informācija",
"dialog.alert": "Brīdinājums",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/nb-NO.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "avventer",
"contextualhelp.help": "Hjelp",
"contextualhelp.info": "Informasjon",
"dialog.alert": "Varsel",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/nl-NL.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "in behandeling",
"contextualhelp.help": "Help",
"contextualhelp.info": "Informatie",
"dialog.alert": "Melding",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/pl-PL.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "oczekujące",
"contextualhelp.help": "Pomoc",
"contextualhelp.info": "Informacja",
"dialog.alert": "Ostrzeżenie",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/pt-BR.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "pendente",
"contextualhelp.help": "Ajuda",
"contextualhelp.info": "Informações",
"dialog.alert": "Alerta",
Expand Down
1 change: 1 addition & 0 deletions packages/@react-spectrum/s2/intl/pt-PT.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button.pending": "pendente",
"contextualhelp.help": "Ajuda",
"contextualhelp.info": "Informação",
"dialog.alert": "Alerta",
Expand Down
Loading

0 comments on commit 988b4d4

Please sign in to comment.