Skip to content

Commit

Permalink
feat(material-experimental/chip): add focus indicators (#18261)
Browse files Browse the repository at this point in the history
  • Loading branch information
zelliott authored and mmalerba committed Feb 4, 2020
1 parent 64fe5ce commit 4f06a8b
Show file tree
Hide file tree
Showing 14 changed files with 125 additions and 74 deletions.
8 changes: 8 additions & 0 deletions src/material-experimental/mdc-chips/chip-grid.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,14 @@ describe('MDC-based MatChipGrid', () => {
expect(chipGridInstance._keyManager.activeColumnIndex).toBe(0);
}));
});

it('should have a focus indicator', () => {
const focusableTextNativeElements = Array.from(chipGridNativeElement
.querySelectorAll('.mat-chip-row-focusable-text-content'));

expect(focusableTextNativeElements
.every(element => element.classList.contains('mat-mdc-focus-indicator'))).toBe(true);
});
});

describe('keyboard behavior', () => {
Expand Down
4 changes: 2 additions & 2 deletions src/material-experimental/mdc-chips/chip-icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ const _MatChipRemoveMixinBase:
selector: '[matChipRemove]',
inputs: ['disabled', 'tabIndex'],
host: {
'class':
'mat-mdc-chip-remove mat-mdc-chip-trailing-icon mdc-chip__icon mdc-chip__icon--trailing',
'class': `mat-mdc-chip-remove mat-mdc-chip-trailing-icon mat-mdc-focus-indicator
mdc-chip__icon mdc-chip__icon--trailing`,
'[tabIndex]': 'tabIndex',
'role': 'button',
'(click)': 'interaction.next($event)',
Expand Down
7 changes: 7 additions & 0 deletions src/material-experimental/mdc-chips/chip-option.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
<span class="mdc-chip__ripple"></span>

<span matRipple class="mat-mdc-chip-ripple"
[matRippleAnimation]="_rippleAnimation"
[matRippleDisabled]="_isRippleDisabled()"
[matRippleCentered]="_isRippleCentered"
[matRippleTrigger]="_elementRef.nativeElement"></span>

<ng-content select="mat-chip-avatar, [matChipAvatar]"></ng-content>
<div class="mdc-chip__checkmark" *ngIf="_chipListMultiple">
<svg class="mdc-chip__checkmark-svg" viewBox="-2 -3 30 30">
Expand Down
8 changes: 4 additions & 4 deletions src/material-experimental/mdc-chips/chip-option.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {SPACE} from '@angular/cdk/keycodes';
import {createKeyboardEvent, dispatchFakeEvent} from '@angular/cdk/testing/private';
import {Component, DebugElement, ViewChild} from '@angular/core';
import {async, ComponentFixture, fakeAsync, flush, TestBed} from '@angular/core/testing';
import {MAT_RIPPLE_GLOBAL_OPTIONS, RippleGlobalOptions} from '@angular/material/core';
import {By} from '@angular/platform-browser';
import {chipCssClasses} from '@material/chips';
import {Subject} from 'rxjs';
Expand All @@ -21,17 +20,14 @@ describe('MDC-based Option Chips', () => {
let chipDebugElement: DebugElement;
let chipNativeElement: HTMLElement;
let chipInstance: MatChipOption;
let globalRippleOptions: RippleGlobalOptions;

let dir = 'ltr';

beforeEach(async(() => {
globalRippleOptions = {};
TestBed.configureTestingModule({
imports: [MatChipsModule],
declarations: [SingleChip],
providers: [
{provide: MAT_RIPPLE_GLOBAL_OPTIONS, useFactory: () => globalRippleOptions},
{provide: Directionality, useFactory: () => ({
value: dir,
change: new Subject()
Expand Down Expand Up @@ -286,6 +282,10 @@ describe('MDC-based Option Chips', () => {
const avatar = fixture.nativeElement.querySelector('.avatar');
expect(avatar.classList).toContain(chipCssClasses.HIDDEN_LEADING_ICON);
});

it('should have a focus indicator', () => {
expect(chipNativeElement.classList.contains('mat-mdc-focus-indicator')).toBe(true);
});
});
});

Expand Down
1 change: 1 addition & 0 deletions src/material-experimental/mdc-chips/chip-option.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export class MatChipSelectionChange {
inputs: ['color', 'disableRipple', 'tabIndex'],
host: {
'role': 'option',
'class': 'mat-mdc-focus-indicator',
'[class.mat-mdc-chip-disabled]': 'disabled',
'[class.mat-mdc-chip-highlighted]': 'highlighted',
'[class.mat-mdc-chip-with-avatar]': 'leadingIcon',
Expand Down
5 changes: 5 additions & 0 deletions src/material-experimental/mdc-chips/chip-remove.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,11 @@ describe('MDC-based Chip Remove', () => {
expect(event.defaultPrevented).toBe(false);
});

it('should have a focus indicator', () => {
const buttonElement = chipNativeElement.querySelector('button')!;

expect(buttonElement.classList.contains('mat-mdc-focus-indicator')).toBe(true);
});
});
});

Expand Down
12 changes: 10 additions & 2 deletions src/material-experimental/mdc-chips/chip-row.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
<span class="mdc-chip__ripple"></span>

<span matRipple class="mat-mdc-chip-ripple"
[matRippleAnimation]="_rippleAnimation"
[matRippleDisabled]="_isRippleDisabled()"
[matRippleCentered]="_isRippleCentered"
[matRippleTrigger]="_elementRef.nativeElement"></span>

<div role="gridcell">
<div #chipContent tabindex="-1" class="mat-chip-row-focusable-text-content">
<span class="mdc-chip__ripple"></span>
<div #chipContent tabindex="-1"
class="mat-chip-row-focusable-text-content mat-mdc-focus-indicator">
<ng-content select="mat-chip-avatar, [matChipAvatar]"></ng-content>
<span class="mdc-chip__text"><ng-content></ng-content></span>
<ng-content select="mat-chip-trailing-icon,[matChipTrailingIcon]"></ng-content>
Expand Down
4 changes: 0 additions & 4 deletions src/material-experimental/mdc-chips/chip-row.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
} from '@angular/cdk/testing/private';
import {Component, DebugElement, ViewChild} from '@angular/core';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {MAT_RIPPLE_GLOBAL_OPTIONS, RippleGlobalOptions} from '@angular/material/core';
import {By} from '@angular/platform-browser';
import {Subject} from 'rxjs';
import {MatChipEvent, MatChipGrid, MatChipRow, MatChipsModule} from './index';
Expand All @@ -18,17 +17,14 @@ describe('MDC-based Row Chips', () => {
let chipDebugElement: DebugElement;
let chipNativeElement: HTMLElement;
let chipInstance: MatChipRow;
let globalRippleOptions: RippleGlobalOptions;

let dir = 'ltr';

beforeEach(async(() => {
globalRippleOptions = {};
TestBed.configureTestingModule({
imports: [MatChipsModule],
declarations: [SingleChip],
providers: [
{provide: MAT_RIPPLE_GLOBAL_OPTIONS, useFactory: () => globalRippleOptions},
{provide: Directionality, useFactory: () => ({
value: dir,
change: new Subject()
Expand Down
7 changes: 7 additions & 0 deletions src/material-experimental/mdc-chips/chip.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
<span class="mdc-chip__ripple"></span>

<span matRipple class="mat-mdc-chip-ripple"
[matRippleAnimation]="_rippleAnimation"
[matRippleDisabled]="_isRippleDisabled()"
[matRippleCentered]="_isRippleCentered"
[matRippleTrigger]="_elementRef.nativeElement"></span>

<ng-content select="mat-chip-avatar, [matChipAvatar]"></ng-content>
<div class="mdc-chip__text mdc-chip__action--primary"><ng-content></ng-content></div>
<ng-content select="mat-chip-trailing-icon,[matChipRemove],[matChipTrailingIcon]"></ng-content>
39 changes: 30 additions & 9 deletions src/material-experimental/mdc-chips/chip.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {Directionality} from '@angular/cdk/bidi';
import {createFakeEvent} from '@angular/cdk/testing/private';
import {Component, DebugElement, ViewChild} from '@angular/core';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {MAT_RIPPLE_GLOBAL_OPTIONS, RippleGlobalOptions} from '@angular/material/core';
import {MatRipple} from '@angular/material/core';
import {By} from '@angular/platform-browser';
import {Subject} from 'rxjs';
import {MatChip, MatChipEvent, MatChipSet, MatChipsModule} from './index';
Expand All @@ -13,12 +13,12 @@ describe('MDC-based MatChip', () => {
let chipDebugElement: DebugElement;
let chipNativeElement: HTMLElement;
let chipInstance: MatChip;
let globalRippleOptions: RippleGlobalOptions;
let chipRippleDebugElement: DebugElement;
let chipRippleInstance: MatRipple;

let dir = 'ltr';

beforeEach(async(() => {
globalRippleOptions = {};
TestBed.configureTestingModule({
imports: [MatChipsModule],
declarations: [
Expand All @@ -28,7 +28,6 @@ describe('MDC-based MatChip', () => {
BasicChipWithBoundTabindex,
],
providers: [
{provide: MAT_RIPPLE_GLOBAL_OPTIONS, useFactory: () => globalRippleOptions},
{provide: Directionality, useFactory: () => ({
value: dir,
change: new Subject()
Expand Down Expand Up @@ -76,6 +75,15 @@ describe('MDC-based MatChip', () => {

expect(chip.getAttribute('tabindex')).toBe('15');
});

it('should have its ripple disabled', () => {
fixture = TestBed.createComponent(BasicChip);
fixture.detectChanges();
chipDebugElement = fixture.debugElement.query(By.directive(MatChip))!;
chipRippleDebugElement = chipDebugElement.query(By.directive(MatRipple))!;
chipRippleInstance = chipRippleDebugElement.injector.get<MatRipple>(MatRipple);
expect(chipRippleInstance.disabled).toBe(true, 'Expected basic chip ripples to be disabled.');
});
});

describe('MatChip', () => {
Expand All @@ -88,6 +96,8 @@ describe('MDC-based MatChip', () => {
chipDebugElement = fixture.debugElement.query(By.directive(MatChip))!;
chipNativeElement = chipDebugElement.nativeElement;
chipInstance = chipDebugElement.injector.get<MatChip>(MatChip);
chipRippleDebugElement = chipDebugElement.query(By.directive(MatRipple))!;
chipRippleInstance = chipRippleDebugElement.injector.get<MatRipple>(MatRipple);
testComponent = fixture.debugElement.componentInstance;
});

Expand Down Expand Up @@ -143,12 +153,22 @@ describe('MDC-based MatChip', () => {
expect(chipNativeElement.style.display).toBe('none');
});

it('should be able to disable ripples through ripple global options at runtime', () => {
expect(chipInstance.rippleDisabled).toBe(false, 'Expected chip ripples to be enabled.');
it('should be able to disable ripples with the `[rippleDisabled]` input', () => {
expect(chipRippleInstance.disabled).toBe(false, 'Expected chip ripples to be enabled.');

testComponent.rippleDisabled = true;
fixture.detectChanges();

expect(chipRippleInstance.disabled).toBe(true, 'Expected chip ripples to be disabled.');
});

it('should disable ripples when the chip is disabled', () => {
expect(chipRippleInstance.disabled).toBe(false, 'Expected chip ripples to be enabled.');

globalRippleOptions.disabled = true;
testComponent.disabled = true;
fixture.detectChanges();

expect(chipInstance.rippleDisabled).toBe(true, 'Expected chip ripples to be disabled.');
expect(chipRippleInstance.disabled).toBe(true, 'Expected chip ripples to be disabled.');
});

it('should update the aria-label for disabled chips', () => {
Expand Down Expand Up @@ -191,7 +211,7 @@ describe('MDC-based MatChip', () => {
<mat-chip [removable]="removable"
[color]="color" [disabled]="disabled"
(focus)="chipFocus($event)" (destroyed)="chipDestroy($event)"
(removed)="chipRemove($event)" [value]="value">
(removed)="chipRemove($event)" [value]="value" [disableRipple]="rippleDisabled">
{{name}}
</mat-chip>
</div>
Expand All @@ -205,6 +225,7 @@ class SingleChip {
removable: boolean = true;
shouldShow: boolean = true;
value: any;
rippleDisabled: boolean = false;

chipFocus: (event?: MatChipEvent) => void = () => {};
chipDestroy: (event?: MatChipEvent) => void = () => {};
Expand Down
Loading

0 comments on commit 4f06a8b

Please sign in to comment.