fix(datetime): add keyboard year navigation (#23585)

resolves #21553 
resolves #18122
This commit is contained in:
William Martin
2021-07-06 15:56:50 -04:00
committed by GitHub
parent 4188964dc8
commit 55bd1f749b
4 changed files with 99 additions and 2 deletions

View File

@ -39,9 +39,11 @@ import {
getNextDay,
getNextMonth,
getNextWeek,
getNextYear,
getPreviousDay,
getPreviousMonth,
getPreviousWeek,
getPreviousYear,
getStartOfWeek
} from './utils/manipulation';
import {
@ -488,11 +490,11 @@ export class Datetime implements ComponentInterface {
break;
case 'PageUp':
ev.preventDefault();
partsToFocus = getPreviousMonth(parts);
partsToFocus = ev.shiftKey ? getPreviousYear(parts) : getPreviousMonth(parts);
break;
case 'PageDown':
ev.preventDefault();
partsToFocus = getNextMonth(parts);
partsToFocus = ev.shiftKey ? getNextYear(parts) : getNextMonth(parts);
break;
/**
* Do not preventDefault here

View File

@ -109,6 +109,33 @@ subtracting 30 minutes, etc.), or even formatting data to a specific locale,
then we highly recommend using [date-fns](https://date-fns.org) to work with
dates in JavaScript.
## Accessibility
### Keyboard Navigation
`ion-datetime` has full keyboard support for navigating between focusable elements inside of the component. The following table details what each key does:
| Key | Function |
| ------------------ | ------------------------------------------------------------ |
| `Tab` | Moves focus to the next focusable element. |
| `Shift` + `Tab` | Moves focus to the previous focusable element. |
| `Space` or `Enter` | Clicks the focusable element. |
#### Date Grid
| Key | Function |
| ------------------ | ------------------------------------------------------------ |
| `ArrowUp` | Moves focus to the same day of the previous week. |
| `ArrowDown` | Moves focus to the same day of the next week. |
| `ArrowRight` | Moves focus to the next day. |
| `ArrowLeft` | Moves focus to the previous day. |
| `Home` | Moves focus to the first day of the current week. |
| `End` | Moves focus to the last day of the current week. |
| `PageUp` | Changes the grid of dates to the previous month. |
| `PageDown` | Changes the grid of dates to the next month. |
| `Shift` + `PageUp` | Changes the grid of dates to the previous year. |
| `Shift` + `PageDown` | Changes the grid of dates to the next year. |
<!-- Auto Generated Below -->

View File

@ -1,4 +1,6 @@
import {
getPreviousYear,
getNextYear,
getPreviousMonth,
getNextMonth,
getPreviousDay,
@ -388,3 +390,45 @@ describe('getPreviousMonth()', () => {
});
});
});
describe('getNextYear()', () => {
it('should return correct next year', () => {
expect(getNextYear({ month: 5, year: 2021, day: 1 })).toEqual({
month: 5,
year: 2022,
day: 1
});
expect(getNextYear({ month: 12, year: 1999, day: 30 })).toEqual({
month: 12,
year: 2000,
day: 30
});
// Leap year
expect(getNextYear({ month: 2, year: 2024, day: 29 })).toEqual({
month: 2,
year: 2025,
day: 28
});
});
});
describe('getPreviousYear()', () => {
it('should return correct next year', () => {
expect(getPreviousYear({ month: 5, year: 2021, day: 1 })).toEqual({
month: 5,
year: 2020,
day: 1
});
expect(getPreviousYear({ month: 12, year: 1999, day: 30 })).toEqual({
month: 12,
year: 1998,
day: 30
});
// Leap year
expect(getPreviousYear({ month: 2, year: 2024, day: 29 })).toEqual({
month: 2,
year: 2023,
day: 28
});
});
});

View File

@ -256,6 +256,30 @@ export const getNextMonth = (refParts: DatetimeParts) => {
return { month, year, day };
}
const changeYear = (refParts: DatetimeParts, yearDelta: number) => {
const month = refParts.month;
const year = refParts.year + yearDelta;
const numDaysInMonth = getNumDaysInMonth(month, year);
const day = (numDaysInMonth < refParts.day!) ? numDaysInMonth : refParts.day;
return { month, year, day }
}
/**
* Given DatetimeParts, generate the previous year.
*/
export const getPreviousYear = (refParts: DatetimeParts) => {
return changeYear(refParts, -1);
}
/**
* Given DatetimeParts, generate the next year.
*/
export const getNextYear = (refParts: DatetimeParts) => {
return changeYear(refParts, 1);
}
/**
* If PM, then internal value should
* be converted to 24-hr time.