Skip to content

Commit 8a1dff2

Browse files
add disabled/selected styles and events demo
1 parent cd4f2e4 commit 8a1dff2

File tree

7 files changed

+109
-47
lines changed

7 files changed

+109
-47
lines changed

src/dev-app/mdc-chips/mdc-chips-demo-module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9+
import {CommonModule} from '@angular/common';
910
import {NgModule} from '@angular/core';
1011
import {MatCardModule} from '@angular/material/card';
1112
import {MatToolbarModule} from '@angular/material/toolbar';
@@ -16,6 +17,7 @@ import {MdcChipsDemo} from './mdc-chips-demo';
1617

1718
@NgModule({
1819
imports: [
20+
CommonModule,
1921
MatCardModule,
2022
MatChipsModule,
2123
MatIconModule,

src/dev-app/mdc-chips/mdc-chips-demo.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,14 @@ <h4>Advanced</h4>
2323

2424
<mat-chip-grid selectable="false">
2525
<mat-chip-cell color="accent" selected="true">Selected/Colored</mat-chip-cell>
26+
27+
<mat-chip-cell color="warn" selected="true" *ngIf="visible"
28+
(destroyed)="displayMessage('chip destroyed')" (removed)="toggleVisible()">
29+
With Events
30+
<mat-icon matChipRemove>cancel</mat-icon>
31+
</mat-chip-cell>
2632
</mat-chip-grid>
33+
<div>{{message}}</div>
2734

2835
<h4>With avatar and icons</h4>
2936

src/dev-app/mdc-chips/mdc-chips-demo.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,14 @@ import {Component} from '@angular/core';
1515
styleUrls: ['mdc-chips-demo.css'],
1616
})
1717
export class MdcChipsDemo {
18+
visible = true;
19+
message = '';
20+
21+
displayMessage(message: string): void {
22+
this.message = message;
23+
}
24+
25+
toggleVisible(): void {
26+
this.visible = false;
27+
}
1828
}

src/material-experimental/mdc-chips/_mdc-chips.scss

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,22 @@
1111
$primary: mat-color(map-get($theme, primary));
1212
$accent: mat-color(map-get($theme, accent));
1313
$warn: mat-color(map-get($theme, warn));
14+
$background: map-get($theme, background);
15+
$foreground: map-get($theme, foreground);
16+
17+
$unselected-background: mat-color($background, unselected-chip);
18+
$unselected-foreground: mat-color($foreground, text);
19+
20+
21+
&.mat-chip-disabled {
22+
opacity: 0.4;
23+
}
1424

1525
&.mat-mdc-chip-cell {
26+
.mdc-chip {
27+
@include mdc-chip-fill-color-accessible($unselected-background);
28+
}
29+
1630
.mat-primary {
1731
@include mdc-chip-fill-color-accessible($primary);
1832
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
[class.mat-accent] = "color === 'accent'"
55
[class.mat-warn] = "color === 'warn'"
66
[ngClass]="_classes"
7+
(click)='_handleInteraction($event)'
8+
(keydown)='_handleInteraction($event)'
9+
(transitionend)='_chipFoundation.handleTransitionEnd($event)'
710
tabindex="0">
811
<div class="mdc-chip__text"><ng-content></ng-content></div>
912
</div>

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

Lines changed: 67 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,14 @@ import {takeUntil} from 'rxjs/operators';
1616

1717
let uid = 0;
1818

19+
/** Represents an event fired on an individual `mat-chip`. */
20+
export interface MatChipCellEvent {
21+
/** The chip the event was fired on. */
22+
chip: MatChipCell;
23+
}
24+
1925
/**
20-
* Dummy directive to add CSS class to chip leading icon.
26+
* Directive to add CSS classes to chip leading icon.
2127
* @docs-private
2228
*/
2329
@Directive({
@@ -27,23 +33,26 @@ let uid = 0;
2733
}
2834
})
2935
export class MatChipAvatar {
30-
_classes: {[key: string]: boolean} = {};
36+
constructor(private _changeDetectorRef: ChangeDetectorRef,
37+
private _elementRef: ElementRef) {}
3138

3239
/** Sets whether the given CSS class should be applied to the leading icon. */
3340
setClass(cssClass: string, active: boolean) {
3441
const element = this._elementRef.nativeElement;
3542
active ? element.addClass(cssClass) : element.removeClass(cssClass);
3643
this._changeDetectorRef.markForCheck();
3744
}
38-
39-
constructor(private _changeDetectorRef: ChangeDetectorRef,
40-
private _elementRef: ElementRef) {}
4145
}
4246

4347
/**
44-
* Dummy directive to add CSS class to chip trailing icon.
48+
* Directive to add CSS class to chip trailing icon and notify parent chip
49+
* about trailing icon interactions.
50+
*
51+
* If matChipRemove is used to add this directive, the parent chip will be
52+
* removed when the trailing icon is clicked.
53+
*
4554
* @docs-private
46-
*/
55+
z */
4756
@Directive({
4857
selector: 'mat-chip-trailing-icon, [matChipTrailingIcon], [matChipRemove]',
4958
host: {
@@ -56,8 +65,16 @@ export class MatChipAvatar {
5665
})
5766
export class MatChipTrailingIcon {
5867
@Output() interaction = new EventEmitter<MouseEvent | KeyboardEvent>();
68+
shouldRemove!: boolean;
69+
70+
constructor(_elementRef: ElementRef) {
71+
this.shouldRemove = _elementRef.nativeElement.getAttribute('matChipRemove') !== null;
72+
}
5973
}
6074

75+
/**
76+
* Material design styled Chip component. Used inside the MatChipGrid component.
77+
*/
6178
@Component({
6279
selector: 'mat-chip-cell, mat-basic-chip-cell',
6380
templateUrl: 'chip-cell.html',
@@ -67,9 +84,6 @@ export class MatChipTrailingIcon {
6784
'[id]': 'id',
6885
'[class.mat-chip-disabled]': 'disabled',
6986
'[class.mat-chip-selected]': 'selected',
70-
'(click)': '_chipFoundation.handleInteraction($event)',
71-
'(keydown)': '_chipFoundation.handleInteraction($event)',
72-
'(transitionend)': '_chipFoundation.handleTransitionEnd($event)'
7387
},
7488
})
7589
export class MatChipCell implements AfterContentInit, AfterViewInit, OnDestroy {
@@ -93,34 +107,22 @@ export class MatChipCell implements AfterContentInit, AfterViewInit, OnDestroy {
93107
this._changeDetectorRef.markForCheck();
94108
}
95109

96-
/**
97-
* EventEmitters used to notify the parent chip-set of an event on the chip.
98-
*/
99-
@Output() removal = new EventEmitter<string>();
100-
@Output() trailingIconInteraction = new EventEmitter<string>();
101-
@Output() interaction = new EventEmitter<string>();
102-
@Output() selection = new EventEmitter<{id: string, selected: boolean}>();
103-
104110
/** Whether the chip is selected. */
111+
@Input()
105112
get selected(): boolean {
106113
return this._chipFoundation.isSelected();
107114
}
108-
109-
@Input()
110-
/** Sets selected state on the chip. */
111115
set selected(selected: boolean) {
112116
this._chipFoundation.setSelected(selected);
113117
}
114118

115-
/** Whether a trailing icon click should trigger exit/removal of the chip. */
116-
get shouldRemoveOnTrailingIconClick(): boolean {
117-
return this._chipFoundation.getShouldRemoveOnTrailingIconClick();
118-
}
119-
120-
/** Sets whether a trailing icon click should trigger exit/removal of the chip. */
121-
set shouldRemoveOnTrailingIconClick(shouldRemove: boolean) {
122-
this._chipFoundation.setShouldRemoveOnTrailingIconClick(shouldRemove);
123-
}
119+
/**
120+
* EventEmitters used to notify the parent chip-set of an event on the chip.
121+
*/
122+
@Output() removal = new EventEmitter<string>();
123+
@Output() trailingIconInteraction = new EventEmitter<string>();
124+
@Output() interaction = new EventEmitter<string>();
125+
@Output() selection = new EventEmitter<{id: string, selected: boolean}>();
124126

125127
/** The MDC foundation containing business logic for MDC chip. */
126128
_chipFoundation: MDCChipFoundation;
@@ -131,6 +133,12 @@ export class MatChipCell implements AfterContentInit, AfterViewInit, OnDestroy {
131133
*/
132134
_classes: {[key: string]: boolean} = {};
133135

136+
/** Emitted when the chip is destroyed. */
137+
@Output() readonly destroyed: EventEmitter<MatChipCellEvent> = new EventEmitter<MatChipCellEvent>();
138+
139+
/** Emitted when a chip is to be removed. */
140+
@Output() readonly removed: EventEmitter<MatChipCellEvent> = new EventEmitter<MatChipCellEvent>();
141+
134142
/** Subject that emits when the component has been destroyed. */
135143
private _destroyed = new Subject<void>();
136144

@@ -143,10 +151,12 @@ export class MatChipCell implements AfterContentInit, AfterViewInit, OnDestroy {
143151
/** The chip's trailing icon. */
144152
@ContentChild(MatChipTrailingIcon, {static: false}) trailingIcon: MatChipTrailingIcon;
145153

154+
/** The div element that is styled as an MDC chip. */
146155
@ViewChild('wrapper') _wrapper!: ElementRef;
147-
/**
148-
* Implementation of the MDC chip adapter interface.
149-
* These methods are called by the chip foundation.
156+
157+
/**
158+
* Implementation of the MDC chip adapter interface.
159+
* These methods are called by the chip foundation.
150160
*/
151161
private _chipAdapter: MDCChipAdapter = {
152162
addClass: (className) => this._setClass(className, true),
@@ -160,14 +170,19 @@ export class MatChipCell implements AfterContentInit, AfterViewInit, OnDestroy {
160170
notifyInteraction: () => this.interaction.emit(this.id),
161171
notifySelection: () => this.selection.emit({id: this.id, selected: this.selected}),
162172
notifyTrailingIconInteraction: () => this.trailingIconInteraction.emit(this.id),
163-
notifyRemoval: () => this.removal.emit(this.id),
173+
notifyRemoval: () => {
174+
this.removed.emit({chip: this});
175+
this.removal.emit(this.id);
176+
},
164177
getComputedStyleValue: (propertyName) => {
165-
return window.getComputedStyle(this._elementRef.nativeElement).getPropertyValue(propertyName);
178+
return window.getComputedStyle(this._wrapper.nativeElement).getPropertyValue(propertyName);
166179
},
167180
setStyleProperty: (propertyName: string, value: string) => {
168-
this._elementRef.nativeElement.style.setProperty(propertyName, value);
181+
this._wrapper.nativeElement.style.setProperty(propertyName, value);
169182
},
170183
hasLeadingIcon: () => {return !!this.leadingIcon},
184+
// The 2 functions below are used by the MDC ripple, which we aren't using,
185+
// so they will never be called
171186
getRootBoundingClientRect: () => this._elementRef.nativeElement.getBoundingClientRect(),
172187
getCheckmarkBoundingClientRect: () => {return null},
173188
};
@@ -183,9 +198,14 @@ export class MatChipCell implements AfterContentInit, AfterViewInit, OnDestroy {
183198

184199
ngAfterContentInit() {
185200
if (this.trailingIcon) {
201+
this._chipFoundation.setShouldRemoveOnTrailingIconClick(this.trailingIcon.shouldRemove);
186202
this.trailingIcon.interaction
187203
.pipe(takeUntil(this._destroyed))
188-
.subscribe((event) => this._chipFoundation.handleTrailingIconInteraction(event));
204+
.subscribe((event) => {
205+
if (!this.disabled) {
206+
this._chipFoundation.handleTrailingIconInteraction(event);
207+
}
208+
});
189209
}
190210
}
191211

@@ -195,27 +215,30 @@ export class MatChipCell implements AfterContentInit, AfterViewInit, OnDestroy {
195215
}
196216

197217
ngOnDestroy() {
218+
this.destroyed.emit({chip: this});
198219
this._destroyed.next();
199220
this._destroyed.complete();
200221
this._chipFoundation.destroy();
201222
}
202223

203224
/**
204225
* Begins the exit animation which leads to removal of the chip.
205-
* If shouldRemoveOnTrailingIconClick is set to false, you must manually call
226+
* If you aren't using the matChipRemove Directive, you must manually call
206227
* this method to remove the chip.
207228
*/
208229
beginExit() {
209230
this._chipFoundation.beginExit();
210231
}
211232

233+
/** Whether this chip is a basic (unstyled) chip. */
212234
_isBasicChip() {
213235
const basicChipAttrName = 'mat-basic-chip-cell';
214236
const element = this._elementRef.nativeElement as HTMLElement;
215237
return element.hasAttribute(basicChipAttrName) ||
216238
element.tagName.toLowerCase() === basicChipAttrName;
217239
}
218240

241+
/** Adds a class to non-basic chips. */
219242
_addHostClassName() {
220243
if (!this._isBasicChip()) {
221244
this._elementRef.nativeElement.classList.add('mat-standard-chip-cell');
@@ -237,12 +260,17 @@ export class MatChipCell implements AfterContentInit, AfterViewInit, OnDestroy {
237260
exitDuration: 150 /* MDCRippleFoundation.numbers.FG_DEACTIVATION_MS */,
238261
},
239262
},
240-
rippleDisabled: this._isBasicChip()
263+
rippleDisabled: this.disabled || this._isBasicChip(),
241264
};
242265

243266
this._rippleRenderer =
244267
new RippleRenderer(rippleTarget, this._ngZone, this._wrapper, this._platform);
245268
this._rippleRenderer.setupTriggerEvents(this._wrapper.nativeElement);
246269
}
270+
271+
/** Forwards interaction events to the MDC chip foundation. */
272+
_handleInteraction(event: MouseEvent | KeyboardEvent) {
273+
if (!this.disabled) this._chipFoundation.handleInteraction(event);
274+
}
247275
}
248276

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

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import {AfterContentInit, AfterViewInit, ChangeDetectionStrategy, Component, ContentChildren, ElementRef, OnDestroy, QueryList, ViewChild, ViewEncapsulation} from '@angular/core';
1010
import {MDCChipSetAdapter, MDCChipSetFoundation} from '@material/chips';
11-
import {MatChipCell} from './chip-cell';
11+
import {MatChipCell, MatChipCellEvent} from './chip-cell';
1212
import {Subject} from 'rxjs';
1313
import {takeUntil} from 'rxjs/operators';
1414

@@ -52,10 +52,8 @@ export class MatChipGrid implements AfterContentInit, AfterViewInit, OnDestroy {
5252
*/
5353
private _chipSetAdapter: MDCChipSetAdapter = {
5454
hasClass: (className) => this._elementRef.nativeElement.classList.contains(className),
55-
removeChip: (chipId) => {
56-
const chip = document.getElementById(chipId);
57-
this._wrapper.nativeElement.removeChild(chip);
58-
},
55+
removeChip: () => {
56+
},
5957
setSelected: (chipId, selected) => {
6058
const chip = this._chips.find(c => c.id === chipId);
6159
if (chip) chip.selected = selected;
@@ -77,10 +75,10 @@ export class MatChipGrid implements AfterContentInit, AfterViewInit, OnDestroy {
7775
this._chipSetFoundation.select(chip.id);
7876
}
7977

80-
chip.removal
78+
chip.removed
8179
.pipe(takeUntil(this._destroyed))
82-
.subscribe((id: string) => {
83-
this._chipSetFoundation.handleChipRemoval(id);
80+
.subscribe((chipEvent: MatChipCellEvent) => {
81+
this._chipSetFoundation.handleChipRemoval(chipEvent.chip.id);
8482
});
8583

8684
chip.interaction

0 commit comments

Comments
 (0)