Skip to content
This repository has been archived by the owner on Aug 29, 2023. It is now read-only.

Commit

Permalink
fix(): switch focus on keyboard, use .md-focused
Browse files Browse the repository at this point in the history
Updates button, checkbox and radio to only show focus on keyboard interaction using the .md-focused class

Closes #1336. Closes #2273.
  • Loading branch information
Marcy Sutton authored and ThomasBurleson committed Apr 13, 2015
1 parent 48eeb62 commit 0e916bf
Show file tree
Hide file tree
Showing 24 changed files with 237 additions and 58 deletions.
Binary file added docs/app/img/100-0.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/app/img/100-1.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/app/img/100-2.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions src/components/button/button.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ function MdButtonDirective($mdInkRipple, $mdTheming, $mdAria, $timeout) {
}, 100);
})
.on('focus', function() {
if(scope.mouseActive === false) element.addClass('focus');
if(scope.mouseActive === false) { element.addClass('md-focused'); }
})
.on('blur', function() { element.removeClass('focus'); });
.on('blur', function() { element.removeClass('md-focused'); });
}

}
Expand Down
7 changes: 3 additions & 4 deletions src/components/button/button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ $icon-button-margin: 0.600rem !default;
&:not([disabled]) {
&.md-raised,
&.md-fab {
&:focus {
&.md-focused {
@extend .md-shadow-bottom-z-1;
}
&:active {
Expand All @@ -165,7 +165,7 @@ $icon-button-margin: 0.600rem !default;
.md-button.md-fab-top-right {
transform: translate3d(0, $button-fab-toast-offset, 0);
&:not([disabled]) {
&.focus,
&.md-focused,
&:hover {
transform: translate3d(0, $button-fab-toast-offset - 1, 0);
}
Expand All @@ -177,15 +177,14 @@ $icon-button-margin: 0.600rem !default;
.md-button.md-fab-bottom-right {
transform: translate3d(0, -$button-fab-toast-offset, 0);
&:not([disabled]) {
&.focus,
&.md-focused,
&:hover {
transform: translate3d(0, -$button-fab-toast-offset - 1, 0);
}
}
}
}


.md-button-group {
display: flex;
flex: 1;
Expand Down
6 changes: 3 additions & 3 deletions src/components/button/button.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,16 @@ describe('md-button', function() {
var button = $compile('<md-button>')($rootScope.$new());
$rootScope.$apply();
button.triggerHandler('mousedown');
expect(button[0]).not.toHaveClass('focus');
expect(button[0]).not.toHaveClass('md-focused');
}));

it('should set focus state on focus and remove on blur', inject(function ($compile, $rootScope){
var button = $compile('<md-button>')($rootScope.$new());
$rootScope.$apply();
button.triggerHandler('focus');
expect(button[0]).toHaveClass('focus');
expect(button[0]).toHaveClass('md-focused');
button.triggerHandler('blur');
expect(button[0]).not.toHaveClass('focus');
expect(button[0]).not.toHaveClass('md-focused');
}));

describe('with href or ng-href', function() {
Expand Down
12 changes: 10 additions & 2 deletions src/components/checkbox/checkbox-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ md-checkbox.md-THEME_NAME-theme {
&.md-checked .md-ripple {
color: '{{background-600}}';
}
&.md-checked.md-focused .md-container:before {
background-color: '{{accent-color-0.26}}';
}

.md-icon {
border-color: '{{foreground-2}}';
Expand Down Expand Up @@ -34,6 +37,10 @@ md-checkbox.md-THEME_NAME-theme {
background-color: '{{primary-color-0.87}}';
}

&.md-checked.md-focused .md-container:before {
background-color: '{{primary-color-0.26}}';
}

&.md-checked .md-icon:after {
border-color: '{{background-200}}';
}
Expand All @@ -43,14 +50,15 @@ md-checkbox.md-THEME_NAME-theme {
.md-ripple {
color: '{{warn-600}}';
}

.md-icon {
border-color: '{{foreground-2}}';
}
&.md-checked .md-icon {
background-color: '{{warn-color-0.87}}';
}

&.md-checked.md-focused:not([disabled]) .md-container:before {
background-color: '{{warn-color-0.26}}';
}
&.md-checked .md-icon:after {
border-color: '{{background-200}}';
}
Expand Down
23 changes: 19 additions & 4 deletions src/components/checkbox/checkbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ angular
* </hljs>
*
*/
function MdCheckboxDirective(inputDirective, $mdInkRipple, $mdAria, $mdConstant, $mdTheming, $mdUtil) {
function MdCheckboxDirective(inputDirective, $mdInkRipple, $mdAria, $mdConstant, $mdTheming, $mdUtil, $timeout) {
inputDirective = inputDirective[0];
var CHECKED_CSS = 'md-checked';

Expand Down Expand Up @@ -96,13 +96,28 @@ function MdCheckboxDirective(inputDirective, $mdInkRipple, $mdAria, $mdConstant,
0: {}
}, attr, [ngModelCtrl]);

element.on('click', listener)
.on('keypress', keypressHandler);
scope.mouseActive = false;
element
.on('click', listener)
.on('keypress', keypressHandler)
.on('mousedown', function() {
scope.mouseActive = true;
$timeout(function(){
scope.mouseActive = false;
}, 100);
})
.on('focus', function() {
if(scope.mouseActive === false) { element.addClass('md-focused'); }
})
.on('blur', function() { element.removeClass('md-focused'); });

ngModelCtrl.$render = render;

function keypressHandler(ev) {
if(ev.which === $mdConstant.KEY_CODE.SPACE || ev.which === $mdConstant.KEY_CODE.ENTER) {
var keyCode = ev.which || ev.keyCode;
if (keyCode === $mdConstant.KEY_CODE.SPACE || keyCode === $mdConstant.KEY_CODE.ENTER) {
ev.preventDefault();
if (!element.hasClass('md-focused')) { element.addClass('md-focused'); }
listener(ev);
}
}
Expand Down
35 changes: 30 additions & 5 deletions src/components/checkbox/checkbox.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,43 @@ md-checkbox {
box-sizing: border-box;
}

&.md-focused:not([disabled]) {
.md-container:before {
left: -8px;
top: -8px;
right: -8px;
bottom: -8px;
}

&:not(.md-checked) {
.md-container:before {
background-color: rgba(0, 0, 0, 0.12);
}
}
}

.md-container {
position: relative;
top: 4px;
display: inline-block;
width: $checkbox-width;
height: $checkbox-height;

&:before {
background-color: transparent;
border-radius: 50%;
content: '';
position: absolute;
display: block;
height: auto;
left: 0;
top: 0;
right: 0;
bottom: 0;
transition: all 0.5s;
width: auto;
}

&:after {
content: '';
position: absolute;
Expand Down Expand Up @@ -65,11 +95,6 @@ md-checkbox {
cursor: no-drop;
}

// focus
&:focus .md-label:not(:empty) {
border-color: black;
}


&.md-checked .md-icon:after {
transform: rotate(45deg);
Expand Down
25 changes: 25 additions & 0 deletions src/components/checkbox/checkbox.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,33 @@ describe('mdCheckbox', function() {

checkbox.triggerHandler('click');
expect($rootScope.blue).toBe(true);
}));

it('should not set focus state on mousedown', inject(function($compile, $rootScope) {
var checkbox = $compile('<md-checkbox ng-model="blue">')($rootScope.$new());
$rootScope.$apply();
checkbox.triggerHandler('mousedown');
expect(checkbox[0]).not.toHaveClass('md-focused');
}));

it('should set focus state on focus and remove on blur', inject(function($compile, $rootScope) {
var checkbox = $compile('<md-checkbox ng-model="blue">')($rootScope.$new());
$rootScope.$apply();
checkbox.triggerHandler('focus');
expect(checkbox[0]).toHaveClass('md-focused');
checkbox.triggerHandler('blur');
expect(checkbox[0]).not.toHaveClass('md-focused');
}));

it('should set focus state on keyboard interaction after clicking', inject(function($compile, $rootScope, $mdConstant) {
var checkbox = $compile('<md-checkbox ng-model="blue">')($rootScope.$new());
$rootScope.$apply();
checkbox.triggerHandler('mousedown');
checkbox.triggerHandler({
type: 'keypress',
keyCode: $mdConstant.KEY_CODE.SPACE
});
expect(checkbox[0]).toHaveClass('md-focused');
}));

describe('ng core checkbox tests', function() {
Expand Down
2 changes: 1 addition & 1 deletion src/components/list/demoListControls/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<md-divider></md-divider>
<md-subheader class="md-no-sticky">Avatar with Secondary Action Icon</md-subheader>
<md-list-item ng-repeat="person in people" ng-click="goToPerson(person.name)">
<img alt="avatar" src="http://lorempixel.com/100/100/people/?{{$index}}" class="md-avatar" />
<img alt="{{ person.name }" ng-src="{{ person.img }}" class="md-avatar" />
<p>{{ person.name }}</p>
<md-icon md-svg-icon="communication:messenger" ng-click="doSecondaryAction()" aria-label="Open Chat" class="md-secondary md-hue-3" ng-class="{'md-primary': person.newMessage}"></md-icon>
</md-list-item>
Expand Down
8 changes: 3 additions & 5 deletions src/components/list/demoListControls/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,10 @@ angular.module('listDemo2', ['ngMaterial'])
{id: 3, title: "Message C", selected: true},
];



$scope.people = [
{ name: 'Janet Perkins', newMessage: true },
{ name: 'Mary Johnson', newMessage: false },
{ name: 'Peter Carlsson', newMessage: false }
{ name: 'Janet Perkins', img: 'img/100-0.jpeg', newMessage: true },
{ name: 'Mary Johnson', img: 'img/100-1.jpeg', newMessage: false },
{ name: 'Peter Carlsson', img: 'img/100-2.jpeg', newMessage: false }
];

$scope.goToPerson = function(person) {
Expand Down
Binary file added src/components/list/img/100-0.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/components/list/img/100-1.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/components/list/img/100-2.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion src/components/list/list-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ md-list.md-THEME_NAME-theme {
}
}
.md-proxy-focus.md-focused div.md-no-style,
.md-secondary:focus,
.md-no-style:focus {
background-color: '{{background-100}}';
}
Expand Down
12 changes: 10 additions & 2 deletions src/components/radioButton/radio-button-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ md-radio-button.md-THEME_NAME-theme {
}


md-radio-group.md-THEME_NAME-theme:focus:not(:empty) {
border-color: '{{foreground-1}}';
md-radio-group.md-THEME_NAME-theme.md-focused:not(:empty) {
.md-checked .md-container:before {
background-color: '{{accent-color-0.26}}';
}
.md-checked:not([disabled]).md-primary .md-container:before {
background-color: '{{primary-color-0.26}}';
}
.md-checked.md-primary .md-container:before {
background-color: '{{warn-color-0.26}}';
}
}
34 changes: 26 additions & 8 deletions src/components/radioButton/radio-button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,21 @@ md-radio-button,
left: -$radio-width;
top: -$radio-width;
}

&:before {
background-color: transparent;
border-radius: 50%;
content: '';
position: absolute;
display: block;
height: auto;
left: 0;
top: 0;
right: 0;
bottom: 0;
transition: all 0.5s;
width: auto;
}
}


Expand Down Expand Up @@ -81,14 +96,17 @@ md-radio-button,

}
md-radio-group {
border: 1px dotted transparent;
display: block;
outline: none;
}


.radioButtondemoBasicUsage md-radio-group {
border: none;
&:focus {
outline: none;
}
&.md-focused {
.md-checked .md-container:before {
left: -8px;
top: -8px;
right: -8px;
bottom: -8px;
}
}
}

@media screen and (-ms-high-contrast: active) {
Expand Down
25 changes: 21 additions & 4 deletions src/components/radioButton/radioButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ angular.module('material.components.radioButton', [
* </hljs>
*
*/
function mdRadioGroupDirective($mdUtil, $mdConstant, $mdTheming) {
function mdRadioGroupDirective($mdUtil, $mdConstant, $mdTheming, $timeout) {
RadioGroupController.prototype = createRadioGroupControllerProto();

return {
Expand All @@ -68,18 +68,25 @@ function mdRadioGroupDirective($mdUtil, $mdConstant, $mdTheming) {
var rgCtrl = ctrls[0];
var ngModelCtrl = ctrls[1] || $mdUtil.fakeNgModel();

function setFocus() {
if (!element.hasClass('md-focused')) { element.addClass('md-focused'); }
}

function keydownListener(ev) {
switch(ev.keyCode) {
var keyCode = ev.which || ev.keyCode;
switch(keyCode) {
case $mdConstant.KEY_CODE.LEFT_ARROW:
case $mdConstant.KEY_CODE.UP_ARROW:
ev.preventDefault();
rgCtrl.selectPrevious();
setFocus();
break;

case $mdConstant.KEY_CODE.RIGHT_ARROW:
case $mdConstant.KEY_CODE.DOWN_ARROW:
ev.preventDefault();
rgCtrl.selectNext();
setFocus();
break;

case $mdConstant.KEY_CODE.ENTER:
Expand All @@ -93,12 +100,22 @@ function mdRadioGroupDirective($mdUtil, $mdConstant, $mdTheming) {

rgCtrl.init(ngModelCtrl);

scope.mouseActive = false;
element.attr({
'role': 'radiogroup',
'tabIndex': element.attr('tabindex') || '0'
})
.on('keydown', keydownListener);

.on('keydown', keydownListener)
.on('mousedown', function(event) {
scope.mouseActive = true;
$timeout(function() {
scope.mouseActive = false;
}, 100);
})
.on('focus', function() {
if(scope.mouseActive === false) { rgCtrl.$element.addClass('md-focused'); }
})
.on('blur', function() { rgCtrl.$element.removeClass('md-focused'); });
}

function RadioGroupController($element) {
Expand Down
Loading

0 comments on commit 0e916bf

Please sign in to comment.