Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/lib/snack-bar/_snack-bar-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
$accent: map-get($theme, accent);

.mat-snack-bar-container {
// Use the primary text on the dark theme, even though the lighter one uses
// a secondary, because the contrast on the light primary text is poor.
color: if($is-dark-theme, $dark-primary-text, $light-secondary-text);
background: if($is-dark-theme, map-get($mat-grey, 50), #323232);
color: if($is-dark-theme, $dark-primary-text, $light-primary-text);
}

.mat-simple-snackbar-action {
Expand Down
7 changes: 5 additions & 2 deletions src/lib/snack-bar/simple-snack-bar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ $mat-snack-bar-button-vertical-margin:
.mat-simple-snackbar {
display: flex;
justify-content: space-between;
align-items: center;
height: 100%;
line-height: $mat-snack-bar-line-height;
opacity: 1;
}
Expand All @@ -22,16 +24,17 @@ $mat-snack-bar-button-vertical-margin:
flex-direction: column;
flex-shrink: 0;
justify-content: space-around;
margin: $mat-snack-bar-button-vertical-margin 0
margin: $mat-snack-bar-button-vertical-margin $mat-snack-bar-button-horizontal-margin * -1
$mat-snack-bar-button-vertical-margin $mat-snack-bar-button-horizontal-margin;

button {
flex: 1;
max-height: $mat-snack-bar-button-height;
min-width: 0;
}

[dir='rtl'] & {
margin-left: 0;
margin-left: -$mat-snack-bar-button-horizontal-margin;
margin-right: $mat-snack-bar-button-horizontal-margin;
}
}
5 changes: 1 addition & 4 deletions src/lib/snack-bar/simple-snack-bar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import {Component, ViewEncapsulation, Inject, ChangeDetectionStrategy} from '@angular/core';
import {MatSnackBarRef} from './snack-bar-ref';
import {MAT_SNACK_BAR_DATA} from './snack-bar-config';
import {matSnackBarAnimations} from './snack-bar-animations';


/**
Expand All @@ -23,15 +22,13 @@ import {matSnackBarAnimations} from './snack-bar-animations';
styleUrls: ['simple-snack-bar.css'],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
animations: [matSnackBarAnimations.contentFade],
host: {
'[@contentFade]': '',
'class': 'mat-simple-snackbar',
}
})
export class SimpleSnackBar {
/** Data that was injected into the snack bar. */
data: { message: string, action: string };
data: {message: string, action: string};

constructor(
public snackBarRef: MatSnackBarRef<SimpleSnackBar>,
Expand Down
27 changes: 12 additions & 15 deletions src/lib/snack-bar/snack-bar-animations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,24 @@ import {
trigger,
AnimationTriggerMetadata,
} from '@angular/animations';
import {AnimationCurves, AnimationDurations} from '@angular/material/core';

/** Animations used by the Material snack bar. */
export const matSnackBarAnimations: {
readonly contentFade: AnimationTriggerMetadata;
readonly snackBarState: AnimationTriggerMetadata;
} = {
/** Animation that slides the dialog in and out of view and fades the opacity. */
contentFade: trigger('contentFade', [
transition(':enter', [
style({opacity: '0'}),
animate(`${AnimationDurations.COMPLEX} ${AnimationCurves.STANDARD_CURVE}`)
])
]),

/** Animation that shows and hides a snack bar. */
snackBarState: trigger('state', [
state('visible-top, visible-bottom', style({transform: 'translateY(0%)'})),
transition('visible-top => hidden-top, visible-bottom => hidden-bottom',
animate(`${AnimationDurations.EXITING} ${AnimationCurves.ACCELERATION_CURVE}`)),
transition('void => visible-top, void => visible-bottom',
animate(`${AnimationDurations.ENTERING} ${AnimationCurves.DECELERATION_CURVE}`)),
state('void, hidden', style({
transform: 'scale(0.8)',
opacity: 0,
})),
state('visible', style({
transform: 'scale(1)',
opacity: 1,
})),
transition('* => visible', animate('150ms cubic-bezier(0, 0, 0.2, 1)')),
transition('* => void, * => hidden', animate('75ms cubic-bezier(0.4, 0.0, 1, 1)', style({
opacity: 0
}))),
])
};
43 changes: 12 additions & 31 deletions src/lib/snack-bar/snack-bar-container.scss
Original file line number Diff line number Diff line change
@@ -1,44 +1,25 @@
@import '../../cdk/a11y/a11y';
@import '../core/style/elevation';

$mat-snack-bar-padding: 14px 24px !default;
$mat-snack-bar-min-width: 288px !default;
$mat-snack-bar-max-width: 568px !default;
$mat-snack-bar-padding: 14px 16px !default;
$mat-snack-bar-min-height: 48px !default;
$mat-snack-bar-min-width: 344px !default;
$mat-snack-bar-max-width: 33vw !default;
$mat-snack-bar-spacing-margin: 24px !default;
$mat-snack-bar-spacing-margin-handset: 8px !default;


.mat-snack-bar-container {
border-radius: 2px;
@include mat-elevation(6);
border-radius: 4px;
box-sizing: border-box;
display: block;
margin: $mat-snack-bar-spacing-margin;
max-width: $mat-snack-bar-max-width;
min-width: $mat-snack-bar-min-width;
padding: $mat-snack-bar-padding;
// Initial transformation is applied to start snack bar out of view, below its target position.
// Note: it's preferred to use a series of transforms, instead of something like `calc()`, because
// IE won't animate transforms that contain a `calc`.
transform: translateY(100%) translateY($mat-snack-bar-spacing-margin);

/**
* Removes margin of snack bars which are center positioned horizontally. This
* is done to align snack bars to the edge of the view vertically to match spec.
*/
&.mat-snack-bar-center {
margin: 0;
transform: translateY(100%);
}

/**
* To allow for animations from a 'top' vertical position to animate in a downward
* direction, set the translation to start the snack bar above the target position.
*/
&.mat-snack-bar-top {
transform: translateY(-100%) translateY(#{-$mat-snack-bar-spacing-margin});

&.mat-snack-bar-center {
transform: translateY(-100%);
}
}
min-height: $mat-snack-bar-min-height;
transform-origin: center;

@include cdk-high-contrast {
border: solid 1px;
Expand All @@ -53,8 +34,8 @@ $mat-snack-bar-spacing-margin: 24px !default;
width: 100%;

.mat-snack-bar-container {
margin: 0;
max-width: inherit;
margin: $mat-snack-bar-spacing-margin-handset;
max-width: 100%;
width: 100%;
}
}
11 changes: 7 additions & 4 deletions src/lib/snack-bar/snack-bar-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,11 @@ export class MatSnackBarContainer extends BasePortalOutlet implements OnDestroy
onAnimationEnd(event: AnimationEvent) {
const {fromState, toState} = event;

if ((toState === 'void' && fromState !== 'void') || toState.startsWith('hidden')) {
if ((toState === 'void' && fromState !== 'void') || toState === 'hidden') {
this._completeExit();
}

if (toState.startsWith('visible')) {
if (toState === 'visible') {
// Note: we shouldn't use `this` inside the zone callback,
// because it can cause a memory leak.
const onEnter = this._onEnter;
Expand All @@ -113,14 +113,17 @@ export class MatSnackBarContainer extends BasePortalOutlet implements OnDestroy
/** Begin animation of snack bar entrance into view. */
enter(): void {
if (!this._destroyed) {
this._animationState = `visible-${this.snackBarConfig.verticalPosition}`;
this._animationState = 'visible';
this._changeDetectorRef.detectChanges();
}
}

/** Begin animation of the snack bar exiting from view. */
exit(): Observable<void> {
this._animationState = `hidden-${this.snackBarConfig.verticalPosition}`;
// Note: this one transitions to `hidden`, rather than `void`, in order to handle the case
// where multiple snack bars are opened in quick succession (e.g. two consecutive calls to
// `MatSnackBar.open`).
this._animationState = 'hidden';
return this._onExit;
}

Expand Down
39 changes: 7 additions & 32 deletions src/lib/snack-bar/snack-bar.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,12 +214,12 @@ describe('MatSnackBar', () => {

viewContainerFixture.detectChanges();
expect(snackBarRef.containerInstance._animationState)
.toBe('visible-bottom', `Expected the animation state would be 'visible-bottom'.`);
.toBe('visible', `Expected the animation state would be 'visible'.`);
snackBarRef.dismiss();

viewContainerFixture.detectChanges();
expect(snackBarRef.containerInstance._animationState)
.toBe('hidden-bottom', `Expected the animation state would be 'hidden-bottom'.`);
.toBe('hidden', `Expected the animation state would be 'hidden'.`);
});

it('should set the animation state to complete on exit', () => {
Expand All @@ -229,7 +229,7 @@ describe('MatSnackBar', () => {

viewContainerFixture.detectChanges();
expect(snackBarRef.containerInstance._animationState)
.toBe('hidden-bottom', `Expected the animation state would be 'hidden-bottom'.`);
.toBe('hidden', `Expected the animation state would be 'hidden'.`);
});

it(`should set the old snack bar animation state to complete and the new snack bar animation
Expand All @@ -240,7 +240,7 @@ describe('MatSnackBar', () => {

viewContainerFixture.detectChanges();
expect(snackBarRef.containerInstance._animationState)
.toBe('visible-bottom', `Expected the animation state would be 'visible-bottom'.`);
.toBe('visible', `Expected the animation state would be 'visible'.`);

let config2 = {viewContainerRef: testViewContainerRef};
let snackBarRef2 = snackBar.open(simpleMessage, undefined, config2);
Expand All @@ -251,9 +251,9 @@ describe('MatSnackBar', () => {

expect(dismissCompleteSpy).toHaveBeenCalled();
expect(snackBarRef.containerInstance._animationState)
.toBe('hidden-bottom', `Expected the animation state would be 'hidden-bottom'.`);
.toBe('hidden', `Expected the animation state would be 'hidden'.`);
expect(snackBarRef2.containerInstance._animationState)
.toBe('visible-bottom', `Expected the animation state would be 'visible-bottom'.`);
.toBe('visible', `Expected the animation state would be 'visible'.`);
}));

it('should open a new snackbar after dismissing a previous snackbar', fakeAsync(() => {
Expand All @@ -273,7 +273,7 @@ describe('MatSnackBar', () => {
// Wait for the snackbar open animation to finish.
flush();
expect(snackBarRef.containerInstance._animationState)
.toBe('visible-bottom', `Expected the animation state would be 'visible-bottom'.`);
.toBe('visible', `Expected the animation state would be 'visible'.`);
}));

it('should remove past snackbars when opening new snackbars', fakeAsync(() => {
Expand Down Expand Up @@ -452,31 +452,6 @@ describe('MatSnackBar', () => {
.toContain('custom-class', 'Expected class applied through the defaults to be applied.');
}));

it('should position the snack bar correctly if no default position is defined', fakeAsync(() => {
overlayContainer.ngOnDestroy();
viewContainerFixture.destroy();

TestBed
.resetTestingModule()
.overrideProvider(MAT_SNACK_BAR_DEFAULT_OPTIONS, {
deps: [],
useFactory: () => ({politeness: 'polite'})
})
.configureTestingModule({imports: [MatSnackBarModule, NoopAnimationsModule]})
.compileComponents();

inject([MatSnackBar, OverlayContainer], (sb: MatSnackBar, oc: OverlayContainer) => {
snackBar = sb;
overlayContainer = oc;
overlayContainerElement = oc.getContainerElement();
})();

const snackBarRef = snackBar.open(simpleMessage);
flush();

expect(snackBarRef.containerInstance._animationState).toBe('visible-bottom');
}));

describe('with custom component', () => {
it('should open a custom component', () => {
const snackBarRef = snackBar.openFromComponent(BurritosNotification);
Expand Down