feat(calendar): add year navigation

This commit is contained in:
qa46hx 2020-08-13 10:55:23 +02:00 committed by Thomas Allmer
parent 6729a9fb32
commit d5f8b461d3
23 changed files with 613 additions and 249 deletions

View file

@ -156,7 +156,7 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
render() { render() {
return html` return html`
<div class="calendar" role="application"> <div class="calendar" role="application">
${this.__renderHeader()} ${this.__renderData()} ${this.__renderNavigation()} ${this.__renderData()}
</div> </div>
`; `;
} }
@ -173,6 +173,14 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
this.__modifyDate(-1, { dateType: 'centralDate', type: 'Month', mode: 'both' }); this.__modifyDate(-1, { dateType: 'centralDate', type: 'Month', mode: 'both' });
} }
goToNextYear() {
this.__modifyDate(1, { dateType: 'centralDate', type: 'FullYear', mode: 'both' });
}
goToPreviousYear() {
this.__modifyDate(-1, { dateType: 'centralDate', type: 'FullYear', mode: 'both' });
}
async focusDate(date) { async focusDate(date) {
this.centralDate = date; this.centralDate = date;
await this.updateComplete; await this.updateComplete;
@ -254,9 +262,7 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
} }
} }
__renderHeader() { __renderMonthNavigation(month, year) {
const month = getMonthNames({ locale: this.__getLocale() })[this.centralDate.getMonth()];
const year = this.centralDate.getFullYear();
const nextMonth = const nextMonth =
this.centralDate.getMonth() === 11 this.centralDate.getMonth() === 11
? getMonthNames({ locale: this.__getLocale() })[0] ? getMonthNames({ locale: this.__getLocale() })[0]
@ -265,22 +271,40 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
this.centralDate.getMonth() === 0 this.centralDate.getMonth() === 0
? getMonthNames({ locale: this.__getLocale() })[11] ? getMonthNames({ locale: this.__getLocale() })[11]
: getMonthNames({ locale: this.__getLocale() })[this.centralDate.getMonth() - 1]; : getMonthNames({ locale: this.__getLocale() })[this.centralDate.getMonth() - 1];
const nextYear = const nextYear = this.centralDate.getMonth() === 11 ? year + 1 : year;
this.centralDate.getMonth() === 11 const previousYear = this.centralDate.getMonth() === 0 ? year - 1 : year;
? this.centralDate.getFullYear() + 1 return html`
: this.centralDate.getFullYear(); <div class="calendar__navigation__month">
const previousYear = ${this.__renderPreviousButton('Month', previousMonth, previousYear)}
this.centralDate.getMonth() === 0 <h2 class="calendar__navigation-heading" id="month" aria-atomic="true">
? this.centralDate.getFullYear() - 1 ${month}
: this.centralDate.getFullYear(); </h2>
${this.__renderNextButton('Month', nextMonth, nextYear)}
</div>
`;
}
__renderYearNavigation(month, year) {
const nextYear = year + 1;
const previousYear = year - 1;
return html` return html`
<div class="calendar__header"> <div class="calendar__navigation__year">
${this.__renderPreviousButton(previousMonth, previousYear)} ${this.__renderPreviousButton('FullYear', month, previousYear)}
<h2 class="calendar__month-heading" id="month_and_year" aria-atomic="true"> <h2 class="calendar__navigation-heading" id="year" aria-atomic="true">
${month} ${year} ${year}
</h2> </h2>
${this.__renderNextButton(nextMonth, nextYear)} ${this.__renderNextButton('FullYear', month, nextYear)}
</div>
`;
}
__renderNavigation() {
const month = getMonthNames({ locale: this.__getLocale() })[this.centralDate.getMonth()];
const year = this.centralDate.getFullYear();
return html`
<div class="calendar__navigation">
${this.__renderYearNavigation(month, year)} ${this.__renderMonthNavigation(month, year)}
</div> </div>
`; `;
} }
@ -302,40 +326,96 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
}); });
} }
__renderPreviousButton(previousMonth, previousYear) { __getPreviousDisabled(type, previousMonth, previousYear) {
const previousButtonTitle = `${this.msgLit( let disabled;
'lion-calendar:previousMonth', let month = previousMonth;
)}, ${previousMonth} ${previousYear}`; if (this.minDate && type === 'Month') {
disabled = getLastDayPreviousMonth(this.centralDate) < this.minDate;
} else if (this.minDate) {
disabled = previousYear < this.minDate.getFullYear();
}
if (!disabled && this.minDate && type === 'FullYear') {
// change the month to the first available month
if (previousYear === this.minDate.getFullYear()) {
if (this.centralDate.getMonth() < this.minDate.getMonth()) {
month = getMonthNames({ locale: this.__getLocale() })[this.minDate.getMonth()];
}
}
}
return { disabled, month };
}
__getNextDisabled(type, nextMonth, nextYear) {
let disabled;
let month = nextMonth;
if (this.maxDate && type === 'Month') {
disabled = getFirstDayNextMonth(this.centralDate) > this.maxDate;
} else if (this.maxDate) {
disabled = nextYear > this.maxDate.getFullYear();
}
if (!disabled && this.maxDate && type === 'FullYear') {
// change the month to the first available month
if (nextYear === this.maxDate.getFullYear()) {
if (this.centralDate.getMonth() >= this.maxDate.getMonth()) {
month = getMonthNames({ locale: this.__getLocale() })[this.maxDate.getMonth()];
}
}
}
return { disabled, month };
}
__renderPreviousButton(type, previousMonth, previousYear) {
const { disabled, month } = this.__getPreviousDisabled(type, previousMonth, previousYear);
const previousButtonTitle = this.__getNavigationLabel('previous', type, month, previousYear);
function clickDateDelegation() {
if (type === 'FullYear') {
this.goToPreviousYear();
} else {
this.goToPreviousMonth();
}
}
return html` return html`
<button <button
class="calendar__previous-month-button" class="calendar__previous-button"
aria-label=${previousButtonTitle} aria-label=${previousButtonTitle}
title=${previousButtonTitle} title=${previousButtonTitle}
@click=${this.goToPreviousMonth} @click=${clickDateDelegation}
?disabled=${this.isPreviousMonthDisabled} ?disabled=${disabled}
> >
&lt; &lt;
</button> </button>
`; `;
} }
__renderNextButton(nextMonth, nextYear) { __renderNextButton(type, nextMonth, nextYear) {
const nextButtonTitle = `${this.msgLit('lion-calendar:nextMonth')}, ${nextMonth} ${nextYear}`; const { disabled, month } = this.__getNextDisabled(type, nextMonth, nextYear);
const nextButtonTitle = this.__getNavigationLabel('next', type, month, nextYear);
function clickDateDelegation() {
if (type === 'FullYear') {
this.goToNextYear();
} else {
this.goToNextMonth();
}
}
return html` return html`
<button <button
class="calendar__next-month-button" class="calendar__next-button"
aria-label=${nextButtonTitle} aria-label=${nextButtonTitle}
title=${nextButtonTitle} title=${nextButtonTitle}
@click=${this.goToNextMonth} @click=${clickDateDelegation}
?disabled=${this.isNextMonthDisabled} ?disabled=${disabled}
> >
&gt; &gt;
</button> </button>
`; `;
} }
__getNavigationLabel(mode, type, month, year) {
return `${this.msgLit(`lion-calendar:${mode}${type}`)}, ${month} ${year}`;
}
__coreDayPreprocessor(_day, { currentMonth = false } = {}) { __coreDayPreprocessor(_day, { currentMonth = false } = {}) {
const day = createDay(new Date(_day.date), _day); const day = createDay(new Date(_day.date), _day);
const today = normalizeDateTime(new Date()); const today = normalizeDateTime(new Date());
@ -380,12 +460,6 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
}); });
}); });
}); });
this.isNextMonthDisabled =
this.maxDate && getFirstDayNextMonth(this.centralDate) > this.maxDate;
this.isPreviousMonthDisabled =
this.minDate && getLastDayPreviousMonth(this.centralDate) < this.minDate;
return data; return data;
} }

View file

@ -13,19 +13,21 @@ export const calendarStyle = css`
display: block; display: block;
} }
.calendar__header { .calendar__navigation {
display: flex;
justify-content: space-between;
border-bottom: 1px solid #adadad;
padding: 0 8px; padding: 0 8px;
} }
.calendar__month-heading { .calendar__navigation__month,
.calendar__navigation__year {
display: flex;
}
.calendar__navigation-heading {
margin: 0.5em 0; margin: 0.5em 0;
} }
.calendar__previous-month-button, .calendar__previous-button,
.calendar__next-month-button { .calendar__next-button {
background-color: #fff; background-color: #fff;
border: 0; border: 0;
padding: 0; padding: 0;

View file

@ -14,7 +14,7 @@ export function dataTemplate(
data-wrap-cols data-wrap-cols
aria-readonly="true" aria-readonly="true"
class="calendar__grid" class="calendar__grid"
aria-labelledby="month_and_year" aria-labelledby="month year"
> >
<thead> <thead>
<tr role="row"> <tr role="row">

View file

@ -14,14 +14,43 @@ const defaultMonthLabels = [
'November', 'November',
'December', 'December',
]; ];
const firstWeekDays = [1, 2, 3, 4, 5, 6, 7];
const lastDaysOfYear = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
export function dayTemplate(day, { weekdays, monthsLabels = defaultMonthLabels } = {}) { export function dayTemplate(day, { weekdays, monthsLabels = defaultMonthLabels } = {}) {
const dayNumber = day.date.getDate(); const dayNumber = day.date.getDate();
const monthName = monthsLabels[day.date.getMonth()]; const monthName = monthsLabels[day.date.getMonth()];
const year = day.date.getFullYear(); const year = day.date.getFullYear();
const weekdayName = weekdays[day.weekOrder]; const weekdayName = weekdays[day.weekOrder];
const firstDay = dayNumber === 1;
const endOfFirstWeek = day.weekOrder === 6 && firstWeekDays.includes(dayNumber);
const startOfFirstFullWeek = day.startOfWeek && firstWeekDays.includes(dayNumber);
if (year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)) {
lastDaysOfYear[1] = 29;
}
const lastDayNumber = lastDaysOfYear[day.date.getMonth()];
const lastWeekDays = [];
for (let i = lastDayNumber; i >= lastDayNumber - 7; i -= 1) {
lastWeekDays.push(i);
}
const endOfLastFullWeek = day.weekOrder === 6 && lastWeekDays.includes(dayNumber);
const startOfLastWeek = day.startOfWeek && lastWeekDays.includes(dayNumber);
const lastDay = lastDayNumber === dayNumber;
return html` return html`
<td role="gridcell" class="calendar__day-cell"> <td
role="gridcell"
class="calendar__day-cell"
?current-month=${day.currentMonth}
?first-day=${firstDay}
?end-of-first-week=${endOfFirstWeek}
?start-of-first-full-week=${startOfFirstFullWeek}
?end-of-last-full-week=${endOfLastFullWeek}
?start-of-last-week=${startOfLastWeek}
?last-day=${lastDay}
>
<button <button
.date=${day.date} .date=${day.date}
class="calendar__day-button" class="calendar__day-button"
@ -38,7 +67,9 @@ export function dayTemplate(day, { weekdays, monthsLabels = defaultMonthLabels }
?current-month=${day.currentMonth} ?current-month=${day.currentMonth}
?next-month=${day.nextMonth} ?next-month=${day.nextMonth}
> >
<span class="calendar__day-button__text">
${day.date.getDate()} ${day.date.getDate()}
</span>
</button> </button>
</td> </td>
`; `;

View file

@ -18,19 +18,31 @@ export class CalendarObject {
} }
get headerEl() { get headerEl() {
return this.el.shadowRoot.querySelector('.calendar__header'); return this.el.shadowRoot.querySelector('.calendar__navigation');
}
get yearHeadingEl() {
return this.el.shadowRoot.querySelector('#year');
} }
get monthHeadingEl() { get monthHeadingEl() {
return this.el.shadowRoot.querySelector('.calendar__month-heading'); return this.el.shadowRoot.querySelector('#month');
}
get nextYearButtonEl() {
return this.el.shadowRoot.querySelectorAll('.calendar__next-button')[0];
}
get previousYearButtonEl() {
return this.el.shadowRoot.querySelectorAll('.calendar__previous-button')[0];
} }
get nextMonthButtonEl() { get nextMonthButtonEl() {
return this.el.shadowRoot.querySelector('.calendar__next-month-button'); return this.el.shadowRoot.querySelectorAll('.calendar__next-button')[1];
} }
get previousMonthButtonEl() { get previousMonthButtonEl() {
return this.el.shadowRoot.querySelector('.calendar__previous-month-button'); return this.el.shadowRoot.querySelectorAll('.calendar__previous-button')[1];
} }
get gridEl() { get gridEl() {
@ -117,15 +129,11 @@ export class CalendarObject {
/** /**
* States * States
*/ */
get activeMonthAndYear() { get activeMonth() {
return this.monthHeadingEl.textContent.trim(); return this.monthHeadingEl.textContent.trim();
} }
get activeMonth() {
return this.activeMonthAndYear.split(' ')[0];
}
get activeYear() { get activeYear() {
return this.activeMonthAndYear.split(' ')[1]; return this.yearHeadingEl.textContent.trim();
} }
} }

View file

@ -18,10 +18,10 @@ describe('<lion-calendar>', () => {
const el = await fixture(html`<lion-calendar></lion-calendar>`); const el = await fixture(html`<lion-calendar></lion-calendar>`);
expect(el.shadowRoot.querySelector('.calendar')).to.exist; expect(el.shadowRoot.querySelector('.calendar')).to.exist;
expect(el.shadowRoot.querySelector('.calendar__header')).to.exist; expect(el.shadowRoot.querySelector('.calendar__navigation')).to.exist;
expect(el.shadowRoot.querySelector('.calendar__previous-month-button')).to.exist; expect(el.shadowRoot.querySelector('.calendar__previous-button')).to.exist;
expect(el.shadowRoot.querySelector('.calendar__next-month-button')).to.exist; expect(el.shadowRoot.querySelector('.calendar__next-button')).to.exist;
expect(el.shadowRoot.querySelector('.calendar__month-heading')).to.exist; expect(el.shadowRoot.querySelector('.calendar__navigation-heading')).to.exist;
expect(el.shadowRoot.querySelector('.calendar__grid')).to.exist; expect(el.shadowRoot.querySelector('.calendar__grid')).to.exist;
}); });
@ -30,25 +30,52 @@ describe('<lion-calendar>', () => {
const el = await fixture(html`<lion-calendar></lion-calendar>`); const el = await fixture(html`<lion-calendar></lion-calendar>`);
expect(el.shadowRoot.querySelector('.calendar__month-heading')).dom.to.equal(` expect(el.shadowRoot.querySelector('#year')).dom.to.equal(`
<h2 <h2
id="month_and_year" id="year"
class="calendar__month-heading" class="calendar__navigation-heading"
aria-atomic="true" aria-atomic="true"
> >
December 2000 2000
</h2>
`);
expect(el.shadowRoot.querySelector('#month')).dom.to.equal(`
<h2
id="month"
class="calendar__navigation-heading"
aria-atomic="true"
>
December
</h2> </h2>
`); `);
clock.restore(); clock.restore();
}); });
it('has previous year button', async () => {
const el = await fixture(
html`<lion-calendar .centralDate=${new Date('2019/11/20')}></lion-calendar>`,
);
expect(el.shadowRoot.querySelectorAll('.calendar__previous-button')[0]).dom.to.equal(`
<button class="calendar__previous-button" aria-label="Previous year, November 2018" title="Previous year, November 2018">&lt;</button>
`);
});
it('has next year button', async () => {
const el = await fixture(
html`<lion-calendar .centralDate=${new Date('2019/11/20')}></lion-calendar>`,
);
expect(el.shadowRoot.querySelectorAll('.calendar__next-button')[0]).dom.to.equal(`
<button class="calendar__next-button" aria-label="Next year, November 2020" title="Next year, November 2020">&gt;</button>
`);
});
it('has previous month button', async () => { it('has previous month button', async () => {
const el = await fixture( const el = await fixture(
html`<lion-calendar .centralDate=${new Date('2019/11/20')}></lion-calendar>`, html`<lion-calendar .centralDate=${new Date('2019/11/20')}></lion-calendar>`,
); );
expect(el.shadowRoot.querySelector('.calendar__previous-month-button')).dom.to.equal(` expect(el.shadowRoot.querySelectorAll('.calendar__previous-button')[1]).dom.to.equal(`
<button class="calendar__previous-month-button" aria-label="Previous month, October 2019" title="Previous month, October 2019">&lt;</button> <button class="calendar__previous-button" aria-label="Previous month, October 2019" title="Previous month, October 2019">&lt;</button>
`); `);
}); });
@ -56,8 +83,8 @@ describe('<lion-calendar>', () => {
const el = await fixture( const el = await fixture(
html`<lion-calendar .centralDate=${new Date('2019/11/20')}></lion-calendar>`, html`<lion-calendar .centralDate=${new Date('2019/11/20')}></lion-calendar>`,
); );
expect(el.shadowRoot.querySelector('.calendar__next-month-button')).dom.to.equal(` expect(el.shadowRoot.querySelectorAll('.calendar__next-button')[1]).dom.to.equal(`
<button class="calendar__next-month-button" aria-label="Next month, December 2019" title="Next month, December 2019">&gt;</button> <button class="calendar__next-button" aria-label="Next month, December 2019" title="Next month, December 2019">&gt;</button>
`); `);
}); });
}); });
@ -69,7 +96,8 @@ describe('<lion-calendar>', () => {
<lion-calendar .centralDate="${new Date('2014/05/15')}"></lion-calendar> <lion-calendar .centralDate="${new Date('2014/05/15')}"></lion-calendar>
`), `),
); );
expect(elObj.activeMonthAndYear).to.equal('May 2014'); expect(elObj.activeMonth).to.equal('May');
expect(elObj.activeYear).to.equal('2014');
}); });
it('sets "centralDate" to today by default', async () => { it('sets "centralDate" to today by default', async () => {
@ -78,7 +106,8 @@ describe('<lion-calendar>', () => {
const el = await fixture(html`<lion-calendar></lion-calendar>`); const el = await fixture(html`<lion-calendar></lion-calendar>`);
const elObj = new CalendarObject(el); const elObj = new CalendarObject(el);
expect(isSameDate(el.centralDate, new Date())).to.be.true; expect(isSameDate(el.centralDate, new Date())).to.be.true;
expect(elObj.activeMonthAndYear).to.equal('March 2013'); expect(elObj.activeMonth).to.equal('March');
expect(elObj.activeYear).to.equal('2013');
clock.restore(); clock.restore();
}); });
@ -125,7 +154,8 @@ describe('<lion-calendar>', () => {
></lion-calendar> ></lion-calendar>
`), `),
); );
expect(elObj.activeMonthAndYear).to.equal('June 2018'); expect(elObj.activeMonth).to.equal('June');
expect(elObj.activeYear).to.equal('2018');
}); });
it('changes "centralDate" from default to "selectedDate" on first render if no other custom "centralDate" is provided', async () => { it('changes "centralDate" from default to "selectedDate" on first render if no other custom "centralDate" is provided', async () => {
@ -136,8 +166,8 @@ describe('<lion-calendar>', () => {
`); `);
const elObj = new CalendarObject(el); const elObj = new CalendarObject(el);
expect(isSameDate(el.centralDate, new Date('2016/10/20'))).to.be.true; expect(isSameDate(el.centralDate, new Date('2016/10/20'))).to.be.true;
expect(elObj.activeMonthAndYear).to.equal('October 2016'); expect(elObj.activeMonth).to.equal('October');
expect(elObj.activeYear).to.equal('2016');
clock.restore(); clock.restore();
}); });
@ -318,7 +348,8 @@ describe('<lion-calendar>', () => {
`); `);
const elObj = new CalendarObject(el); const elObj = new CalendarObject(el);
expect(isSameDate(el.centralDate, new Date('2001/01/08'))).to.be.true; expect(isSameDate(el.centralDate, new Date('2001/01/08'))).to.be.true;
expect(elObj.activeMonthAndYear).to.equal('January 2001'); expect(elObj.activeMonth).to.equal('January');
expect(elObj.activeYear).to.equal('2001');
clock.restore(); clock.restore();
}); });
@ -377,14 +408,15 @@ describe('<lion-calendar>', () => {
}); });
}); });
describe('Calendar header (month navigation)', () => { describe('Calendar navigation', () => {
describe('Title', () => { describe('Title', () => {
it('contains secondary title displaying the current month and year in focus', async () => { it('contains secondary title displaying the current month and year in focus', async () => {
const el = await fixture( const el = await fixture(
html`<lion-calendar .selectedDate="${new Date('2000/12/12')}"></lion-calendar>`, html`<lion-calendar .selectedDate="${new Date('2000/12/12')}"></lion-calendar>`,
); );
const elObj = new CalendarObject(el); const elObj = new CalendarObject(el);
expect(elObj.activeMonthAndYear).to.equal('December 2000'); expect(elObj.activeMonth).to.equal('December');
expect(elObj.activeYear).to.equal('2000');
}); });
it('updates the secondary title when the displayed month/year changes', async () => { it('updates the secondary title when the displayed month/year changes', async () => {
@ -394,7 +426,8 @@ describe('<lion-calendar>', () => {
const elObj = new CalendarObject(el); const elObj = new CalendarObject(el);
el.centralDate = new Date('1999/10/12'); el.centralDate = new Date('1999/10/12');
await el.updateComplete; await el.updateComplete;
expect(elObj.activeMonthAndYear).to.equal('October 1999'); expect(elObj.activeMonth).to.equal('October');
expect(elObj.activeYear).to.equal('1999');
}); });
describe('Accessibility', () => { describe('Accessibility', () => {
@ -406,21 +439,112 @@ describe('<lion-calendar>', () => {
}); });
describe('Navigation', () => { describe('Navigation', () => {
describe('Year', () => {
it('has a button for navigation to previous year', async () => {
const el = await fixture(
html`<lion-calendar .selectedDate="${new Date('2001/01/01')}"></lion-calendar>`,
);
const elObj = new CalendarObject(el);
expect(elObj.previousYearButtonEl).not.to.equal(null);
expect(elObj.activeMonth).to.equal('January');
expect(elObj.activeYear).to.equal('2001');
elObj.previousYearButtonEl.click();
await el.updateComplete;
expect(elObj.activeMonth).to.equal('January');
expect(elObj.activeYear).to.equal('2000');
elObj.previousYearButtonEl.click();
await el.updateComplete;
expect(elObj.activeMonth).to.equal('January');
expect(elObj.activeYear).to.equal('1999');
});
it('has a button for navigation to next year', async () => {
const el = await fixture(
html`<lion-calendar .selectedDate="${new Date('2000/12/12')}"></lion-calendar>`,
);
const elObj = new CalendarObject(el);
expect(elObj.nextYearButtonEl).not.to.equal(null);
expect(elObj.activeMonth).to.equal('December');
expect(elObj.activeYear).to.equal('2000');
elObj.nextYearButtonEl.click();
await el.updateComplete;
expect(elObj.activeMonth).to.equal('December');
expect(elObj.activeYear).to.equal('2001');
elObj.nextYearButtonEl.click();
await el.updateComplete;
expect(elObj.activeMonth).to.equal('December');
expect(elObj.activeYear).to.equal('2002');
});
it('disables previousYearButton and nextYearButton based on disabled days accordingly', async () => {
const el = await fixture(html`
<lion-calendar .selectedDate="${new Date('2000/06/12')}"></lion-calendar>
`);
const elObj = new CalendarObject(el);
expect(elObj.activeMonth).to.equal('June');
expect(elObj.activeYear).to.equal('2000');
expect(elObj.previousYearButtonEl.hasAttribute('disabled')).to.equal(false);
expect(elObj.nextYearButtonEl.hasAttribute('disabled')).to.equal(false);
el.minDate = new Date('2000/01/01');
el.maxDate = new Date('2000/12/31');
await el.updateComplete;
expect(elObj.previousYearButtonEl.hasAttribute('disabled')).to.equal(true);
expect(elObj.nextYearButtonEl.hasAttribute('disabled')).to.equal(true);
elObj.previousYearButtonEl.click();
await el.updateComplete;
expect(elObj.activeMonth).to.equal('June');
expect(elObj.activeYear).to.equal('2000');
el.minDate = new Date('1999/12/31');
el.maxDate = new Date('2001/01/01');
await el.updateComplete;
expect(elObj.previousYearButtonEl.hasAttribute('disabled')).to.equal(false);
expect(elObj.nextYearButtonEl.hasAttribute('disabled')).to.equal(false);
});
it('sets label to correct month previousYearButton and nextYearButton based on disabled days accordingly', async () => {
const el = await fixture(html`
<lion-calendar .selectedDate="${new Date('2000/06/12')}"></lion-calendar>
`);
const elObj = new CalendarObject(el);
el.minDate = new Date('1999/07/12');
el.maxDate = new Date('2001/05/12');
await el.updateComplete;
expect(elObj.previousYearButtonEl.hasAttribute('disabled')).to.equal(false);
expect(elObj.previousYearButtonEl.ariaLabel).to.equal('Previous year, July 1999');
expect(elObj.nextYearButtonEl.hasAttribute('disabled')).to.equal(false);
expect(elObj.nextYearButtonEl.ariaLabel).to.equal('Next year, May 2001');
});
});
describe('Month', () => {
it('has a button for navigation to previous month', async () => { it('has a button for navigation to previous month', async () => {
const el = await fixture( const el = await fixture(
html`<lion-calendar .selectedDate="${new Date('2001/01/01')}"></lion-calendar>`, html`<lion-calendar .selectedDate="${new Date('2001/01/01')}"></lion-calendar>`,
); );
const elObj = new CalendarObject(el); const elObj = new CalendarObject(el);
expect(elObj.previousMonthButtonEl).not.to.equal(null); expect(elObj.previousMonthButtonEl).not.to.equal(null);
expect(elObj.activeMonthAndYear).to.equal('January 2001'); expect(elObj.activeMonth).to.equal('January');
expect(elObj.activeYear).to.equal('2001');
elObj.previousMonthButtonEl.click(); elObj.previousMonthButtonEl.click();
await el.updateComplete; await el.updateComplete;
expect(elObj.activeMonthAndYear).to.equal('December 2000'); expect(elObj.activeMonth).to.equal('December');
expect(elObj.activeYear).to.equal('2000');
elObj.previousMonthButtonEl.click(); elObj.previousMonthButtonEl.click();
await el.updateComplete; await el.updateComplete;
expect(elObj.activeMonthAndYear).to.equal('November 2000'); expect(elObj.activeMonth).to.equal('November');
expect(elObj.activeYear).to.equal('2000');
}); });
it('has a button for navigation to next month', async () => { it('has a button for navigation to next month', async () => {
@ -429,15 +553,18 @@ describe('<lion-calendar>', () => {
); );
const elObj = new CalendarObject(el); const elObj = new CalendarObject(el);
expect(elObj.nextMonthButtonEl).not.to.equal(null); expect(elObj.nextMonthButtonEl).not.to.equal(null);
expect(elObj.activeMonthAndYear).to.equal('December 2000'); expect(elObj.activeMonth).to.equal('December');
expect(elObj.activeYear).to.equal('2000');
elObj.nextMonthButtonEl.click(); elObj.nextMonthButtonEl.click();
await el.updateComplete; await el.updateComplete;
expect(elObj.activeMonthAndYear).to.equal('January 2001'); expect(elObj.activeMonth).to.equal('January');
expect(elObj.activeYear).to.equal('2001');
elObj.nextMonthButtonEl.click(); elObj.nextMonthButtonEl.click();
await el.updateComplete; await el.updateComplete;
expect(elObj.activeMonthAndYear).to.equal('February 2001'); expect(elObj.activeMonth).to.equal('February');
expect(elObj.activeYear).to.equal('2001');
}); });
it('disables previousMonthButton and nextMonthButton based on disabled days accordingly', async () => { it('disables previousMonthButton and nextMonthButton based on disabled days accordingly', async () => {
@ -445,7 +572,8 @@ describe('<lion-calendar>', () => {
<lion-calendar .selectedDate="${new Date('2000/12/12')}"></lion-calendar> <lion-calendar .selectedDate="${new Date('2000/12/12')}"></lion-calendar>
`); `);
const elObj = new CalendarObject(el); const elObj = new CalendarObject(el);
expect(elObj.activeMonthAndYear).to.equal('December 2000'); expect(elObj.activeMonth).to.equal('December');
expect(elObj.activeYear).to.equal('2000');
expect(elObj.previousMonthButtonEl.hasAttribute('disabled')).to.equal(false); expect(elObj.previousMonthButtonEl.hasAttribute('disabled')).to.equal(false);
expect(elObj.nextMonthButtonEl.hasAttribute('disabled')).to.equal(false); expect(elObj.nextMonthButtonEl.hasAttribute('disabled')).to.equal(false);
@ -458,11 +586,13 @@ describe('<lion-calendar>', () => {
elObj.previousMonthButtonEl.click(); elObj.previousMonthButtonEl.click();
await el.updateComplete; await el.updateComplete;
expect(elObj.activeMonthAndYear).to.equal('December 2000'); expect(elObj.activeMonth).to.equal('December');
expect(elObj.activeYear).to.equal('2000');
elObj.previousMonthButtonEl.click(); elObj.previousMonthButtonEl.click();
await el.updateComplete; await el.updateComplete;
expect(elObj.activeMonthAndYear).to.equal('December 2000'); expect(elObj.activeMonth).to.equal('December');
expect(elObj.activeYear).to.equal('2000');
}); });
it('handles switch to previous month when dates are disabled', async () => { it('handles switch to previous month when dates are disabled', async () => {
@ -470,7 +600,8 @@ describe('<lion-calendar>', () => {
const el = await fixture(html`<lion-calendar></lion-calendar>`); const el = await fixture(html`<lion-calendar></lion-calendar>`);
const elObj = new CalendarObject(el); const elObj = new CalendarObject(el);
expect(elObj.activeMonthAndYear).to.equal('December 2000'); expect(elObj.activeMonth).to.equal('December');
expect(elObj.activeYear).to.equal('2000');
el.minDate = new Date('2000/11/20'); el.minDate = new Date('2000/11/20');
await el.updateComplete; await el.updateComplete;
@ -480,7 +611,8 @@ describe('<lion-calendar>', () => {
elObj.previousMonthButtonEl.click(); elObj.previousMonthButtonEl.click();
await el.updateComplete; await el.updateComplete;
expect(elObj.activeMonthAndYear).to.equal('November 2000'); expect(elObj.activeMonth).to.equal('November');
expect(elObj.activeYear).to.equal('2000');
expect(isSameDate(el.centralDate, new Date('2000/11/20'))).to.be.true; expect(isSameDate(el.centralDate, new Date('2000/11/20'))).to.be.true;
clock.restore(); clock.restore();
@ -491,7 +623,8 @@ describe('<lion-calendar>', () => {
const el = await fixture(html`<lion-calendar></lion-calendar>`); const el = await fixture(html`<lion-calendar></lion-calendar>`);
const elObj = new CalendarObject(el); const elObj = new CalendarObject(el);
expect(elObj.activeMonthAndYear).to.equal('December 2000'); expect(elObj.activeMonth).to.equal('December');
expect(elObj.activeYear).to.equal('2000');
el.maxDate = new Date('2001/01/10'); el.maxDate = new Date('2001/01/10');
await el.updateComplete; await el.updateComplete;
@ -501,7 +634,8 @@ describe('<lion-calendar>', () => {
elObj.nextMonthButtonEl.click(); elObj.nextMonthButtonEl.click();
await el.updateComplete; await el.updateComplete;
expect(elObj.activeMonthAndYear).to.equal('January 2001'); expect(elObj.activeMonth).to.equal('January');
expect(elObj.activeYear).to.equal('2001');
expect(isSameDate(el.centralDate, new Date('2001/01/10'))).to.be.true; expect(isSameDate(el.centralDate, new Date('2001/01/10'))).to.be.true;
clock.restore(); clock.restore();
@ -518,7 +652,8 @@ describe('<lion-calendar>', () => {
remote.nextMonthButtonEl.click(); remote.nextMonthButtonEl.click();
await element.updateComplete; await element.updateComplete;
// then // then
expect(remote.activeMonthAndYear).to.equal('September 2019'); expect(remote.activeMonth).to.equal('September');
expect(remote.activeYear).to.equal('2019');
expect(remote.centralDayObj.el).dom.to.equal(` expect(remote.centralDayObj.el).dom.to.equal(`
<button <button
class="calendar__day-button" class="calendar__day-button"
@ -527,10 +662,13 @@ describe('<lion-calendar>', () => {
aria-pressed="false" aria-pressed="false"
past="" past=""
current-month=""> current-month="">
<span class="calendar__day-button__text">
30 30
</span>
</button> </button>
`); `);
}); });
});
describe('Accessibility', () => { describe('Accessibility', () => {
it('navigate buttons have a aria-label and title attribute with accessible label', async () => { it('navigate buttons have a aria-label and title attribute with accessible label', async () => {
@ -538,6 +676,7 @@ describe('<lion-calendar>', () => {
<lion-calendar .selectedDate="${new Date('2000/12/12')}"></lion-calendar> <lion-calendar .selectedDate="${new Date('2000/12/12')}"></lion-calendar>
`); `);
const elObj = new CalendarObject(el); const elObj = new CalendarObject(el);
// month
expect(elObj.previousMonthButtonEl.getAttribute('title')).to.equal( expect(elObj.previousMonthButtonEl.getAttribute('title')).to.equal(
'Previous month, November 2000', 'Previous month, November 2000',
); );
@ -550,6 +689,18 @@ describe('<lion-calendar>', () => {
expect(elObj.nextMonthButtonEl.getAttribute('aria-label')).to.equal( expect(elObj.nextMonthButtonEl.getAttribute('aria-label')).to.equal(
'Next month, January 2001', 'Next month, January 2001',
); );
// year
expect(elObj.previousYearButtonEl.getAttribute('title')).to.equal(
'Previous year, December 1999',
);
expect(elObj.previousYearButtonEl.getAttribute('aria-label')).to.equal(
'Previous year, December 1999',
);
expect(elObj.nextYearButtonEl.getAttribute('title')).to.equal('Next year, December 2001');
expect(elObj.nextYearButtonEl.getAttribute('aria-label')).to.equal(
'Next year, December 2001',
);
}); });
}); });
}); });
@ -670,17 +821,20 @@ describe('<lion-calendar>', () => {
<lion-calendar .selectedDate="${new Date('2001/01/02')}"></lion-calendar> <lion-calendar .selectedDate="${new Date('2001/01/02')}"></lion-calendar>
`); `);
const elObj = new CalendarObject(el); const elObj = new CalendarObject(el);
expect(elObj.activeMonthAndYear).to.equal('January 2001'); expect(elObj.activeMonth).to.equal('January');
expect(elObj.activeYear).to.equal('2001');
el.__contentWrapperElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'PageUp' })); el.__contentWrapperElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'PageUp' }));
await el.updateComplete; await el.updateComplete;
expect(elObj.activeMonthAndYear).to.equal('December 2000'); expect(elObj.activeMonth).to.equal('December');
expect(elObj.activeYear).to.equal('2000');
el.__contentWrapperElement.dispatchEvent( el.__contentWrapperElement.dispatchEvent(
new KeyboardEvent('keydown', { key: 'PageDown' }), new KeyboardEvent('keydown', { key: 'PageDown' }),
); );
await el.updateComplete; await el.updateComplete;
expect(elObj.activeMonthAndYear).to.equal('January 2001'); expect(elObj.activeMonth).to.equal('January');
expect(elObj.activeYear).to.equal('2001');
}); });
it('navigates through years with [alt + pageup] [alt + pagedown] keys', async () => { it('navigates through years with [alt + pageup] [alt + pagedown] keys', async () => {
@ -688,19 +842,22 @@ describe('<lion-calendar>', () => {
<lion-calendar .selectedDate="${new Date('2001/01/02')}"></lion-calendar> <lion-calendar .selectedDate="${new Date('2001/01/02')}"></lion-calendar>
`); `);
const elObj = new CalendarObject(el); const elObj = new CalendarObject(el);
expect(elObj.activeMonthAndYear).to.equal('January 2001'); expect(elObj.activeMonth).to.equal('January');
expect(elObj.activeYear).to.equal('2001');
el.__contentWrapperElement.dispatchEvent( el.__contentWrapperElement.dispatchEvent(
new KeyboardEvent('keydown', { key: 'PageDown', altKey: true }), new KeyboardEvent('keydown', { key: 'PageDown', altKey: true }),
); );
await el.updateComplete; await el.updateComplete;
expect(elObj.activeMonthAndYear).to.equal('January 2002'); expect(elObj.activeMonth).to.equal('January');
expect(elObj.activeYear).to.equal('2002');
el.__contentWrapperElement.dispatchEvent( el.__contentWrapperElement.dispatchEvent(
new KeyboardEvent('keydown', { key: 'PageUp', altKey: true }), new KeyboardEvent('keydown', { key: 'PageUp', altKey: true }),
); );
await el.updateComplete; await el.updateComplete;
expect(elObj.activeMonthAndYear).to.equal('January 2001'); expect(elObj.activeMonth).to.equal('January');
expect(elObj.activeYear).to.equal('2001');
}); });
describe('Arrow keys', () => { describe('Arrow keys', () => {
@ -809,13 +966,15 @@ describe('<lion-calendar>', () => {
<lion-calendar .selectedDate="${new Date('2000/12/31')}"></lion-calendar> <lion-calendar .selectedDate="${new Date('2000/12/31')}"></lion-calendar>
`); `);
const elObj = new CalendarObject(el); const elObj = new CalendarObject(el);
expect(elObj.activeMonthAndYear).to.equal('December 2000'); expect(elObj.activeMonth).to.equal('December');
expect(elObj.activeYear).to.equal('2000');
el.__contentWrapperElement.dispatchEvent( el.__contentWrapperElement.dispatchEvent(
new KeyboardEvent('keydown', { key: 'ArrowRight' }), new KeyboardEvent('keydown', { key: 'ArrowRight' }),
); );
await el.updateComplete; await el.updateComplete;
expect(elObj.activeMonthAndYear).to.equal('January 2001'); expect(elObj.activeMonth).to.equal('January');
expect(elObj.activeYear).to.equal('2001');
expect(elObj.focusedDayObj.monthday).to.equal(1); expect(elObj.focusedDayObj.monthday).to.equal(1);
}); });
@ -824,13 +983,15 @@ describe('<lion-calendar>', () => {
<lion-calendar .selectedDate="${new Date('2001/01/01')}"></lion-calendar> <lion-calendar .selectedDate="${new Date('2001/01/01')}"></lion-calendar>
`); `);
const elObj = new CalendarObject(el); const elObj = new CalendarObject(el);
expect(elObj.activeMonthAndYear).to.equal('January 2001'); expect(elObj.activeMonth).to.equal('January');
expect(elObj.activeYear).to.equal('2001');
el.__contentWrapperElement.dispatchEvent( el.__contentWrapperElement.dispatchEvent(
new KeyboardEvent('keydown', { key: 'ArrowLeft' }), new KeyboardEvent('keydown', { key: 'ArrowLeft' }),
); );
await el.updateComplete; await el.updateComplete;
expect(elObj.activeMonthAndYear).to.equal('December 2000'); expect(elObj.activeMonth).to.equal('December');
expect(elObj.activeYear).to.equal('2000');
expect(elObj.focusedDayObj.monthday).to.equal(31); expect(elObj.focusedDayObj.monthday).to.equal(31);
}); });
@ -839,13 +1000,15 @@ describe('<lion-calendar>', () => {
<lion-calendar .selectedDate="${new Date('2000/12/30')}"></lion-calendar> <lion-calendar .selectedDate="${new Date('2000/12/30')}"></lion-calendar>
`); `);
const elObj = new CalendarObject(el); const elObj = new CalendarObject(el);
expect(elObj.activeMonthAndYear).to.equal('December 2000'); expect(elObj.activeMonth).to.equal('December');
expect(elObj.activeYear).to.equal('2000');
el.__contentWrapperElement.dispatchEvent( el.__contentWrapperElement.dispatchEvent(
new KeyboardEvent('keydown', { key: 'ArrowDown' }), new KeyboardEvent('keydown', { key: 'ArrowDown' }),
); );
await el.updateComplete; await el.updateComplete;
expect(elObj.activeMonthAndYear).to.equal('January 2001'); expect(elObj.activeMonth).to.equal('January');
expect(elObj.activeYear).to.equal('2001');
expect(elObj.focusedDayObj.monthday).to.equal(6); expect(elObj.focusedDayObj.monthday).to.equal(6);
}); });
@ -854,13 +1017,15 @@ describe('<lion-calendar>', () => {
<lion-calendar .selectedDate="${new Date('2001/01/02')}"></lion-calendar> <lion-calendar .selectedDate="${new Date('2001/01/02')}"></lion-calendar>
`); `);
const elObj = new CalendarObject(el); const elObj = new CalendarObject(el);
expect(elObj.activeMonthAndYear).to.equal('January 2001'); expect(elObj.activeMonth).to.equal('January');
expect(elObj.activeYear).to.equal('2001');
el.__contentWrapperElement.dispatchEvent( el.__contentWrapperElement.dispatchEvent(
new KeyboardEvent('keydown', { key: 'ArrowUp' }), new KeyboardEvent('keydown', { key: 'ArrowUp' }),
); );
await el.updateComplete; await el.updateComplete;
expect(elObj.activeMonthAndYear).to.equal('December 2000'); expect(elObj.activeMonth).to.equal('December');
expect(elObj.activeYear).to.equal('2000');
expect(elObj.focusedDayObj.monthday).to.equal(26); expect(elObj.focusedDayObj.monthday).to.equal(26);
}); });
}); });

View file

@ -1,17 +1,14 @@
/* eslint-disable no-unused-expressions */ /* eslint-disable no-unused-expressions */
import { expect, fixture } from '@open-wc/testing'; import { expect, fixture } from '@open-wc/testing';
import { createDay } from '../../src/utils/createDay.js'; import { createDay } from '../../src/utils/createDay.js';
import { dayTemplate } from '../../src/utils/dayTemplate.js'; import { dayTemplate } from '../../src/utils/dayTemplate.js';
const weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
describe('dayTemplate', () => { describe('dayTemplate', () => {
it('renders day cell', async () => { it('renders day cell', async () => {
const day = createDay(new Date('2019/04/19'), { weekOrder: 5 }); const day = createDay(new Date('2019/04/19'), { weekOrder: 5 });
const el = await fixture( const el = await fixture(dayTemplate(day, { weekdays }));
dayTemplate(day, {
weekdays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
}),
);
expect(el).dom.to.equal(` expect(el).dom.to.equal(`
<td role="gridcell" class="calendar__day-cell"> <td role="gridcell" class="calendar__day-cell">
<button <button
@ -20,9 +17,66 @@ describe('dayTemplate', () => {
aria-pressed="false" aria-pressed="false"
tabindex="-1" tabindex="-1"
> >
19 <span class="calendar__day-button__text">19</span>
</button> </button>
</td> </td>
`); `);
}); });
it('sets the first-day attribute', async () => {
let day = createDay(new Date('2019/04/01'));
const el1 = await fixture(dayTemplate(day, { weekdays }));
expect(el1.hasAttribute('first-day')).to.be.true;
day = createDay(new Date('2019/04/02'));
const el2 = await fixture(dayTemplate(day, { weekdays }));
expect(el2.hasAttribute('first-day')).to.be.false;
});
it('sets the end-of-first-week attribute', async () => {
let day = createDay(new Date('2019/04/06'), { weekOrder: 6 });
const el1 = await fixture(dayTemplate(day, { weekdays }));
expect(el1.hasAttribute('end-of-first-week')).to.be.true;
day = createDay(new Date('2019/04/13'), { weekOrder: 6 });
const el2 = await fixture(dayTemplate(day, { weekdays }));
expect(el2.hasAttribute('end-of-first-week')).to.be.false;
});
it('sets the start-of-first-full-week attribute', async () => {
let day = createDay(new Date('2019/04/07'), { startOfWeek: true });
const el1 = await fixture(dayTemplate(day, { weekdays }));
expect(el1.hasAttribute('start-of-first-full-week')).to.be.true;
day = createDay(new Date('2019/04/14'), { startOfWeek: true });
const el2 = await fixture(dayTemplate(day, { weekdays }));
expect(el2.hasAttribute('start-of-first-full-week')).to.be.false;
});
it('sets the end-of-last-full-week attribute', async () => {
let day = createDay(new Date('2019/04/27'), { weekOrder: 6 });
const el1 = await fixture(dayTemplate(day, { weekdays }));
expect(el1.hasAttribute('end-of-last-full-week')).to.be.true;
day = createDay(new Date('2019/04/20'), { weekOrder: 6 });
const el2 = await fixture(dayTemplate(day, { weekdays }));
expect(el2.hasAttribute('end-of-last-full-week')).to.be.false;
});
it('sets the start-of-last-week attribute', async () => {
let day = createDay(new Date('2019/04/28'), { startOfWeek: true });
const el1 = await fixture(dayTemplate(day, { weekdays }));
expect(el1.hasAttribute('start-of-last-week')).to.be.true;
day = createDay(new Date('2019/04/21'), { startOfWeek: true });
const el2 = await fixture(dayTemplate(day, { weekdays }));
expect(el2.hasAttribute('start-of-last-week')).to.be.false;
});
it('sets the last-day attribute', async () => {
let day = createDay(new Date('2019/04/30'), { startOfWeek: true });
const el1 = await fixture(dayTemplate(day, { weekdays }));
expect(el1.hasAttribute('last-day')).to.be.true;
day = createDay(new Date('2019/03/30'), { startOfWeek: true });
const el2 = await fixture(dayTemplate(day, { weekdays }));
expect(el2.hasAttribute('last-day')).to.be.false;
day = createDay(new Date('2019/02/28'), { startOfWeek: true });
const el3 = await fixture(dayTemplate(day, { weekdays }));
expect(el3.hasAttribute('last-day')).to.be.true;
});
}); });

View file

@ -3,7 +3,7 @@ const html = strings => strings[0];
export default html` export default html`
<div id="js-content-wrapper"> <div id="js-content-wrapper">
<table <table
aria-labelledby="month_and_year" aria-labelledby="month year"
aria-readonly="true" aria-readonly="true"
class="calendar__grid" class="calendar__grid"
data-wrap-cols="" data-wrap-cols=""
@ -51,14 +51,14 @@ export default html`
</thead> </thead>
<tbody> <tbody>
<tr role="row"> <tr role="row">
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell" start-of-last-week>
<button <button
aria-label="25 November 2018 Sunday" aria-label="25 November 2018 Sunday"
aria-pressed="false" aria-pressed="false"
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
25 <span class="calendar__day-button__text">25</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -68,7 +68,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
26 <span class="calendar__day-button__text">26</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -78,7 +78,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
27 <span class="calendar__day-button__text">27</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -88,7 +88,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
28 <span class="calendar__day-button__text">28</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -98,39 +98,39 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
29 <span class="calendar__day-button__text">29</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell" last-day>
<button <button
aria-label="30 November 2018 Friday" aria-label="30 November 2018 Friday"
aria-pressed="false" aria-pressed="false"
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
30 <span class="calendar__day-button__text">30</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell" end-of-first-week first-day>
<button <button
aria-label="1 December 2018 Saturday" aria-label="1 December 2018 Saturday"
aria-pressed="false" aria-pressed="false"
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
1 <span class="calendar__day-button__text">1</span>
</button> </button>
</td> </td>
</tr> </tr>
<tr role="row"> <tr role="row">
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell" start-of-first-full-week>
<button <button
aria-label="2 December 2018 Sunday" aria-label="2 December 2018 Sunday"
aria-pressed="false" aria-pressed="false"
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
2 <span class="calendar__day-button__text">2</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -140,7 +140,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
3 <span class="calendar__day-button__text">3</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -150,7 +150,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
4 <span class="calendar__day-button__text">4</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -160,7 +160,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
5 <span class="calendar__day-button__text">5</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -170,7 +170,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
6 <span class="calendar__day-button__text">6</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -180,7 +180,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
7 <span class="calendar__day-button__text">7</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -190,7 +190,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
8 <span class="calendar__day-button__text">8</span>
</button> </button>
</td> </td>
</tr> </tr>
@ -202,7 +202,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
9 <span class="calendar__day-button__text">9</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -212,7 +212,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
10 <span class="calendar__day-button__text">10</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -222,7 +222,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
11 <span class="calendar__day-button__text">11</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -232,7 +232,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
12 <span class="calendar__day-button__text">12</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -242,7 +242,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
13 <span class="calendar__day-button__text">13</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -252,7 +252,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
14 <span class="calendar__day-button__text">14</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -262,7 +262,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
15 <span class="calendar__day-button__text">15</span>
</button> </button>
</td> </td>
</tr> </tr>
@ -274,7 +274,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
16 <span class="calendar__day-button__text">16</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -284,7 +284,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
17 <span class="calendar__day-button__text">17</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -294,7 +294,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
18 <span class="calendar__day-button__text">18</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -304,7 +304,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
19 <span class="calendar__day-button__text">19</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -314,7 +314,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
20 <span class="calendar__day-button__text">20</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -324,7 +324,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
21 <span class="calendar__day-button__text">21</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -334,7 +334,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
22 <span class="calendar__day-button__text">22</span>
</button> </button>
</td> </td>
</tr> </tr>
@ -346,7 +346,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
23 <span class="calendar__day-button__text">23</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -356,7 +356,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
24 <span class="calendar__day-button__text">24</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -366,7 +366,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
25 <span class="calendar__day-button__text">25</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -376,7 +376,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
26 <span class="calendar__day-button__text">26</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -386,7 +386,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
27 <span class="calendar__day-button__text">27</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -396,49 +396,49 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
28 <span class="calendar__day-button__text">28</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell" end-of-last-full-week>
<button <button
aria-label="29 December 2018 Saturday" aria-label="29 December 2018 Saturday"
aria-pressed="false" aria-pressed="false"
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
29 <span class="calendar__day-button__text">29</span>
</button> </button>
</td> </td>
</tr> </tr>
<tr role="row"> <tr role="row">
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell" start-of-last-week>
<button <button
aria-label="30 December 2018 Sunday" aria-label="30 December 2018 Sunday"
aria-pressed="false" aria-pressed="false"
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
30 <span class="calendar__day-button__text">30</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" last-day role="gridcell">
<button <button
aria-label="31 December 2018 Monday" aria-label="31 December 2018 Monday"
aria-pressed="false" aria-pressed="false"
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
31 <span class="calendar__day-button__text">31</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell" first-day>
<button <button
aria-label="1 January 2019 Tuesday" aria-label="1 January 2019 Tuesday"
aria-pressed="false" aria-pressed="false"
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
1 <span class="calendar__day-button__text">1</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -448,7 +448,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
2 <span class="calendar__day-button__text">2</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -458,7 +458,7 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
3 <span class="calendar__day-button__text">3</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell">
@ -468,17 +468,17 @@ export default html`
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
4 <span class="calendar__day-button__text">4</span>
</button> </button>
</td> </td>
<td class="calendar__day-cell" role="gridcell"> <td class="calendar__day-cell" role="gridcell" end-of-first-week>
<button <button
aria-label="5 January 2019 Saturday" aria-label="5 January 2019 Saturday"
aria-pressed="false" aria-pressed="false"
class="calendar__day-button" class="calendar__day-button"
tabindex="-1" tabindex="-1"
> >
5 <span class="calendar__day-button__text">5</span>
</button> </button>
</td> </td>
</tr> </tr>

View file

@ -1,4 +1,6 @@
export default { export default {
nextMonth: 'Следващ месец', nextMonth: 'Следващ месец',
previousMonth: 'Предишен месец', previousMonth: 'Предишен месец',
nextFullYear: 'Следващ година',
previousFullYear: 'Предишен година',
}; };

View file

@ -1,4 +1,6 @@
export default { export default {
nextMonth: 'Příští měsíc', nextMonth: 'Příští měsíc',
previousMonth: 'Předchozí měsíc', previousMonth: 'Předchozí měsíc',
nextFullYear: 'Příští rok',
previousFullYear: 'Předchozí rok',
}; };

View file

@ -1,4 +1,6 @@
export default { export default {
nextMonth: 'Nächster Monat', nextMonth: 'Nächster Monat',
previousMonth: 'Vorheriger Monat', previousMonth: 'Vorheriger Monat',
nextFullYear: 'Nächster Jahr',
previousFullYear: 'Vorheriger Jahr',
}; };

View file

@ -1,4 +1,6 @@
export default { export default {
nextMonth: 'Next month', nextMonth: 'Next month',
previousMonth: 'Previous month', previousMonth: 'Previous month',
nextFullYear: 'Next year',
previousFullYear: 'Previous year',
}; };

View file

@ -1,4 +1,6 @@
export default { export default {
nextMonth: 'Mes siguiente', nextMonth: 'Mes siguiente',
previousMonth: 'Mes anterior', previousMonth: 'Mes anterior',
nextFullYear: 'Año siguiente',
previousFullYear: 'Año anterior',
}; };

View file

@ -1,4 +1,6 @@
export default { export default {
nextMonth: 'Mois prochain', nextMonth: 'Mois prochain',
previousMonth: 'Mois précédent', previousMonth: 'Mois précédent',
nextFullYear: 'An prochain',
previousFullYear: 'An précédent',
}; };

View file

@ -1,4 +1,6 @@
export default { export default {
nextMonth: 'Következő hónap', nextMonth: 'Következő hónap',
previousMonth: 'Előző hónap', previousMonth: 'Előző hónap',
nextFullYear: 'Következő év',
previousFullYear: 'Előző év',
}; };

View file

@ -1,4 +1,6 @@
export default { export default {
nextMonth: 'Mese successivo', nextMonth: 'Mese successivo',
previousMonth: 'Mese precedente', previousMonth: 'Mese precedente',
nextFullYear: 'Anno successivo',
previousFullYear: 'Anno precedente',
}; };

View file

@ -1,4 +1,6 @@
export default { export default {
nextMonth: 'Volgende maand', nextMonth: 'Volgende maand',
previousMonth: 'Vorige maand', previousMonth: 'Vorige maand',
nextFullMonth: 'Volgend jaar',
previousFullMonth: 'Vorig jaar',
}; };

View file

@ -1,4 +1,6 @@
export default { export default {
nextMonth: 'Następny miesiąc', nextMonth: 'Następny miesiąc',
previousMonth: 'Poprzedni miesiąc', previousMonth: 'Poprzedni miesiąc',
nextFullYear: 'Następny rok',
previousFullYear: 'Poprzedni rok',
}; };

View file

@ -1,4 +1,6 @@
export default { export default {
nextMonth: 'Luna viitoare', nextMonth: 'Luna viitoare',
previousMonth: 'Luna anterioară', previousMonth: 'Luna anterioară',
nextFullYear: 'An viitoare',
previousFullYear: 'An anterioară',
}; };

View file

@ -1,4 +1,6 @@
export default { export default {
nextMonth: 'Следующий месяц', nextMonth: 'Следующий месяц',
previousMonth: 'Предыдущий месяц', previousMonth: 'Предыдущий месяц',
nextFullMonth: 'Следующий год',
previousFullMonth: 'Предыдущий год',
}; };

View file

@ -1,4 +1,6 @@
export default { export default {
nextMonth: 'Nasledujúci mesiac', nextMonth: 'Nasledujúci mesiac',
previousMonth: 'Predchádzajúci mesiac', previousMonth: 'Predchádzajúci mesiac',
nextFullYear: 'Nasledujúci rok',
previousFullYear: 'Predchádzajúci rok',
}; };

View file

@ -1,4 +1,6 @@
export default { export default {
nextMonth: 'Наступний місяць', nextMonth: 'Наступний місяць',
previousMonth: 'Попередній місяць', previousMonth: 'Попередній місяць',
nextFullYear: 'Наступний року',
previousFullYear: 'Попередній року',
}; };

View file

@ -1,4 +1,6 @@
export default { export default {
nextMonth: '下一个月', nextMonth: '下一个月',
previousMonth: '前一个月', previousMonth: '前一个月',
nextFullYear: '明一年',
previousFullYear: '前一年',
}; };