From c8657cb99a1e363a20b6501433966f9e0e0b519f Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Thu, 22 Aug 2024 12:34:40 +0200 Subject: [PATCH] fix(multiple): stop exposing internal ripple implementation Removes the code that exposes the ripple implementations of some components since they are internal details and they require some hacky workarounds to keep exposed. BREAKING CHANGES: * `MatButton.ripple` is no longer available. * `MatCheckbox.ripple` is no longer available. * `MatChip.ripple` is no longer available. --- src/material/button/button-base.ts | 18 +--- src/material/button/button.spec.ts | 93 +-------------------- src/material/checkbox/checkbox.spec.ts | 4 - src/material/checkbox/checkbox.ts | 7 -- src/material/chips/chip.spec.ts | 38 --------- src/material/chips/chip.ts | 15 +--- src/material/core/private/ripple-loader.ts | 6 -- tools/public_api_guard/material/button.md | 1 - tools/public_api_guard/material/checkbox.md | 3 - tools/public_api_guard/material/chips.md | 6 -- tools/public_api_guard/material/core.md | 1 - 11 files changed, 6 insertions(+), 186 deletions(-) diff --git a/src/material/button/button-base.ts b/src/material/button/button-base.ts index c198de65c612..da5f247c84f6 100644 --- a/src/material/button/button-base.ts +++ b/src/material/button/button-base.ts @@ -21,7 +21,7 @@ import { OnDestroy, OnInit, } from '@angular/core'; -import {MatRipple, MatRippleLoader, ThemePalette} from '@angular/material/core'; +import {MatRippleLoader, ThemePalette} from '@angular/material/core'; /** Object that can be used to configure the default options for the button component. */ export interface MatButtonConfig { @@ -93,22 +93,10 @@ export class MatButtonBase implements AfterViewInit, OnDestroy { * Handles the lazy creation of the MatButton ripple. * Used to improve initial load time of large applications. */ - _rippleLoader: MatRippleLoader = inject(MatRippleLoader); + protected _rippleLoader: MatRippleLoader = inject(MatRippleLoader); /** Whether this button is a FAB. Used to apply the correct class on the ripple. */ - _isFab = false; - - /** - * Reference to the MatRipple instance of the button. - * @deprecated Considered an implementation detail. To be removed. - * @breaking-change 17.0.0 - */ - get ripple(): MatRipple { - return this._rippleLoader?.getRipple(this._elementRef.nativeElement)!; - } - set ripple(v: MatRipple) { - this._rippleLoader?.attachRipple(this._elementRef.nativeElement, v); - } + protected _isFab = false; /** * Theme color of the button. This API is supported in M2 themes only, it has diff --git a/src/material/button/button.spec.ts b/src/material/button/button.spec.ts index a08c854be7d1..ebd3164e323f 100644 --- a/src/material/button/button.spec.ts +++ b/src/material/button/button.spec.ts @@ -1,12 +1,11 @@ import {createMouseEvent, dispatchEvent} from '@angular/cdk/testing/private'; -import {ApplicationRef, Component, DebugElement} from '@angular/core'; +import {ApplicationRef, Component} from '@angular/core'; import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; -import {MatRipple, ThemePalette} from '@angular/material/core'; +import {ThemePalette} from '@angular/material/core'; import {By} from '@angular/platform-browser'; import { MAT_BUTTON_CONFIG, MAT_FAB_DEFAULT_OPTIONS, - MatButton, MatButtonModule, MatFabDefaultOptions, } from './index'; @@ -62,14 +61,6 @@ describe('MatButton', () => { expect(anchor.classList).toContain('mat-mdc-button-disabled'); }); - it('should expose the ripple instance', () => { - const fixture = TestBed.createComponent(TestApp); - fixture.detectChanges(); - - const button = fixture.debugElement.query(By.directive(MatButton))!.componentInstance; - expect(button.ripple).toBeTruthy(); - }); - it('should not clear previous defined classes', () => { let fixture = TestBed.createComponent(TestApp); let testComponent = fixture.debugElement.componentInstance; @@ -287,86 +278,6 @@ describe('MatButton', () => { }); }); - // Ripple tests. - describe('button ripples', () => { - let fixture: ComponentFixture; - let testComponent: TestApp; - let buttonDebugElement: DebugElement; - let buttonRippleInstance: MatRipple; - let anchorDebugElement: DebugElement; - let anchorRippleInstance: MatRipple; - - beforeEach(() => { - fixture = TestBed.createComponent(TestApp); - fixture.detectChanges(); - - testComponent = fixture.componentInstance; - - buttonDebugElement = fixture.debugElement.query(By.css('button[mat-button]'))!; - buttonRippleInstance = buttonDebugElement.componentInstance.ripple; - - anchorDebugElement = fixture.debugElement.query(By.css('a[mat-button]'))!; - anchorRippleInstance = anchorDebugElement.componentInstance.ripple; - }); - - it('should disable the ripple if matRippleDisabled input is set', () => { - expect(buttonRippleInstance.disabled).toBeFalsy(); - - testComponent.rippleDisabled = true; - fixture.changeDetectorRef.markForCheck(); - fixture.detectChanges(); - - expect(buttonRippleInstance.disabled).toBeTruthy(); - }); - - it('should disable the ripple when the button is disabled', () => { - expect(buttonRippleInstance.disabled).toBeFalsy( - 'Expected an enabled button[mat-button] to have an enabled ripple', - ); - expect(anchorRippleInstance.disabled).toBeFalsy( - 'Expected an enabled a[mat-button] to have an enabled ripple', - ); - - testComponent.isDisabled = true; - fixture.changeDetectorRef.markForCheck(); - fixture.detectChanges(); - - expect(buttonRippleInstance.disabled).toBeTruthy( - 'Expected a disabled button[mat-button] not to have an enabled ripple', - ); - expect(anchorRippleInstance.disabled).toBeTruthy( - 'Expected a disabled a[mat-button] not to have an enabled ripple', - ); - }); - - it('should render the ripple once it is referenced', () => { - const fab = fixture.debugElement.query(By.css('button[mat-fab]'))!; - let ripple = fab.nativeElement.querySelector('.mat-mdc-button-ripple'); - expect(ripple).withContext('Expect ripple to be absent before user interaction').toBeNull(); - - // Referencing the ripple should instantiate the ripple. - expect(fab.componentInstance.ripple).toBeDefined(); - - ripple = fab.nativeElement.querySelector('.mat-mdc-button-ripple'); - expect(ripple) - .withContext('Expect ripple to be present after user interaction') - .not.toBeNull(); - }); - - // Ensure each of these events triggers the initialization of the button ripple. - for (const event of ['mousedown', 'touchstart', 'mouseenter', 'focus']) { - it(`should render the ripple once a button has received a "${event}" event`, () => { - const fab = fixture.debugElement.query(By.css('button[mat-fab]'))!; - let ripple = fab.nativeElement.querySelector('.mat-mdc-button-ripple'); - expect(ripple).toBeNull(); - - dispatchEvent(fab.nativeElement, createMouseEvent(event)); - ripple = fab.nativeElement.querySelector('.mat-mdc-button-ripple'); - expect(ripple).not.toBeNull(); - }); - } - }); - it('should have a focus indicator', () => { const fixture = TestBed.createComponent(TestApp); const buttonNativeElements = [ diff --git a/src/material/checkbox/checkbox.spec.ts b/src/material/checkbox/checkbox.spec.ts index a95e820c07bf..7b013197d690 100644 --- a/src/material/checkbox/checkbox.spec.ts +++ b/src/material/checkbox/checkbox.spec.ts @@ -67,10 +67,6 @@ describe('MatCheckbox', () => { expect(inputElement.checked).toBe(false); })); - it('should expose the ripple instance', () => { - expect(checkboxInstance.ripple).toBeTruthy(); - }); - it('should hide the internal SVG', () => { const svg = checkboxNativeElement.querySelector('svg')!; expect(svg.getAttribute('aria-hidden')).toBe('true'); diff --git a/src/material/checkbox/checkbox.ts b/src/material/checkbox/checkbox.ts index aee9aaac1016..19a09c881c29 100644 --- a/src/material/checkbox/checkbox.ts +++ b/src/material/checkbox/checkbox.ts @@ -216,13 +216,6 @@ export class MatCheckbox @Input({transform: booleanAttribute}) disabledInteractive: boolean; - /** - * Reference to the MatRipple instance of the checkbox. - * @deprecated Considered an implementation detail. To be removed. - * @breaking-change 17.0.0 - */ - @ViewChild(MatRipple) ripple: MatRipple; - /** * Called when the checkbox is blurred. Needed to properly implement ControlValueAccessor. * @docs-private diff --git a/src/material/chips/chip.spec.ts b/src/material/chips/chip.spec.ts index 2f916981ae51..cd022b7ec7a3 100644 --- a/src/material/chips/chip.spec.ts +++ b/src/material/chips/chip.spec.ts @@ -65,16 +65,6 @@ describe('MatChip', () => { expect(chip.getAttribute('tabindex')).toBe('15'); }); - - it('should have its ripple disabled', () => { - fixture = TestBed.createComponent(BasicChip); - fixture.detectChanges(); - chipDebugElement = fixture.debugElement.query(By.directive(MatChip))!; - chipInstance = chipDebugElement.injector.get(MatChip); - expect(chipInstance.ripple.disabled) - .withContext('Expected basic chip ripples to be disabled.') - .toBe(true); - }); }); describe('MatChip', () => { @@ -131,34 +121,6 @@ describe('MatChip', () => { expect(testComponent.chipRemove).toHaveBeenCalledWith({chip: chipInstance}); }); - it('should be able to disable ripples with the `[rippleDisabled]` input', () => { - expect(chipInstance.ripple.disabled) - .withContext('Expected chip ripples to be enabled.') - .toBe(false); - - testComponent.rippleDisabled = true; - fixture.changeDetectorRef.markForCheck(); - fixture.detectChanges(); - - expect(chipInstance.ripple.disabled) - .withContext('Expected chip ripples to be disabled.') - .toBe(true); - }); - - it('should disable ripples when the chip is disabled', () => { - expect(chipInstance.ripple.disabled) - .withContext('Expected chip ripples to be enabled.') - .toBe(false); - - testComponent.disabled = true; - fixture.changeDetectorRef.markForCheck(); - fixture.detectChanges(); - - expect(chipInstance.ripple.disabled) - .withContext('Expected chip ripples to be disabled.') - .toBe(true); - }); - it('should make disabled chips non-focusable', () => { testComponent.disabled = true; fixture.changeDetectorRef.markForCheck(); diff --git a/src/material/chips/chip.ts b/src/material/chips/chip.ts index d489f9766168..630d22aa1c5a 100644 --- a/src/material/chips/chip.ts +++ b/src/material/chips/chip.ts @@ -38,7 +38,6 @@ import { } from '@angular/core'; import { MAT_RIPPLE_GLOBAL_OPTIONS, - MatRipple, MatRippleLoader, RippleGlobalOptions, } from '@angular/material/core'; @@ -216,18 +215,6 @@ export class MatChip implements OnInit, AfterViewInit, AfterContentInit, DoCheck /** The chip's trailing remove icon. */ @ContentChild(MAT_CHIP_REMOVE) removeIcon: MatChipRemove; - /** - * Reference to the MatRipple instance of the chip. - * @deprecated Considered an implementation detail. To be removed. - * @breaking-change 17.0.0 - */ - 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; @@ -235,7 +222,7 @@ export class MatChip implements OnInit, AfterViewInit, AfterContentInit, DoCheck * Handles the lazy creation of the MatChip ripple. * Used to improve initial load time of large applications. */ - _rippleLoader: MatRippleLoader = inject(MatRippleLoader); + private _rippleLoader: MatRippleLoader = inject(MatRippleLoader); protected _injector = inject(Injector); diff --git a/src/material/core/private/ripple-loader.ts b/src/material/core/private/ripple-loader.ts index 6c2501a27620..da92c7ff1cfa 100644 --- a/src/material/core/private/ripple-loader.ts +++ b/src/material/core/private/ripple-loader.ts @@ -109,12 +109,6 @@ export class MatRippleLoader implements OnDestroy { } } - /** Returns the ripple instance for the given host element. */ - getRipple(host: HTMLElement): MatRipple | undefined { - const ripple = this._hosts.get(host); - return ripple || this._createRipple(host); - } - /** Sets the disabled state on the ripple instance corresponding to the given host element. */ setDisabled(host: HTMLElement, disabled: boolean): void { const ripple = this._hosts.get(host); diff --git a/tools/public_api_guard/material/button.md b/tools/public_api_guard/material/button.md index 5e08b7fb90a0..34449374d5a9 100644 --- a/tools/public_api_guard/material/button.md +++ b/tools/public_api_guard/material/button.md @@ -10,7 +10,6 @@ import { FocusOrigin } from '@angular/cdk/a11y'; import * as i0 from '@angular/core'; import * as i1 from '@angular/material/core'; import { InjectionToken } from '@angular/core'; -import { MatRipple } from '@angular/material/core'; import { MatRippleLoader } from '@angular/material/core'; import { NgZone } from '@angular/core'; import { OnDestroy } from '@angular/core'; diff --git a/tools/public_api_guard/material/checkbox.md b/tools/public_api_guard/material/checkbox.md index 51621165fdb0..bc59c890df69 100644 --- a/tools/public_api_guard/material/checkbox.md +++ b/tools/public_api_guard/material/checkbox.md @@ -15,7 +15,6 @@ import { FocusableOption } from '@angular/cdk/a11y'; import * as i0 from '@angular/core'; import * as i3 from '@angular/material/core'; import { InjectionToken } from '@angular/core'; -import { MatRipple } from '@angular/material/core'; import { NgZone } from '@angular/core'; import { OnChanges } from '@angular/core'; import { Provider } from '@angular/core'; @@ -114,8 +113,6 @@ export class MatCheckbox implements AfterViewInit, OnChanges, ControlValueAccess // (undocumented) registerOnValidatorChange(fn: () => void): void; required: boolean; - // @deprecated - ripple: MatRipple; // (undocumented) setDisabledState(isDisabled: boolean): void; tabIndex: number; diff --git a/tools/public_api_guard/material/chips.md b/tools/public_api_guard/material/chips.md index 7a387fa1dcfa..82e20ca5d178 100644 --- a/tools/public_api_guard/material/chips.md +++ b/tools/public_api_guard/material/chips.md @@ -22,8 +22,6 @@ import { InjectionToken } from '@angular/core'; import { Injector } 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'; @@ -116,10 +114,6 @@ export class MatChip implements OnInit, AfterViewInit, AfterContentInit, DoCheck remove(): void; readonly removed: EventEmitter; removeIcon: MatChipRemove; - // @deprecated - get ripple(): MatRipple; - set ripple(v: MatRipple); - _rippleLoader: MatRippleLoader; role: string | null; trailingIcon: MatChipTrailingIcon; get value(): any; diff --git a/tools/public_api_guard/material/core.md b/tools/public_api_guard/material/core.md index 21b46b72c8ed..99e82c00e495 100644 --- a/tools/public_api_guard/material/core.md +++ b/tools/public_api_guard/material/core.md @@ -411,7 +411,6 @@ export class MatRippleLoader implements OnDestroy { }): void; // (undocumented) destroyRipple(host: HTMLElement): void; - getRipple(host: HTMLElement): MatRipple | undefined; // (undocumented) ngOnDestroy(): void; setDisabled(host: HTMLElement, disabled: boolean): void;