diff --git a/goldens/material/chips/index.api.md b/goldens/material/chips/index.api.md index fdcc60891262..5093bff4245d 100644 --- a/goldens/material/chips/index.api.md +++ b/goldens/material/chips/index.api.md @@ -83,6 +83,7 @@ export class MatChip implements OnInit, AfterViewInit, AfterContentInit, DoCheck _handlePrimaryActionInteraction(): void; // (undocumented) _hasFocus(): boolean; + _hasInteractiveActions(): boolean; _hasTrailingIcon(): boolean; highlighted: boolean; id: string; diff --git a/src/material/chips/chip-row.spec.ts b/src/material/chips/chip-row.spec.ts index 229692a2843d..22c1aa7dcd06 100644 --- a/src/material/chips/chip-row.spec.ts +++ b/src/material/chips/chip-row.spec.ts @@ -436,6 +436,43 @@ describe('Row Chips', () => { })); }); + describe('_hasInteractiveActions', () => { + it('should return true if the chip has a remove icon', () => { + testComponent.removable = true; + fixture.changeDetectorRef.markForCheck(); + fixture.detectChanges(); + expect(chipInstance._hasInteractiveActions()).toBe(true); + }); + + it('should return true if the chip has an edit icon', () => { + testComponent.editable = true; + testComponent.showEditIcon = true; + fixture.changeDetectorRef.markForCheck(); + fixture.detectChanges(); + expect(chipInstance._hasInteractiveActions()).toBe(true); + }); + + it('should return true even with a non-interactive trailing icon', () => { + testComponent.showTrailingIcon = true; + fixture.changeDetectorRef.markForCheck(); + fixture.detectChanges(); + expect(chipInstance._hasInteractiveActions()).toBe(true); + }); + + it('should return false if all actions are non-interactive', () => { + // Make primary action non-interactive for testing purposes. + chipInstance.primaryAction.isInteractive = false; + testComponent.showTrailingIcon = true; + testComponent.removable = false; // remove icon is interactive + fixture.changeDetectorRef.markForCheck(); + fixture.detectChanges(); + + // The trailing icon is not interactive. + expect(chipInstance.trailingIcon.isInteractive).toBe(false); + expect(chipInstance._hasInteractiveActions()).toBe(false); + }); + }); + describe('with edit icon', () => { beforeEach(async () => { testComponent.showEditIcon = true; @@ -507,10 +544,15 @@ describe('Row Chips', () => { } {{name}} - + @if (removable) { + + } @if (useCustomEditInput) { } + @if (showTrailingIcon) { + trailing + } @@ -529,6 +571,7 @@ class SingleChip { editable: boolean = false; showEditIcon: boolean = false; useCustomEditInput: boolean = true; + showTrailingIcon = false; ariaLabel: string | null = null; ariaDescription: string | null = null; diff --git a/src/material/chips/chip.spec.ts b/src/material/chips/chip.spec.ts index b9748576396d..750afb2f4db6 100644 --- a/src/material/chips/chip.spec.ts +++ b/src/material/chips/chip.spec.ts @@ -117,6 +117,18 @@ describe('MatChip', () => { expect(primaryAction.hasAttribute('tabindex')).toBe(false); }); + it('should disable the ripple if there are no interactive actions', () => { + // expect(chipInstance._isRippleDisabled()).toBe(false); TODO(andreyd) + + // Make primary action non-interactive for testing purposes. + chipInstance.primaryAction.isInteractive = false; + fixture.changeDetectorRef.markForCheck(); + fixture.detectChanges(); + + expect(chipInstance._hasInteractiveActions()).toBe(false); + expect(chipInstance._isRippleDisabled()).toBe(true); + }); + it('should return the chip text if value is undefined', () => { expect(chipInstance.value.trim()).toBe(fixture.componentInstance.name); }); diff --git a/src/material/chips/chip.ts b/src/material/chips/chip.ts index 85e2cde30552..eb02fde77b67 100644 --- a/src/material/chips/chip.ts +++ b/src/material/chips/chip.ts @@ -327,6 +327,7 @@ export class MatChip implements OnInit, AfterViewInit, AfterContentInit, DoCheck this.disableRipple || this._animationsDisabled || this._isBasicChip || + !this._hasInteractiveActions() || !!this._globalRippleOptions?.disabled ); } @@ -396,6 +397,11 @@ export class MatChip implements OnInit, AfterViewInit, AfterContentInit, DoCheck // Empty here, but is overwritten in child classes. } + /** Returns whether the chip has any interactive actions. */ + _hasInteractiveActions(): boolean { + return this._getActions().some(a => a.isInteractive); + } + /** Handles interactions with the edit action of the chip. */ _edit(event: Event) { // Empty here, but is overwritten in child classes.