Skip to content

Commit

Permalink
refactor(material/chips): switch to lazy ripple rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
wagnermaciel committed Jul 12, 2023
1 parent cbac7f6 commit dfe5cac
Show file tree
Hide file tree
Showing 9 changed files with 50 additions and 33 deletions.
4 changes: 0 additions & 4 deletions src/material/chips/chip-option.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
<span matRipple class="mat-mdc-chip-ripple"
[matRippleDisabled]="_isRippleDisabled()"
[matRippleCentered]="_isRippleCentered"
[matRippleTrigger]="_elementRef.nativeElement"></span>
<span class="mat-mdc-chip-focus-overlay"></span>

<span class="mdc-evolution-chip__cell mdc-evolution-chip__cell--primary">
Expand Down
9 changes: 0 additions & 9 deletions src/material/chips/chip-row.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
<ng-container *ngIf="!_isEditing">
<span matRipple class="mat-mdc-chip-ripple"
[matRippleDisabled]="_isRippleDisabled()"
[matRippleCentered]="_isRippleCentered"
[matRippleTrigger]="_elementRef.nativeElement"></span>
<span class="mat-mdc-chip-focus-overlay"></span>
</ng-container>


<span class="mdc-evolution-chip__cell mdc-evolution-chip__cell--primary" role="gridcell"
matChipAction
[tabIndex]="tabIndex"
Expand Down
4 changes: 4 additions & 0 deletions src/material/chips/chip-row.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@ export class MatChipRow extends MatChip implements AfterViewInit {
}
}

override _isRippleDisabled(): boolean {
return super._isRippleDisabled() || this._isEditing;
}

/**
* Gets the projected chip edit input, or the default input if none is projected in. One of these
* two values is guaranteed to be defined.
Expand Down
4 changes: 0 additions & 4 deletions src/material/chips/chip.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
<span matRipple class="mat-mdc-chip-ripple"
[matRippleDisabled]="_isRippleDisabled()"
[matRippleCentered]="_isRippleCentered"
[matRippleTrigger]="_elementRef.nativeElement"></span>
<span class="mat-mdc-chip-focus-overlay"></span>

<span class="mdc-evolution-chip__cell mdc-evolution-chip__cell--primary">
Expand Down
15 changes: 6 additions & 9 deletions src/material/chips/chip.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ describe('MDC-based MatChip', () => {
let chipNativeElement: HTMLElement;
let chipInstance: MatChip;
let chipRippleDebugElement: DebugElement;
let chipRippleInstance: MatRipple;

let dir = 'ltr';

Expand Down Expand Up @@ -74,9 +73,8 @@ describe('MDC-based MatChip', () => {
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)
chipInstance = chipDebugElement.injector.get<MatChip>(MatChip);
expect(chipInstance.ripple.disabled)
.withContext('Expected basic chip ripples to be disabled.')
.toBe(true);
});
Expand All @@ -94,7 +92,6 @@ describe('MDC-based 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;
primaryAction = chipNativeElement.querySelector('.mdc-evolution-chip__action--primary')!;
});
Expand Down Expand Up @@ -137,27 +134,27 @@ describe('MDC-based MatChip', () => {
});

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

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

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

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

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

expect(chipRippleInstance.disabled)
expect(chipInstance.ripple.disabled)
.withContext('Expected chip ripples to be disabled.')
.toBe(true);
});
Expand Down
29 changes: 25 additions & 4 deletions src/material/chips/chip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import {
ContentChildren,
QueryList,
OnInit,
DoCheck,
inject,
} from '@angular/core';
import {DOCUMENT} from '@angular/common';
import {
Expand All @@ -43,6 +45,7 @@ import {
mixinTabIndex,
mixinDisabled,
RippleGlobalOptions,
MatRippleLoader,
} from '@angular/material/core';
import {FocusMonitor} from '@angular/cdk/a11y';
import {merge, Subject, Subscription} from 'rxjs';
Expand Down Expand Up @@ -123,14 +126,12 @@ export class MatChip
CanColor,
CanDisableRipple,
CanDisable,
DoCheck,
HasTabIndex,
OnDestroy
{
protected _document: Document;

/** Whether the ripple is centered on the chip. */
readonly _isRippleCentered = false;

/** Emits when the chip is focused. */
readonly _onFocus = new Subject<MatChipEvent>();

Expand Down Expand Up @@ -251,11 +252,22 @@ export class MatChip
* @deprecated Considered an implementation detail. To be removed.
* @breaking-change 17.0.0
*/
@ViewChild(MatRipple) ripple: MatRipple;
get ripple(): MatRipple {
return this._rippleLoader?.getRipple(this._elementRef.nativeElement)!;
}
set ripple(v: MatRipple) {
this._rippleLoader?.attachRipple(this._elementRef.nativeElement, v);
}

/** Action receiving the primary set of user interactions. */
@ViewChild(MatChipAction) primaryAction: MatChipAction;

/**
* Handles the lazy creation of the MatButton ripple.
* Used to improve initial load time of large applications.
*/
_rippleLoader: MatRippleLoader = inject(MatRippleLoader);

constructor(
public _changeDetectorRef: ChangeDetectorRef,
elementRef: ElementRef<HTMLElement>,
Expand All @@ -275,6 +287,11 @@ export class MatChip
this.tabIndex = parseInt(tabIndex) ?? this.defaultTabIndex;
}
this._monitorFocus();

this._rippleLoader?.configureRipple(this._elementRef.nativeElement, {
className: 'mat-mdc-chip-ripple',
disabled: this._isRippleDisabled(),
});
}

ngOnInit() {
Expand Down Expand Up @@ -305,6 +322,10 @@ export class MatChip
).subscribe(() => this._changeDetectorRef.markForCheck());
}

ngDoCheck(): void {
this._rippleLoader.setDisabled(this._elementRef.nativeElement, this._isRippleDisabled());
}

ngOnDestroy() {
this._focusMonitor.stopMonitoring(this._elementRef);
this._actionChanges?.unsubscribe();
Expand Down
5 changes: 5 additions & 0 deletions src/material/core/private/ripple-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export class MatRippleLoader implements OnDestroy {
config: {
className?: string;
centered?: boolean;
disabled?: boolean;
},
): void {
// Indicates that the ripple has not yet been rendered for this component.
Expand All @@ -89,6 +90,10 @@ export class MatRippleLoader implements OnDestroy {
if (config.centered) {
host.setAttribute(matRippleCentered, '');
}

if (config.disabled) {
host.setAttribute(matRippleDisabled, '');
}
}

/** Returns the ripple instance for the given host element. */
Expand Down
12 changes: 9 additions & 3 deletions tools/public_api_guard/material/chips.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { InjectionToken } from '@angular/core';
import { MatFormField } from '@angular/material/form-field';
import { MatFormFieldControl } from '@angular/material/form-field';
import { MatRipple } from '@angular/material/core';
import { MatRippleLoader } from '@angular/material/core';
import { NgControl } from '@angular/forms';
import { NgForm } from '@angular/forms';
import { NgZone } from '@angular/core';
Expand Down Expand Up @@ -61,7 +62,7 @@ export const MAT_CHIP_TRAILING_ICON: InjectionToken<unknown>;
export const MAT_CHIPS_DEFAULT_OPTIONS: InjectionToken<MatChipsDefaultOptions>;

// @public
export class MatChip extends _MatChipMixinBase implements OnInit, AfterViewInit, AfterContentInit, CanColor, CanDisableRipple, CanDisable, HasTabIndex, OnDestroy {
export class MatChip extends _MatChipMixinBase implements OnInit, AfterViewInit, AfterContentInit, CanColor, CanDisableRipple, CanDisable, DoCheck, HasTabIndex, OnDestroy {
constructor(_changeDetectorRef: ChangeDetectorRef, elementRef: ElementRef<HTMLElement>, _ngZone: NgZone, _focusMonitor: FocusMonitor, _document: any, animationMode?: string, _globalRippleOptions?: RippleGlobalOptions | undefined, tabIndex?: string);
protected _allLeadingIcons: QueryList<MatChipAvatar>;
protected _allRemoveIcons: QueryList<MatChipRemove>;
Expand Down Expand Up @@ -90,14 +91,15 @@ export class MatChip extends _MatChipMixinBase implements OnInit, AfterViewInit,
protected _highlighted: boolean;
id: string;
_isBasicChip: boolean;
readonly _isRippleCentered = false;
_isRippleDisabled(): boolean;
leadingIcon: MatChipAvatar;
// (undocumented)
ngAfterContentInit(): void;
// (undocumented)
ngAfterViewInit(): void;
// (undocumented)
ngDoCheck(): void;
// (undocumented)
ngOnDestroy(): void;
// (undocumented)
ngOnInit(): void;
Expand All @@ -114,7 +116,9 @@ export class MatChip extends _MatChipMixinBase implements OnInit, AfterViewInit,
readonly removed: EventEmitter<MatChipEvent>;
removeIcon: MatChipRemove;
// @deprecated
ripple: MatRipple;
get ripple(): MatRipple;
set ripple(v: MatRipple);
_rippleLoader: MatRippleLoader;
role: string | null;
trailingIcon: MatChipTrailingIcon;
get value(): any;
Expand Down Expand Up @@ -407,6 +411,8 @@ export class MatChipRow extends MatChip implements AfterViewInit {
// (undocumented)
_isEditing: boolean;
// (undocumented)
_isRippleDisabled(): boolean;
// (undocumented)
static ɵcmp: i0.ɵɵComponentDeclaration<MatChipRow, "mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]", never, { "color": { "alias": "color"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "disableRipple": { "alias": "disableRipple"; "required": false; }; "tabIndex": { "alias": "tabIndex"; "required": false; }; "editable": { "alias": "editable"; "required": false; }; }, { "edited": "edited"; }, ["contentEditInput"], ["mat-chip-avatar, [matChipAvatar]", "*", "[matChipEditInput]", "mat-chip-trailing-icon,[matChipRemove],[matChipTrailingIcon]"], false, never>;
// (undocumented)
static ɵfac: i0.ɵɵFactoryDeclaration<MatChipRow, [null, null, null, null, null, { optional: true; }, { optional: true; }, { attribute: "tabindex"; }]>;
Expand Down
1 change: 1 addition & 0 deletions tools/public_api_guard/material/core.md
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ export class MatRippleLoader implements OnDestroy {
configureRipple(host: HTMLElement, config: {
className?: string;
centered?: boolean;
disabled?: boolean;
}): void;
createRipple(host: HTMLElement): MatRipple | undefined;
getRipple(host: HTMLElement): MatRipple | undefined;
Expand Down

0 comments on commit dfe5cac

Please sign in to comment.