Skip to content

Commit a5e13e2

Browse files
zelliottjelbourn
authored andcommitted
feat(material-experimental/chip): add focus indicators (#18261)
1 parent e06d269 commit a5e13e2

File tree

14 files changed

+122
-75
lines changed

14 files changed

+122
-75
lines changed

src/material-experimental/mdc-chips/chip-grid.spec.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,14 @@ describe('MDC-based MatChipGrid', () => {
239239
expect(chipGridInstance._keyManager.activeColumnIndex).toBe(0);
240240
}));
241241
});
242+
243+
it('should have a focus indicator', () => {
244+
const focusableTextNativeElements = Array.from(chipGridNativeElement
245+
.querySelectorAll('.mat-chip-row-focusable-text-content'));
246+
247+
expect(focusableTextNativeElements
248+
.every(element => element.classList.contains('mat-mdc-focus-indicator'))).toBe(true);
249+
});
242250
});
243251

244252
describe('keyboard behavior', () => {

src/material-experimental/mdc-chips/chip-icons.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ const _MatChipRemoveMixinBase:
105105
selector: '[matChipRemove]',
106106
inputs: ['disabled', 'tabIndex'],
107107
host: {
108-
'class':
109-
'mat-mdc-chip-remove mat-mdc-chip-trailing-icon mdc-chip__icon mdc-chip__icon--trailing',
108+
'class': `mat-mdc-chip-remove mat-mdc-chip-trailing-icon mat-mdc-focus-indicator
109+
mdc-chip__icon mdc-chip__icon--trailing`,
110110
'[tabIndex]': 'tabIndex',
111111
'role': 'button',
112112
'(click)': 'interaction.next($event)',

src/material-experimental/mdc-chips/chip-option.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
<span class="mdc-chip__ripple"></span>
2+
3+
<span matRipple class="mat-mdc-chip-ripple"
4+
[matRippleAnimation]="_rippleAnimation"
5+
[matRippleDisabled]="_isRippleDisabled()"
6+
[matRippleCentered]="_isRippleCentered"
7+
[matRippleTrigger]="_elementRef.nativeElement"></span>
8+
29
<ng-content select="mat-chip-avatar, [matChipAvatar]"></ng-content>
310
<div class="mdc-chip__checkmark" *ngIf="_chipListMultiple">
411
<svg class="mdc-chip__checkmark-svg" viewBox="-2 -3 30 30">

src/material-experimental/mdc-chips/chip-option.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import {SPACE} from '@angular/cdk/keycodes';
33
import {createKeyboardEvent, dispatchFakeEvent} from '@angular/cdk/testing/private';
44
import {Component, DebugElement, ViewChild} from '@angular/core';
55
import {async, ComponentFixture, fakeAsync, flush, TestBed} from '@angular/core/testing';
6-
import {MAT_RIPPLE_GLOBAL_OPTIONS, RippleGlobalOptions} from '@angular/material/core';
76
import {By} from '@angular/platform-browser';
87
import {Subject} from 'rxjs';
98
import {
@@ -20,17 +19,14 @@ describe('MDC-based Option Chips', () => {
2019
let chipDebugElement: DebugElement;
2120
let chipNativeElement: HTMLElement;
2221
let chipInstance: MatChipOption;
23-
let globalRippleOptions: RippleGlobalOptions;
2422

2523
let dir = 'ltr';
2624

2725
beforeEach(async(() => {
28-
globalRippleOptions = {};
2926
TestBed.configureTestingModule({
3027
imports: [MatChipsModule],
3128
declarations: [SingleChip],
3229
providers: [
33-
{provide: MAT_RIPPLE_GLOBAL_OPTIONS, useFactory: () => globalRippleOptions},
3430
{provide: Directionality, useFactory: () => ({
3531
value: dir,
3632
change: new Subject()
@@ -269,6 +265,10 @@ describe('MDC-based Option Chips', () => {
269265
expect(chipNativeElement.getAttribute('aria-disabled')).toBe('true');
270266
});
271267
});
268+
269+
it('should have a focus indicator', () => {
270+
expect(chipNativeElement.classList.contains('mat-mdc-focus-indicator')).toBe(true);
271+
});
272272
});
273273
});
274274

src/material-experimental/mdc-chips/chip-option.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export class MatChipSelectionChange {
4242
inputs: ['color', 'disableRipple', 'tabIndex'],
4343
host: {
4444
'role': 'option',
45+
'class': 'mat-mdc-focus-indicator',
4546
'[class.mat-mdc-chip-disabled]': 'disabled',
4647
'[class.mat-mdc-chip-highlighted]': 'highlighted',
4748
'[class.mat-mdc-chip-with-avatar]': 'leadingIcon',

src/material-experimental/mdc-chips/chip-remove.spec.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ describe('MDC-based Chip Remove', () => {
150150
expect(event.defaultPrevented).toBe(false);
151151
});
152152

153+
it('should have a focus indicator', () => {
154+
const buttonElement = chipNativeElement.querySelector('button')!;
155+
156+
expect(buttonElement.classList.contains('mat-mdc-focus-indicator')).toBe(true);
157+
});
153158
});
154159
});
155160

src/material-experimental/mdc-chips/chip-row.html

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
1+
<span class="mdc-chip__ripple"></span>
2+
3+
<span matRipple class="mat-mdc-chip-ripple"
4+
[matRippleAnimation]="_rippleAnimation"
5+
[matRippleDisabled]="_isRippleDisabled()"
6+
[matRippleCentered]="_isRippleCentered"
7+
[matRippleTrigger]="_elementRef.nativeElement"></span>
8+
19
<div role="gridcell">
2-
<div #chipContent tabindex="-1" class="mat-chip-row-focusable-text-content">
3-
<span class="mdc-chip__ripple"></span>
10+
<div #chipContent tabindex="-1"
11+
class="mat-chip-row-focusable-text-content mat-mdc-focus-indicator">
412
<ng-content select="mat-chip-avatar, [matChipAvatar]"></ng-content>
513
<span class="mdc-chip__text"><ng-content></ng-content></span>
614
<ng-content select="mat-chip-trailing-icon,[matChipTrailingIcon]"></ng-content>

src/material-experimental/mdc-chips/chip-row.spec.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
} from '@angular/cdk/testing/private';
88
import {Component, DebugElement, ViewChild} from '@angular/core';
99
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
10-
import {MAT_RIPPLE_GLOBAL_OPTIONS, RippleGlobalOptions} from '@angular/material/core';
1110
import {By} from '@angular/platform-browser';
1211
import {Subject} from 'rxjs';
1312
import {MatChipEvent, MatChipGrid, MatChipRow, MatChipsModule} from './index';
@@ -18,17 +17,14 @@ describe('MDC-based Row Chips', () => {
1817
let chipDebugElement: DebugElement;
1918
let chipNativeElement: HTMLElement;
2019
let chipInstance: MatChipRow;
21-
let globalRippleOptions: RippleGlobalOptions;
2220

2321
let dir = 'ltr';
2422

2523
beforeEach(async(() => {
26-
globalRippleOptions = {};
2724
TestBed.configureTestingModule({
2825
imports: [MatChipsModule],
2926
declarations: [SingleChip],
3027
providers: [
31-
{provide: MAT_RIPPLE_GLOBAL_OPTIONS, useFactory: () => globalRippleOptions},
3228
{provide: Directionality, useFactory: () => ({
3329
value: dir,
3430
change: new Subject()
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
<span class="mdc-chip__ripple"></span>
2+
3+
<span matRipple class="mat-mdc-chip-ripple"
4+
[matRippleAnimation]="_rippleAnimation"
5+
[matRippleDisabled]="_isRippleDisabled()"
6+
[matRippleCentered]="_isRippleCentered"
7+
[matRippleTrigger]="_elementRef.nativeElement"></span>
8+
29
<ng-content select="mat-chip-avatar, [matChipAvatar]"></ng-content>
310
<div class="mdc-chip__text mdc-chip__action--primary"><ng-content></ng-content></div>
411
<ng-content select="mat-chip-trailing-icon,[matChipRemove],[matChipTrailingIcon]"></ng-content>

src/material-experimental/mdc-chips/chip.spec.ts

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {Directionality} from '@angular/cdk/bidi';
22
import {createFakeEvent} from '@angular/cdk/testing/private';
33
import {Component, DebugElement, ViewChild} from '@angular/core';
44
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
5-
import {MAT_RIPPLE_GLOBAL_OPTIONS, RippleGlobalOptions} from '@angular/material/core';
5+
import {MatRipple} from '@angular/material/core';
66
import {By} from '@angular/platform-browser';
77
import {Subject} from 'rxjs';
88
import {MatChip, MatChipEvent, MatChipSet, MatChipsModule} from './index';
@@ -13,17 +13,16 @@ describe('MDC-based MatChip', () => {
1313
let chipDebugElement: DebugElement;
1414
let chipNativeElement: HTMLElement;
1515
let chipInstance: MatChip;
16-
let globalRippleOptions: RippleGlobalOptions;
16+
let chipRippleDebugElement: DebugElement;
17+
let chipRippleInstance: MatRipple;
1718

1819
let dir = 'ltr';
1920

2021
beforeEach(async(() => {
21-
globalRippleOptions = {};
2222
TestBed.configureTestingModule({
2323
imports: [MatChipsModule],
2424
declarations: [BasicChip, SingleChip],
2525
providers: [
26-
{provide: MAT_RIPPLE_GLOBAL_OPTIONS, useFactory: () => globalRippleOptions},
2726
{provide: Directionality, useFactory: () => ({
2827
value: dir,
2928
change: new Subject()
@@ -35,19 +34,24 @@ describe('MDC-based MatChip', () => {
3534
}));
3635

3736
describe('MatBasicChip', () => {
38-
3937
beforeEach(() => {
4038
fixture = TestBed.createComponent(BasicChip);
4139
fixture.detectChanges();
4240

4341
chipDebugElement = fixture.debugElement.query(By.directive(MatChip))!;
4442
chipNativeElement = chipDebugElement.nativeElement;
4543
chipInstance = chipDebugElement.injector.get<MatChip>(MatChip);
44+
chipRippleDebugElement = chipDebugElement.query(By.directive(MatRipple))!;
45+
chipRippleInstance = chipRippleDebugElement.injector.get<MatRipple>(MatRipple);
4646
});
4747

4848
it('adds the `mat-mdc-basic-chip` class', () => {
4949
expect(chipNativeElement.classList).toContain('mat-mdc-basic-chip');
5050
});
51+
52+
it('should have its ripple disabled', () => {
53+
expect(chipRippleInstance.disabled).toBe(true, 'Expected basic chip ripples to be disabled.');
54+
});
5155
});
5256

5357
describe('MatChip', () => {
@@ -60,6 +64,8 @@ describe('MDC-based MatChip', () => {
6064
chipDebugElement = fixture.debugElement.query(By.directive(MatChip))!;
6165
chipNativeElement = chipDebugElement.nativeElement;
6266
chipInstance = chipDebugElement.injector.get<MatChip>(MatChip);
67+
chipRippleDebugElement = chipDebugElement.query(By.directive(MatRipple))!;
68+
chipRippleInstance = chipRippleDebugElement.injector.get<MatRipple>(MatRipple);
6369
testComponent = fixture.debugElement.componentInstance;
6470
});
6571

@@ -115,12 +121,22 @@ describe('MDC-based MatChip', () => {
115121
expect(chipNativeElement.style.display).toBe('none');
116122
});
117123

118-
it('should be able to disable ripples through ripple global options at runtime', () => {
119-
expect(chipInstance.rippleDisabled).toBe(false, 'Expected chip ripples to be enabled.');
124+
it('should be able to disable ripples with the `[rippleDisabled]` input', () => {
125+
expect(chipRippleInstance.disabled).toBe(false, 'Expected chip ripples to be enabled.');
126+
127+
testComponent.rippleDisabled = true;
128+
fixture.detectChanges();
129+
130+
expect(chipRippleInstance.disabled).toBe(true, 'Expected chip ripples to be disabled.');
131+
});
132+
133+
it('should disable ripples when the chip is disabled', () => {
134+
expect(chipRippleInstance.disabled).toBe(false, 'Expected chip ripples to be enabled.');
120135

121-
globalRippleOptions.disabled = true;
136+
testComponent.disabled = true;
137+
fixture.detectChanges();
122138

123-
expect(chipInstance.rippleDisabled).toBe(true, 'Expected chip ripples to be disabled.');
139+
expect(chipRippleInstance.disabled).toBe(true, 'Expected chip ripples to be disabled.');
124140
});
125141

126142
it('should update the aria-label for disabled chips', () => {
@@ -163,7 +179,7 @@ describe('MDC-based MatChip', () => {
163179
<mat-chip [removable]="removable"
164180
[color]="color" [disabled]="disabled"
165181
(focus)="chipFocus($event)" (destroyed)="chipDestroy($event)"
166-
(removed)="chipRemove($event)" [value]="value">
182+
(removed)="chipRemove($event)" [value]="value" [disableRipple]="rippleDisabled">
167183
{{name}}
168184
</mat-chip>
169185
</div>
@@ -177,6 +193,7 @@ class SingleChip {
177193
removable: boolean = true;
178194
shouldShow: boolean = true;
179195
value: any;
196+
rippleDisabled: boolean = false;
180197

181198
chipFocus: (event?: MatChipEvent) => void = () => {};
182199
chipDestroy: (event?: MatChipEvent) => void = () => {};

0 commit comments

Comments
 (0)