Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: use a11y-announcer in date-picker #3243

Merged
merged 1 commit into from
Jan 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion packages/date-picker/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
],
"dependencies": {
"@open-wc/dedupe-mixin": "^1.3.0",
"@polymer/iron-a11y-announcer": "^3.0.0",
"@polymer/iron-media-query": "^3.0.0",
"@polymer/polymer": "^3.2.0",
"@vaadin/button": "23.0.0-alpha2",
Expand Down
25 changes: 8 additions & 17 deletions packages/date-picker/src/vaadin-date-picker-overlay-content.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import '@polymer/iron-media-query/iron-media-query.js';
import '@vaadin/button/src/vaadin-button.js';
import './vaadin-month-calendar.js';
import './vaadin-infinite-scroller.js';
import { IronA11yAnnouncer } from '@polymer/iron-a11y-announcer/iron-a11y-announcer.js';
import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
import { announce } from '@vaadin/component-base/src/a11y-announcer.js';
import { timeOut } from '@vaadin/component-base/src/async.js';
import { Debouncer } from '@vaadin/component-base/src/debounce.js';
import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
Expand Down Expand Up @@ -350,34 +350,25 @@ class DatePickerOverlayContent extends ThemableMixin(DirMixin(PolymerElement)) {
this._closeYearScroller();
this._toggleAnimateClass(true);
setTouchAction(this.$.scrollers, 'pan-y');
IronA11yAnnouncer.requestAvailability();
}

announceFocusedDate() {
var focusedDate = this._currentlyFocusedDate();
var announce = [];
const focusedDate = this._currentlyFocusedDate();
let messages = [];
if (dateEquals(focusedDate, new Date())) {
announce.push(this.i18n.today);
messages.push(this.i18n.today);
}
announce = announce.concat([
messages = messages.concat([
this.i18n.weekdays[focusedDate.getDay()],
focusedDate.getDate(),
this.i18n.monthNames[focusedDate.getMonth()],
focusedDate.getFullYear()
]);
if (this.showWeekNumbers && this.i18n.firstDayOfWeek === 1) {
announce.push(this.i18n.week);
announce.push(getISOWeekNumber(focusedDate));
messages.push(this.i18n.week);
messages.push(getISOWeekNumber(focusedDate));
}
this.dispatchEvent(
new CustomEvent('iron-announce', {
bubbles: true,
composed: true,
detail: {
text: announce.join(' ')
}
})
);
announce(messages.join(' '));
}

/**
Expand Down
148 changes: 58 additions & 90 deletions packages/date-picker/test/wai-aria.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { expect } from '@esm-bundle/chai';
import { aTimeout, fixtureSync, isIOS, nextFrame } from '@vaadin/testing-helpers';
import { aTimeout, fixtureSync, nextFrame } from '@vaadin/testing-helpers';
import sinon from 'sinon';
import './not-animated-styles.js';
import '../src/vaadin-date-picker.js';
import { IronA11yAnnouncer } from '@polymer/iron-a11y-announcer/iron-a11y-announcer.js';
import { activateScroller, getDefaultI18n, open } from './common.js';
import { activateScroller, getDefaultI18n } from './common.js';

describe('WAI-ARIA', () => {
describe('date picker', () => {
Expand Down Expand Up @@ -263,114 +263,86 @@ describe('WAI-ARIA', () => {
});

describe('announcements', () => {
// NOTE: See <iron-a11y-announcer> API
let region;
let datepicker;

let clock;

afterEach(() => {
clock.restore();
});

beforeEach(() => {
datepicker = fixtureSync(`<vaadin-date-picker label="ariatest"></vaadin-date-picker>`);
region = document.querySelector('[aria-live]');
clock = sinon.useFakeTimers();
});

function waitForAnnounce(callback) {
const listener = (event) => {
document.body.removeEventListener('iron-announce', listener);
callback(event.detail.text);
};
document.body.addEventListener('iron-announce', listener);
}

it('should request availability from IronA11yAnnouncer', async () => {
const spy = sinon.spy(IronA11yAnnouncer, 'requestAvailability');
it('should announce focused date on open', () => {
datepicker._focusedDate = new Date(2016, 1, 1);
datepicker.open();
await nextFrame();
expect(spy.called).to.be.true;
});

it('should announce focused date on open', (done) => {
waitForAnnounce((text) => {
expect(text).to.equal('Monday 1 February 2016');
done();
});
clock.tick(200);

datepicker._focusedDate = new Date(2016, 1, 1);
datepicker.open();
expect(region.textContent).to.equal('Monday 1 February 2016');
});

it('should announce focused date changes when opened', (done) => {
it('should announce focused date changes when opened', () => {
datepicker.open();
datepicker._focusedDate = new Date(2016, 1, 2);

waitForAnnounce((text) => {
expect(text).to.equal('Tuesday 2 February 2016');
done();
});
clock.tick(200);

datepicker._focusedDate = new Date(2016, 1, 2);
expect(region.textContent).to.equal('Tuesday 2 February 2016');
});

it('should not announce focused date changes when closed', () => {
const announceSpy = sinon.spy();
document.body.addEventListener('iron-announce', announceSpy);

// Reset live region state
region.textContent = '';
datepicker._focusedDate = new Date(2016, 1, 2);

expect(announceSpy.called).to.be.false;
document.body.removeEventListener('iron-announce', announceSpy);
});
clock.tick(200);

it('should announce value on open', (done) => {
waitForAnnounce((text) => {
expect(text).to.equal('Monday 1 February 2016');
done();
});
expect(region.textContent).to.equal('');
});

it('should announce value on open', () => {
datepicker.value = '2016-02-01';
datepicker.open();
});

it('should announce initial position on open', (done) => {
waitForAnnounce((text) => {
expect(text).to.equal('Monday 1 February 2016');
done();
});
clock.tick(200);

expect(region.textContent).to.equal('Monday 1 February 2016');
});

it('should announce initial position on open', () => {
datepicker.initialPosition = '2016-02-01';
datepicker.open();
});

it('should announce today', (done) => {
waitForAnnounce((text) => {
expect(text.indexOf('Today')).to.equal(0);
done();
});
clock.tick(200);

expect(region.textContent).to.equal('Monday 1 February 2016');
});

it('should announce today', () => {
datepicker.open();

clock.tick(200);

expect(region.textContent.indexOf('Today')).to.equal(0);
});

it('should announce week numbers if enabled', (done) => {
it('should announce week numbers if enabled', () => {
datepicker._focusedDate = new Date(2016, 1, 1);
datepicker.showWeekNumbers = true;
datepicker.set('i18n.firstDayOfWeek', 1);
datepicker.open();

waitForAnnounce((text) => {
expect(text).to.match(/ Week 5$/);
done();
});
clock.tick(200);

datepicker.open();
expect(region.textContent).to.match(/ Week 5$/);
});

if (!isIOS) {
it('should announce once', async () => {
datepicker._focusedDate = new Date(2016, 1, 1);
await open(datepicker);
const announceSpy = sinon.spy();
document.body.addEventListener('iron-announce', announceSpy);
datepicker._focusedDate = new Date(2016, 1, 2);
await aTimeout(1);
expect(announceSpy.callCount).to.be.equal(1);
document.body.removeEventListener('iron-announce', announceSpy);
});
}

describe('i18n', () => {
beforeEach(() => {
const monthNames =
Expand All @@ -382,36 +354,32 @@ describe('WAI-ARIA', () => {
datepicker.set('i18n.today', 'Tänään');
});

it('should announce dates in correct locale', (done) => {
waitForAnnounce((text) => {
expect(text).to.equal('maanantai 1 helmikuu 2016');
done();
});

it('should announce dates in correct locale', () => {
datepicker._focusedDate = new Date(2016, 1, 1);
datepicker.open();
});

it('should announce today in correct locale', (done) => {
waitForAnnounce((text) => {
expect(text.indexOf('Tänään')).to.equal(0);
done();
});
clock.tick(200);

expect(region.textContent).to.equal('maanantai 1 helmikuu 2016');
});

it('should announce today in correct locale', () => {
datepicker.open();

clock.tick(200);

expect(region.textContent.indexOf('Tänään')).to.equal(0);
});

it('should announce week numbers in correct locale', (done) => {
it('should announce week numbers in correct locale', () => {
datepicker._focusedDate = new Date(2016, 1, 1);
datepicker.showWeekNumbers = true;
datepicker.set('i18n.firstDayOfWeek', 1);
datepicker.open();

waitForAnnounce((text) => {
expect(text).to.match(/ viikko 5$/);
done();
});
clock.tick(200);

datepicker.open();
expect(region.textContent).to.match(/ viikko 5$/);
});
});
});
Expand Down