From ffc1de4f737efc86a85e8797ac7dde7141febfd3 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Thu, 13 Jan 2022 21:51:31 +0100 Subject: [PATCH] fix(material-experimental/mdc-snack-bar): avoid hard reference to base components and align API (#21425) The MDC snack bar was set up to extend the base `MatSnackBar` directly which has a reference to the base snack bar components. This means that the code and styles from the base components will be pulled in, even though it isn't being used. These changes move the snack bar logic into a base class that is extended by the default and MDC implementations. While working on these changes, I also noticed that the simple snack bar components was called `SimpleSnackBar` in the default implementation and `MatSimpleSnackBar` for MDC. I've aligned the naming in order to make it easier to migrate. --- .../mdc-snack-bar/mdc-snack-bar-demo.ts | 4 +- .../mdc-snack-bar/module.ts | 4 +- .../mdc-snack-bar/public-api.ts | 1 - .../mdc-snack-bar/simple-snack-bar.ts | 11 ++---- .../mdc-snack-bar/snack-bar.spec.ts | 6 +-- .../mdc-snack-bar/snack-bar.ts | 28 +++++++++++--- .../testing/snack-bar-harness.spec.ts | 2 +- src/material/snack-bar/snack-bar.ts | 36 +++++++++++++----- tools/public_api_guard/material/snack-bar.md | 37 +++++++++++++------ 9 files changed, 87 insertions(+), 42 deletions(-) diff --git a/src/dev-app/mdc-snack-bar/mdc-snack-bar-demo.ts b/src/dev-app/mdc-snack-bar/mdc-snack-bar-demo.ts index 51d5bc2654c7..26cc2e9ba194 100644 --- a/src/dev-app/mdc-snack-bar/mdc-snack-bar-demo.ts +++ b/src/dev-app/mdc-snack-bar/mdc-snack-bar-demo.ts @@ -8,12 +8,12 @@ import {Directionality} from '@angular/cdk/bidi'; import {Component, TemplateRef, ViewChild, ViewEncapsulation} from '@angular/core'; -import {MatSnackBar} from '@angular/material-experimental/mdc-snack-bar'; import { + MatSnackBar, MatSnackBarConfig, MatSnackBarHorizontalPosition, MatSnackBarVerticalPosition, -} from '@angular/material/snack-bar'; +} from '@angular/material-experimental/mdc-snack-bar'; @Component({ selector: 'mdc-snack-bar-demo', diff --git a/src/material-experimental/mdc-snack-bar/module.ts b/src/material-experimental/mdc-snack-bar/module.ts index 8c655c815b3d..d23f44380300 100644 --- a/src/material-experimental/mdc-snack-bar/module.ts +++ b/src/material-experimental/mdc-snack-bar/module.ts @@ -13,7 +13,7 @@ import {NgModule} from '@angular/core'; import {MatButtonModule} from '@angular/material-experimental/mdc-button'; import {MatCommonModule} from '@angular/material-experimental/mdc-core'; -import {MatSimpleSnackBar} from './simple-snack-bar'; +import {SimpleSnackBar} from './simple-snack-bar'; import {MatSnackBarContainer} from './snack-bar-container'; import {MatSnackBarAction, MatSnackBarActions, MatSnackBarLabel} from './snack-bar-content'; @@ -27,7 +27,7 @@ import {MatSnackBarAction, MatSnackBarActions, MatSnackBarLabel} from './snack-b MatSnackBarAction, ], declarations: [ - MatSimpleSnackBar, + SimpleSnackBar, MatSnackBarContainer, MatSnackBarLabel, MatSnackBarActions, diff --git a/src/material-experimental/mdc-snack-bar/public-api.ts b/src/material-experimental/mdc-snack-bar/public-api.ts index 923632a13d18..6f0656d33079 100644 --- a/src/material-experimental/mdc-snack-bar/public-api.ts +++ b/src/material-experimental/mdc-snack-bar/public-api.ts @@ -16,7 +16,6 @@ export { MatSnackBarConfig, MatSnackBarDismiss, MatSnackBarRef, - SimpleSnackBar, MAT_SNACK_BAR_DATA, MAT_SNACK_BAR_DEFAULT_OPTIONS, MAT_SNACK_BAR_DEFAULT_OPTIONS_FACTORY, diff --git a/src/material-experimental/mdc-snack-bar/simple-snack-bar.ts b/src/material-experimental/mdc-snack-bar/simple-snack-bar.ts index 0c5ff0ed55c4..38235d685090 100644 --- a/src/material-experimental/mdc-snack-bar/simple-snack-bar.ts +++ b/src/material-experimental/mdc-snack-bar/simple-snack-bar.ts @@ -7,15 +7,10 @@ */ import {ChangeDetectionStrategy, Component, Inject, ViewEncapsulation} from '@angular/core'; -import { - MAT_SNACK_BAR_DATA, - TextOnlySnackBar, - MatSnackBarRef, - SimpleSnackBar, -} from '@angular/material/snack-bar'; +import {MAT_SNACK_BAR_DATA, TextOnlySnackBar, MatSnackBarRef} from '@angular/material/snack-bar'; @Component({ - selector: 'mat-simple-snack-bar', + selector: 'simple-snack-bar', templateUrl: 'simple-snack-bar.html', styleUrls: ['simple-snack-bar.css'], exportAs: 'matSnackBar', @@ -25,7 +20,7 @@ import { 'class': 'mat-mdc-simple-snack-bar', }, }) -export class MatSimpleSnackBar implements TextOnlySnackBar { +export class SimpleSnackBar implements TextOnlySnackBar { constructor( public snackBarRef: MatSnackBarRef, @Inject(MAT_SNACK_BAR_DATA) public data: {message: string; action: string}, diff --git a/src/material-experimental/mdc-snack-bar/snack-bar.spec.ts b/src/material-experimental/mdc-snack-bar/snack-bar.spec.ts index b8fedddde6c7..d682b03804a8 100644 --- a/src/material-experimental/mdc-snack-bar/snack-bar.spec.ts +++ b/src/material-experimental/mdc-snack-bar/snack-bar.spec.ts @@ -14,7 +14,7 @@ import {NoopAnimationsModule} from '@angular/platform-browser/animations'; import { MAT_SNACK_BAR_DATA, MAT_SNACK_BAR_DEFAULT_OPTIONS, - MatSimpleSnackBar, + SimpleSnackBar, MatSnackBar, MatSnackBarConfig, MatSnackBarContainer, @@ -239,7 +239,7 @@ describe('MatSnackBar', () => { viewContainerFixture.detectChanges(); - expect(snackBarRef.instance instanceof MatSimpleSnackBar) + expect(snackBarRef.instance instanceof SimpleSnackBar) .withContext('Expected the snack bar content component to be SimpleSnackBar') .toBe(true); expect(snackBarRef.instance.snackBarRef) @@ -266,7 +266,7 @@ describe('MatSnackBar', () => { viewContainerFixture.detectChanges(); - expect(snackBarRef.instance instanceof MatSimpleSnackBar) + expect(snackBarRef.instance instanceof SimpleSnackBar) .withContext('Expected the snack bar content component to be SimpleSnackBar') .toBe(true); expect(snackBarRef.instance.snackBarRef) diff --git a/src/material-experimental/mdc-snack-bar/snack-bar.ts b/src/material-experimental/mdc-snack-bar/snack-bar.ts index 0dc7d550d101..4ac117696244 100644 --- a/src/material-experimental/mdc-snack-bar/snack-bar.ts +++ b/src/material-experimental/mdc-snack-bar/snack-bar.ts @@ -6,18 +6,36 @@ * found in the LICENSE file at https://angular.io/license */ -import {Injectable} from '@angular/core'; -import {MatSnackBar as BaseMatSnackBar} from '@angular/material/snack-bar'; +import {LiveAnnouncer} from '@angular/cdk/a11y'; +import {BreakpointObserver} from '@angular/cdk/layout'; +import {Overlay} from '@angular/cdk/overlay'; +import {Inject, Injectable, Injector, Optional, SkipSelf} from '@angular/core'; +import { + MatSnackBarConfig, + MAT_SNACK_BAR_DEFAULT_OPTIONS, + _MatSnackBarBase, +} from '@angular/material/snack-bar'; import {MatSnackBarModule} from './module'; -import {MatSimpleSnackBar} from './simple-snack-bar'; +import {SimpleSnackBar} from './simple-snack-bar'; import {MatSnackBarContainer} from './snack-bar-container'; /** * Service to dispatch Material Design snack bar messages. */ @Injectable({providedIn: MatSnackBarModule}) -export class MatSnackBar extends BaseMatSnackBar { - protected override simpleSnackBarComponent = MatSimpleSnackBar; +export class MatSnackBar extends _MatSnackBarBase { + protected override simpleSnackBarComponent = SimpleSnackBar; protected override snackBarContainerComponent = MatSnackBarContainer; protected override handsetCssClass = 'mat-mdc-snack-bar-handset'; + + constructor( + overlay: Overlay, + live: LiveAnnouncer, + injector: Injector, + breakpointObserver: BreakpointObserver, + @Optional() @SkipSelf() parentSnackBar: MatSnackBar, + @Inject(MAT_SNACK_BAR_DEFAULT_OPTIONS) defaultConfig: MatSnackBarConfig, + ) { + super(overlay, live, injector, breakpointObserver, parentSnackBar, defaultConfig); + } } diff --git a/src/material-experimental/mdc-snack-bar/testing/snack-bar-harness.spec.ts b/src/material-experimental/mdc-snack-bar/testing/snack-bar-harness.spec.ts index c301c9ad05bf..06d5e8ca8ede 100644 --- a/src/material-experimental/mdc-snack-bar/testing/snack-bar-harness.spec.ts +++ b/src/material-experimental/mdc-snack-bar/testing/snack-bar-harness.spec.ts @@ -12,7 +12,7 @@ import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed'; import {Component, TemplateRef, ViewChild} from '@angular/core'; describe('MDC-based MatSnackBarHarness', () => { - runHarnessTests(MatSnackBarModule, MatSnackBar, MatSnackBarHarness as any); + runHarnessTests(MatSnackBarModule, MatSnackBar as any, MatSnackBarHarness as any); }); describe('MDC-based MatSnackBarHarness (MDC only behavior)', () => { diff --git a/src/material/snack-bar/snack-bar.ts b/src/material/snack-bar/snack-bar.ts index 0ba152441b13..b9ac058fa914 100644 --- a/src/material/snack-bar/snack-bar.ts +++ b/src/material/snack-bar/snack-bar.ts @@ -44,11 +44,8 @@ export function MAT_SNACK_BAR_DEFAULT_OPTIONS_FACTORY(): MatSnackBarConfig { return new MatSnackBarConfig(); } -/** - * Service to dispatch Material Design snack bar messages. - */ -@Injectable({providedIn: MatSnackBarModule}) -export class MatSnackBar implements OnDestroy { +@Injectable() +export abstract class _MatSnackBarBase implements OnDestroy { /** * Reference to the current snack bar in the view *at this level* (in the Angular injector tree). * If there is a parent snack-bar service, all operations should delegate to that parent @@ -57,13 +54,13 @@ export class MatSnackBar implements OnDestroy { private _snackBarRefAtThisLevel: MatSnackBarRef | null = null; /** The component that should be rendered as the snack bar's simple component. */ - protected simpleSnackBarComponent: Type = SimpleSnackBar; + protected abstract simpleSnackBarComponent: Type; /** The container component that attaches the provided template or component. */ - protected snackBarContainerComponent: Type<_SnackBarContainer> = MatSnackBarContainer; + protected abstract snackBarContainerComponent: Type<_SnackBarContainer>; /** The CSS class to apply for handset mode. */ - protected handsetCssClass = 'mat-snack-bar-handset'; + protected abstract handsetCssClass: string; /** Reference to the currently opened snackbar at *any* level. */ get _openedSnackBarRef(): MatSnackBarRef | null { @@ -84,7 +81,7 @@ export class MatSnackBar implements OnDestroy { private _live: LiveAnnouncer, private _injector: Injector, private _breakpointObserver: BreakpointObserver, - @Optional() @SkipSelf() private _parentSnackBar: MatSnackBar, + @Optional() @SkipSelf() private _parentSnackBar: _MatSnackBarBase, @Inject(MAT_SNACK_BAR_DEFAULT_OPTIONS) private _defaultConfig: MatSnackBarConfig, ) {} @@ -311,3 +308,24 @@ export class MatSnackBar implements OnDestroy { }); } } + +/** + * Service to dispatch Material Design snack bar messages. + */ +@Injectable({providedIn: MatSnackBarModule}) +export class MatSnackBar extends _MatSnackBarBase { + protected simpleSnackBarComponent = SimpleSnackBar; + protected snackBarContainerComponent = MatSnackBarContainer; + protected handsetCssClass = 'mat-snack-bar-handset'; + + constructor( + overlay: Overlay, + live: LiveAnnouncer, + injector: Injector, + breakpointObserver: BreakpointObserver, + @Optional() @SkipSelf() parentSnackBar: MatSnackBar, + @Inject(MAT_SNACK_BAR_DEFAULT_OPTIONS) defaultConfig: MatSnackBarConfig, + ) { + super(overlay, live, injector, breakpointObserver, parentSnackBar, defaultConfig); + } +} diff --git a/tools/public_api_guard/material/snack-bar.md b/tools/public_api_guard/material/snack-bar.md index 529298b2a100..ac5c120be17e 100644 --- a/tools/public_api_guard/material/snack-bar.md +++ b/tools/public_api_guard/material/snack-bar.md @@ -49,19 +49,14 @@ export const MAT_SNACK_BAR_DEFAULT_OPTIONS: InjectionToken; - get _openedSnackBarRef(): MatSnackBarRef | null; - set _openedSnackBarRef(value: MatSnackBarRef | null); - openFromComponent(component: ComponentType, config?: MatSnackBarConfig): MatSnackBarRef; - openFromTemplate(template: TemplateRef, config?: MatSnackBarConfig): MatSnackBarRef>; - protected simpleSnackBarComponent: Type; - protected snackBarContainerComponent: Type<_SnackBarContainer>; + protected simpleSnackBarComponent: typeof SimpleSnackBar; + // (undocumented) + protected snackBarContainerComponent: typeof MatSnackBarContainer; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; // (undocumented) @@ -73,6 +68,26 @@ export const matSnackBarAnimations: { readonly snackBarState: AnimationTriggerMetadata; }; +// @public (undocumented) +export abstract class _MatSnackBarBase implements OnDestroy { + constructor(_overlay: Overlay, _live: LiveAnnouncer, _injector: Injector, _breakpointObserver: BreakpointObserver, _parentSnackBar: _MatSnackBarBase, _defaultConfig: MatSnackBarConfig); + dismiss(): void; + protected abstract handsetCssClass: string; + // (undocumented) + ngOnDestroy(): void; + open(message: string, action?: string, config?: MatSnackBarConfig): MatSnackBarRef; + get _openedSnackBarRef(): MatSnackBarRef | null; + set _openedSnackBarRef(value: MatSnackBarRef | null); + openFromComponent(component: ComponentType, config?: MatSnackBarConfig): MatSnackBarRef; + openFromTemplate(template: TemplateRef, config?: MatSnackBarConfig): MatSnackBarRef>; + protected abstract simpleSnackBarComponent: Type; + protected abstract snackBarContainerComponent: Type<_SnackBarContainer>; + // (undocumented) + static ɵfac: i0.ɵɵFactoryDeclaration<_MatSnackBarBase, [null, null, null, null, { optional: true; skipSelf: true; }, null]>; + // (undocumented) + static ɵprov: i0.ɵɵInjectableDeclaration<_MatSnackBarBase>; +} + // @public export class MatSnackBarConfig { announcementMessage?: string;