Skip to content

Commit d8465f5

Browse files
committed
refactor(material-experimental/mdc-chips): remove usage of MDC adapter
Reworks the MDC-based chips not to use the MDC adapters.
1 parent 445134c commit d8465f5

19 files changed

+400
-834
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,10 @@ <h4>Input is last child of chip grid</h4>
147147
<mat-form-field class="demo-has-chip-list">
148148
<mat-label>New Contributor...</mat-label>
149149
<mat-chip-grid #chipGrid1 [(ngModel)]="selectedPeople" required [disabled]="disableInputs">
150-
<mat-chip-row *ngFor="let person of people"
150+
<!-- Disable the third chip to test focus management with a disabled chip. -->
151+
<mat-chip-row *ngFor="let person of people; let index = index"
151152
[editable]="editable"
153+
[disabled]="index === 2"
152154
(removed)="remove(person)"
153155
(edited)="edit(person, $event)">
154156
{{person.name}}

src/material-experimental/mdc-chips/BUILD.bazel

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ ng_module(
2929
"@npm//@angular/common",
3030
"@npm//@angular/core",
3131
"@npm//@angular/forms",
32-
"@npm//@material/chips",
3332
],
3433
)
3534

@@ -91,7 +90,6 @@ ng_test_library(
9190
"@npm//@angular/common",
9291
"@npm//@angular/forms",
9392
"@npm//@angular/platform-browser",
94-
"@npm//@material/chips",
9593
"@npm//rxjs",
9694
],
9795
)

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

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

9-
import {
10-
AfterViewInit,
11-
ChangeDetectorRef,
12-
Directive,
13-
ElementRef,
14-
Inject,
15-
Input,
16-
OnChanges,
17-
OnDestroy,
18-
SimpleChanges,
19-
} from '@angular/core';
20-
import {DOCUMENT} from '@angular/common';
21-
import {
22-
MDCChipActionAdapter,
23-
MDCChipActionFoundation,
24-
MDCChipActionType,
25-
MDCChipPrimaryActionFoundation,
26-
} from '@material/chips';
27-
import {emitCustomEvent} from './emit-event';
9+
import {Directive, ElementRef, Input} from '@angular/core';
2810
import {
2911
CanDisable,
3012
HasTabIndex,
@@ -35,118 +17,40 @@ import {
3517
const _MatChipActionMixinBase = mixinTabIndex(mixinDisabled(class {}), -1);
3618

3719
/**
38-
* Interactive element within a chip.
20+
* Section within a chip.
3921
* @docs-private
4022
*/
4123
@Directive({
4224
selector: '[matChipAction]',
4325
inputs: ['disabled', 'tabIndex'],
4426
host: {
4527
'class': 'mdc-evolution-chip__action mat-mdc-chip-action',
46-
'[class.mdc-evolution-chip__action--primary]': `_getFoundation().actionType() === ${MDCChipActionType.PRIMARY}`,
28+
'[class.mdc-evolution-chip__action--primary]': '_isPrimary',
4729
// Note that while our actions are interactive, we have to add the `--presentational` class,
4830
// in order to avoid some super-specific `:hover` styles from MDC.
49-
'[class.mdc-evolution-chip__action--presentational]': `_getFoundation().actionType() === ${MDCChipActionType.PRIMARY}`,
50-
'[class.mdc-evolution-chip__action--trailing]': `_getFoundation().actionType() === ${MDCChipActionType.TRAILING}`,
31+
'[class.mdc-evolution-chip__action--presentational]': '_isPrimary',
32+
'[class.mdc-evolution-chip__action--trailing]': '!_isPrimary',
5133
'[attr.tabindex]': '(disabled || !isInteractive) ? null : tabIndex',
5234
'[attr.disabled]': "disabled ? '' : null",
5335
'[attr.aria-disabled]': 'disabled',
54-
'(click)': '_handleClick($event)',
55-
'(keydown)': '_handleKeydown($event)',
5636
},
5737
})
58-
export class MatChipAction
59-
extends _MatChipActionMixinBase
60-
implements AfterViewInit, OnDestroy, CanDisable, HasTabIndex, OnChanges
61-
{
62-
private _document: Document;
63-
private _foundation: MDCChipActionFoundation;
64-
private _adapter: MDCChipActionAdapter = {
65-
focus: () => this.focus(),
66-
getAttribute: (name: string) => this._elementRef.nativeElement.getAttribute(name),
67-
setAttribute: (name: string, value: string) => {
68-
// MDC tries to update the tabindex directly in the DOM when navigating using the keyboard
69-
// which overrides our own handling. If we detect such a case, assign it to the same property
70-
// as the Angular binding in order to maintain consistency.
71-
if (name === 'tabindex') {
72-
this._updateTabindex(parseInt(value));
73-
} else {
74-
this._elementRef.nativeElement.setAttribute(name, value);
75-
}
76-
},
77-
removeAttribute: (name: string) => {
78-
if (name !== 'tabindex') {
79-
this._elementRef.nativeElement.removeAttribute(name);
80-
}
81-
},
82-
getElementID: () => this._elementRef.nativeElement.id,
83-
emitEvent: <T>(eventName: string, data: T) => {
84-
emitCustomEvent<T>(this._elementRef.nativeElement, this._document, eventName, data, true);
85-
},
86-
};
87-
38+
export class MatChipAction extends _MatChipActionMixinBase implements CanDisable, HasTabIndex {
8839
/** Whether the action is interactive. */
8940
@Input() isInteractive = true;
9041

91-
_handleClick(event: MouseEvent) {
92-
// Usually these events can't happen while the chip is disabled since the browser won't
93-
// allow them which is what MDC seems to rely on, however the event can be faked in tests.
94-
if (!this.disabled && this.isInteractive) {
95-
this._foundation.handleClick();
96-
event.preventDefault();
97-
}
98-
}
42+
/** Whether this is the primary action in the chip. */
43+
_isPrimary = true;
9944

100-
_handleKeydown(event: KeyboardEvent) {
101-
// Usually these events can't happen while the chip is disabled since the browser won't
102-
// allow them which is what MDC seems to rely on, however the event can be faked in tests.
103-
if (!this.disabled && this.isInteractive) {
104-
this._foundation.handleKeydown(event);
105-
}
106-
}
107-
108-
protected _createFoundation(adapter: MDCChipActionAdapter): MDCChipActionFoundation {
109-
return new MDCChipPrimaryActionFoundation(adapter);
110-
}
111-
112-
constructor(
113-
public _elementRef: ElementRef,
114-
@Inject(DOCUMENT) _document: any,
115-
private _changeDetectorRef: ChangeDetectorRef,
116-
) {
45+
constructor(public _elementRef: ElementRef<HTMLElement>) {
11746
super();
118-
this._foundation = this._createFoundation(this._adapter);
11947

12048
if (_elementRef.nativeElement.nodeName === 'BUTTON') {
12149
_elementRef.nativeElement.setAttribute('type', 'button');
12250
}
12351
}
12452

125-
ngAfterViewInit() {
126-
this._foundation.init();
127-
this._foundation.setDisabled(this.disabled);
128-
}
129-
130-
ngOnChanges(changes: SimpleChanges) {
131-
if (changes['disabled']) {
132-
this._foundation.setDisabled(this.disabled);
133-
}
134-
}
135-
136-
ngOnDestroy() {
137-
this._foundation.destroy();
138-
}
139-
14053
focus() {
14154
this._elementRef.nativeElement.focus();
14255
}
143-
144-
_getFoundation() {
145-
return this._foundation;
146-
}
147-
148-
_updateTabindex(value: number) {
149-
this.tabIndex = value;
150-
this._changeDetectorRef.markForCheck();
151-
}
15256
}

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

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
dispatchFakeEvent,
1717
dispatchKeyboardEvent,
1818
MockNgZone,
19+
patchElementFocus,
1920
typeInElement,
2021
} from '@angular/cdk/testing/private';
2122
import {
@@ -34,7 +35,6 @@ import {MatFormFieldModule} from '@angular/material-experimental/mdc-form-field'
3435
import {MatInputModule} from '@angular/material-experimental/mdc-input';
3536
import {By} from '@angular/platform-browser';
3637
import {BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations';
37-
import {MDCChipAnimation} from '@material/chips';
3838
import {MatChipEvent, MatChipGrid, MatChipInputEvent, MatChipRow, MatChipsModule} from './index';
3939

4040
describe('MDC-based MatChipGrid', () => {
@@ -199,6 +199,7 @@ describe('MDC-based MatChipGrid', () => {
199199
// Destroy the middle item
200200
testComponent.chips.splice(2, 1);
201201
fixture.detectChanges();
202+
flush();
202203

203204
// Should not have focus
204205
expect(chipGridNativeElement.contains(document.activeElement)).toBe(false);
@@ -208,6 +209,7 @@ describe('MDC-based MatChipGrid', () => {
208209
testComponent.chips = [0];
209210

210211
spyOn(chipGridInstance, 'focus');
212+
patchElementFocus(chips.last.primaryAction!._elementRef.nativeElement);
211213
chips.last.focus();
212214

213215
testComponent.chips.pop();
@@ -216,27 +218,22 @@ describe('MDC-based MatChipGrid', () => {
216218
expect(chipGridInstance.focus).toHaveBeenCalled();
217219
});
218220

219-
it(
220-
'should move focus to the last chip when the focused chip was deleted inside a ' +
221-
'component with animations',
222-
fakeAsync(() => {
223-
fixture.destroy();
224-
TestBed.resetTestingModule();
225-
226-
fixture = createComponent(StandardChipGridWithAnimations, BrowserAnimationsModule);
221+
it('should move focus to the last chip when the focused chip was deleted inside a component with animations', fakeAsync(() => {
222+
fixture.destroy();
223+
TestBed.resetTestingModule();
227224

228-
chips.last.focus();
229-
fixture.detectChanges();
225+
fixture = createComponent(StandardChipGridWithAnimations, BrowserAnimationsModule);
230226

231-
expect(document.activeElement).toBe(primaryActions[primaryActions.length - 1]);
227+
patchElementFocus(chips.last.primaryAction!._elementRef.nativeElement);
228+
chips.last.focus();
229+
fixture.detectChanges();
232230

233-
dispatchKeyboardEvent(chips.last._elementRef.nativeElement, 'keydown', BACKSPACE);
234-
fixture.detectChanges();
235-
tick(500);
231+
dispatchKeyboardEvent(chips.last._elementRef.nativeElement, 'keydown', BACKSPACE);
232+
fixture.detectChanges();
233+
tick(500);
236234

237-
expect(document.activeElement).toBe(primaryActions[primaryActions.length - 2]);
238-
}),
239-
);
235+
expect(document.activeElement).toBe(primaryActions[primaryActions.length - 2]);
236+
}));
240237
});
241238

242239
it('should have a focus indicator', () => {
@@ -394,6 +391,7 @@ describe('MDC-based MatChipGrid', () => {
394391
expect(document.activeElement).toBe(primaryActions[1]);
395392

396393
directionality.value = 'rtl';
394+
directionality.change.next('rtl');
397395
fixture.detectChanges();
398396

399397
dispatchKeyboardEvent(primaryActions[1], 'keydown', RIGHT_ARROW);
@@ -562,14 +560,7 @@ describe('MDC-based MatChipGrid', () => {
562560
// associated chip remove element.
563561
trailingActions[2].click();
564562
fixture.detectChanges();
565-
(chip as any)._handleAnimationend({
566-
animationName: MDCChipAnimation.EXIT,
567-
target: chip._elementRef.nativeElement,
568-
});
569563
flush();
570-
(chip as any)._handleTransitionend({target: chip._elementRef.nativeElement});
571-
flush();
572-
fixture.detectChanges();
573564

574565
expect(document.activeElement).toBe(primaryActions[3]);
575566
}));
@@ -589,7 +580,6 @@ describe('MDC-based MatChipGrid', () => {
589580
.map(chip => chip.nativeElement);
590581

591582
nativeChipGrid = fixture.debugElement.query(By.css('mat-chip-grid'))!.nativeElement;
592-
593583
nativeInput = fixture.nativeElement.querySelector('input');
594584
});
595585

@@ -730,18 +720,21 @@ describe('MDC-based MatChipGrid', () => {
730720

731721
it('should blur the form field when the active chip is blurred', fakeAsync(() => {
732722
const formField: HTMLElement = fixture.nativeElement.querySelector('.mat-mdc-form-field');
723+
const firstAction = nativeChips[0].querySelector('.mat-mdc-chip-action') as HTMLElement;
733724

734-
dispatchFakeEvent(nativeChips[0], 'focusin');
725+
patchElementFocus(firstAction);
726+
firstAction.focus();
735727
fixture.detectChanges();
736728

737729
expect(formField.classList).toContain('mat-focused');
738730

739-
dispatchFakeEvent(nativeChips[0], 'focusout');
731+
firstAction.blur();
740732
fixture.detectChanges();
741-
tick();
742733
fixture.detectChanges();
743734
zone.simulateZoneExit();
744735
fixture.detectChanges();
736+
flush();
737+
745738
expect(formField.classList).not.toContain('mat-focused');
746739
}));
747740

0 commit comments

Comments
 (0)