Skip to content
This repository has been archived by the owner on Sep 5, 2024. It is now read-only.

Commit

Permalink
feat(datepicker): fixes for a11y
Browse files Browse the repository at this point in the history
  • Loading branch information
jelbourn committed Aug 13, 2015
1 parent a1844f7 commit 6480d71
Show file tree
Hide file tree
Showing 7 changed files with 43 additions and 25 deletions.
4 changes: 2 additions & 2 deletions src/components/calendar/calendar-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
color: '{{primary-500}}'; // blue-500
}

.md-calendar-date:focus {
.md-calendar-date.md-focus {
.md-calendar-date-selection-indicator {
background-color: '{{background-300}}'; // grey-300
}
Expand All @@ -29,7 +29,7 @@

// Selected style goes after hover and focus so that it takes priority.
.md-calendar-date.md-calendar-selected-date,
.md-calendar-date:focus.md-calendar-selected-date {
.md-calendar-date.md-focus.md-calendar-selected-date {
.md-calendar-date-selection-indicator {
background-color: '{{primary-500}}'; // blue-500
color: '{{primary-500-contrast}}'; // white
Expand Down
15 changes: 12 additions & 3 deletions src/components/calendar/calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@


// PRE RELEASE
// TODO(jelbourn): Base colors on the theme
// TODO(jelbourn): read-only state.
// TODO(jelbourn): Date "isComplete" logic
// TODO(jelbourn): Apple + up / down == PgDown and PgUp
Expand Down Expand Up @@ -85,7 +84,7 @@
$$mdDateUtil, $$mdDateLocale, $mdInkRipple, $mdUtil) {

/** @type {Array<number>} Dummy array-like object for virtual-repeat to iterate over. */
this.items = {length: 2000 * 12};
this.items = {length: 2000};

/** @final {!angular.$animate} */
this.$animate = $animate;
Expand Down Expand Up @@ -120,6 +119,9 @@
/** @final {HTMLElement} */
this.ariaLiveElement = $element[0].querySelector('[aria-live]');

this.ariaLiveElement.parentNode.removeChild(this.ariaLiveElement);
document.body.appendChild(this.ariaLiveElement);

/** @final {HTMLElement} */
this.calendarScroller = $element[0].querySelector('.md-virtual-repeat-scroller');

Expand Down Expand Up @@ -347,11 +349,18 @@
* @param {Date=} opt_date
*/
CalendarCtrl.prototype.focus = function(opt_date) {
this.$element[0].focus();

var previousFocus = this.calendarElement.querySelector('.md-focus');
if (previousFocus) {
previousFocus.classList.remove('md-focus');
}

var date = opt_date || this.selectedDate;
var cellId = this.getDateId(date);
var cell = this.calendarElement.querySelector('#' + cellId);
if (cell) {
cell.focus();
cell.classList.add('md-focus');
} else {
this.focusDate = date;
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/calendar/calendarMonth.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
this.$element.empty();
this.$element.append(this.buildCalendarForMonth(date));
if (this.focusAfterAppend) {
this.focusAfterAppend.focus();
this.focusAfterAppend.classList.add('md-focus');
this.focusAfterAppend = null;
}
};
Expand Down
5 changes: 1 addition & 4 deletions src/components/calendar/datePicker-theme.scss
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
.md-datepicker-root.md-THEME_NAME-theme {
md-datepicker.md-THEME_NAME-theme {
background: white;
&[disabled] {
background: '{{background-100}}';
}
}

.md-datepicker-input-container {
Expand Down
20 changes: 11 additions & 9 deletions src/components/calendar/datePicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
// TODO(jelbourn): aria attributes tying together date input and floating calendar.
// TODO(jelbourn): make sure this plays well with validation and ngMessages.
// TODO(jelbourn): forward more attributes to the internal input (required, autofocus, etc.)
// TODO(jelbourn): floating panel open animation (see animation for menu in spec).
// TODO(jelbourn): auto-grow input to accomodate longer dates

// POST RELEASE
Expand All @@ -19,20 +18,24 @@


angular.module('material.components.calendar')
.directive('mdDatePicker', datePickerDirective);
.directive('mdDatepicker', datePickerDirective);

function datePickerDirective() {
return {
template:
// Buttons are not in the tab order because users can open the calendar via keyboard
// interaction on the text input, and multiple tab stops for one component (picker)
// may be confusing.
'<md-button class="md-datepicker-button md-icon-button" type="button" ' +
'tabindex="-1" aria-label="Open calendar" ' +
'ng-click="ctrl.openCalendarPane()">' +
'<md-icon class="md-datepicker-calendar-icon" md-svg-icon="md-calendar"></md-icon>' +
'</md-button>' +
'<div class="md-datepicker-input-container">' +
'<input class="md-datepicker-input">' +

'<md-button md-no-ink class="md-datepicker-triangle-button md-icon-button" ' +
'ng-click="ctrl.openCalendarPane()">' +
'ng-click="ctrl.openCalendarPane()" tabindex="-1" aria-label="Open calendar">' +
'<div class="md-datepicker-expand-triangle"></div>' +
'</md-button>' +
'</div>' +
Expand All @@ -41,10 +44,11 @@
'<div class="md-datepicker-calendar-pane md-whiteframe-z1">' +
'<div class="md-datepicker-input-mask"></div>' +
'<div class="md-datepicker-calendar">' +
'<md-calendar ng-model="ctrl.date" ng-if="ctrl.isCalendarOpen"></md-calendar>' +
'<md-calendar role="dialog" aria-label="Calendar" tabindex="0" ' +
'ng-model="ctrl.date" ng-if="ctrl.isCalendarOpen"></md-calendar>' +
'</div>' +
'</div>',
require: ['ngModel', 'mdDatePicker'],
require: ['ngModel', 'mdDatepicker'],
scope: {
placeholder: '@mdPlaceholder'
},
Expand All @@ -69,7 +73,7 @@
* @ngInject @constructor
*/
function DatePickerCtrl($scope, $element, $attrs, $compile, $timeout, $mdConstant, $mdUtil,
$$mdDateLocale, $$mdDateUtil, $mdMenu, $$rAF) {
$$mdDateLocale, $$mdDateUtil, $$rAF) {
/** @final */
this.$compile = $compile;

Expand All @@ -89,8 +93,6 @@
this.$mdUtil = $mdUtil;

/** @final */
this.$mdMenu = $mdMenu;

this.$$rAF = $$rAF;

/** @type {!angular.NgModelController} */
Expand Down Expand Up @@ -250,7 +252,7 @@
calendarPane.style.top = (elementRect.top - bodyRect.top) + 'px';
document.body.appendChild(this.calendarPane);

// Add CSS class after one frame to trigger animation.
// Add CSS class after one frame to trigger open animation.
this.$$rAF(function() {
calendarPane.classList.add('md-pane-open');
});
Expand Down
14 changes: 12 additions & 2 deletions src/components/calendar/datePicker.scss
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,25 @@ $md-datepicker-button-gap: 12px;
// The input into which the user can type the date.
.md-datepicker-input {
@include md-flat-input();
width: 100%;
min-width: 100%;
}

// Container for the datepicker input.
.md-datepicker-input-container {
// Position relative in order to absolutely position the down-triangle button within.
position: relative;

padding-bottom: 5px;
border-bottom-width: 1px;
border-bottom-style: solid;

display: inline-block;
width: 120px;
margin-left: $md-datepicker-button-gap;

md-datepicker[disabled] & {
border-bottom-color: transparent;
}
}


Expand Down Expand Up @@ -89,7 +95,7 @@ $md-datepicker-button-gap: 12px;
// Down triangle/arrow indicating that the datepicker can be opened.
// We can do this entirely with CSS without needing to load an icon.
// See https://css-tricks.com/snippets/css/css-triangle/
$md-date-arrow-size: 6px;
$md-date-arrow-size: 5px;
.md-datepicker-expand-triangle {
// Center the triangle inside of the button so that the
// ink ripple origin looks correct.
Expand All @@ -111,6 +117,10 @@ $md-date-arrow-size: 6px;
right: 0;
top: 0;
transform: translateY(-25%) translateX(45%);

md-datepicker[disabled] & {
display: none;
}
}

// Need crazy specificity to override .md-button.md-icon-button.
Expand Down
8 changes: 4 additions & 4 deletions src/components/calendar/demoDatePicker/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ <h2>Development tools</h2>
</p>
<hr>

<md-date-picker ng-model="myDate" md-placeholder="Enter date"></md-date-picker>
<md-datepicker ng-model="myDate" md-placeholder="Enter date"></md-datepicker>

<hr>
<h3>Disabled with ng-disabled</h3>
<md-date-picker ng-model="myDate" md-placeholder="Enter date" ng-disabled="true">
</md-date-picker>
<md-datepicker ng-model="myDate" md-placeholder="Enter date" ng-disabled="true">
</md-datepicker>

<hr>

<h3>Disabled with static disabled attribute</h3>
<md-date-picker ng-model="myDate" placeholder="Enter date" disabled></md-date-picker>
<md-datepicker ng-model="myDate" placeholder="Enter date" disabled></md-datepicker>

<br><br>
<br><br>
Expand Down

0 comments on commit 6480d71

Please sign in to comment.