Skip to content

feat(snackbar): Add input for custom position strategy#10126 - 12.1.x #10152

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 17, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export abstract class IgxNotificationsDirective extends IgxToggleDirective
* @hidden
* @internal
*/
public textMessage: string | OverlaySettings = '';
public textMessage = '';

/**
* @hidden
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { By } from '@angular/platform-browser';
import { BrowserAnimationsModule, NoopAnimationsModule } from '@angular/platform-browser/animations';
import { IgxSnackbarComponent, IgxSnackbarModule } from './snackbar.component';
import { configureTestSuite } from '../test-utils/configure-suite';
import { HorizontalAlignment, PositionSettings, slideInLeft, slideInRight, VerticalAlignment } from 'igniteui-angular';
import { useAnimation } from '@angular/animations';

describe('IgxSnackbar', () => {
configureTestSuite();
Expand Down Expand Up @@ -160,6 +162,31 @@ describe('IgxSnackbar', () => {
expect(snackbar.textMessage).toBe('Custom Message');
snackbar.close();
}));

it('should be able to set custom positionSettings', () => {
const defaultPositionSettings = snackbar.positionSettings;
const defaulOpenAnimationParams = {duration: '.35s', easing: 'cubic-bezier(0.0, 0.0, 0.2, 1)',
fromPosition: 'translateY(100%)', toPosition: 'translateY(0)'};
expect(defaultPositionSettings.horizontalDirection).toBe(-0.5);
expect(defaultPositionSettings.verticalDirection).toBe(0);
expect(defaultPositionSettings.openAnimation.options.params).toEqual(defaulOpenAnimationParams);
const newPositionSettings: PositionSettings = {
openAnimation: useAnimation(slideInLeft, { params: { duration: '1000ms' } }),
closeAnimation: useAnimation(slideInRight, { params: { duration: '1000ms' } }),
horizontalDirection: HorizontalAlignment.Center,
verticalDirection: VerticalAlignment.Middle,
horizontalStartPoint: HorizontalAlignment.Center,
verticalStartPoint: VerticalAlignment.Middle,
minSize: { height: 100, width: 100 }
};
snackbar.positionSettings = newPositionSettings;
fixture.detectChanges();
const customPositionSettings = snackbar.positionSettings;
expect(customPositionSettings.horizontalDirection).toBe(-0.5);
expect(customPositionSettings.verticalDirection).toBe(-0.5);
expect(customPositionSettings.openAnimation.options.params).toEqual({duration: '1000ms'});
expect(customPositionSettings.minSize).toEqual({height: 100, width: 100});
});
});

describe('IgxSnackbar with custom content', () => {
Expand Down
94 changes: 67 additions & 27 deletions projects/igniteui-angular/src/lib/snackbar/snackbar.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import {
Output
} from '@angular/core';
import { takeUntil } from 'rxjs/operators';
import { slideInBottom, slideOutBottom } from '../animations/main';
import { fadeIn, fadeOut } from '../animations/main';
import { ContainerPositionStrategy, GlobalPositionStrategy, HorizontalAlignment,
OverlaySettings, PositionSettings, VerticalAlignment } from '../services/public_api';
PositionSettings, VerticalAlignment } from '../services/public_api';
import { IgxNotificationsDirective } from '../directives/notification/notifications.directive';
import { ToggleViewEventArgs } from '../directives/toggle/toggle.directive';

Expand Down Expand Up @@ -101,44 +101,84 @@ export class IgxSnackbarComponent extends IgxNotificationsDirective
*/
@Output() public animationDone = new EventEmitter<ToggleViewEventArgs>();

/**
* Get the position and animation settings used by the snackbar.
* ```typescript
* @ViewChild('snackbar', { static: true }) public snackbar: IgxSnackbarComponent;
* let currentPosition: PositionSettings = this.snackbar.positionSettings
* ```
*/
@Input()
public get positionSettings(): PositionSettings {
return this._positionSettings;
}

/**
* Set the position and animation settings used by the snackbar.
* ```html
* <igx-snackbar [positionSettings]="newPositionSettings"></igx-snackbar>
* ```
* ```typescript
* import { slideInTop, slideOutBottom } from 'igniteui-angular';
* ...
* @ViewChild('snackbar', { static: true }) public snackbar: IgxSnackbarComponent;
* public newPositionSettings: PositionSettings = {
* openAnimation: useAnimation(slideInTop, { params: { duration: '1000ms', fromPosition: 'translateY(100%)'}}),
* closeAnimation: useAnimation(slideOutBottom, { params: { duration: '1000ms', fromPosition: 'translateY(0)'}}),
* horizontalDirection: HorizontalAlignment.Left,
* verticalDirection: VerticalAlignment.Middle,
* horizontalStartPoint: HorizontalAlignment.Left,
* verticalStartPoint: VerticalAlignment.Middle,
* minSize: { height: 100, width: 100 }
* };
* this.snackbar.positionSettings = this.newPositionSettings;
* ```
*/
public set positionSettings(settings: PositionSettings) {
this._positionSettings = settings;
}

private _positionSettings: PositionSettings = {
horizontalDirection: HorizontalAlignment.Center,
verticalDirection: VerticalAlignment.Bottom,
openAnimation: useAnimation(fadeIn, { params: { duration: '.35s', easing: 'cubic-bezier(0.0, 0.0, 0.2, 1)',
fromPosition: 'translateY(100%)', toPosition: 'translateY(0)'} }),
closeAnimation: useAnimation(fadeOut, { params: { duration: '.2s', easing: 'cubic-bezier(0.4, 0.0, 1, 1)',
fromPosition: 'translateY(0)', toPosition: 'translateY(100%)'} }),
};

/**
* Shows the snackbar and hides it after the `displayTime` is over if `autoHide` is set to `true`.
* ```typescript
* this.snackbar.open();
* ```
*/
public open(message?: string | OverlaySettings) {
public open(message?: string) {
if (message !== undefined) {
this.textMessage = message;
}

const snackbarSettings: PositionSettings = {
horizontalDirection: HorizontalAlignment.Center,
verticalDirection: VerticalAlignment.Bottom,
openAnimation: useAnimation(slideInBottom, {
params: {
duration: '.35s',
easing: 'cubic-bezier(0.0, 0.0, 0.2, 1)',
fromPosition: 'translateY(100%)',
toPosition: 'translateY(0)'
}
}),
closeAnimation: useAnimation(slideOutBottom, {
params: {
duration: '.2s',
easing: 'cubic-bezier(0.4, 0.0, 1, 1)',
fromPosition: 'translateY(0)',
toOpacity: 1,
toPosition: 'translateY(100%)'
}
})
};

this.strategy = this.outlet ? new ContainerPositionStrategy(snackbarSettings)
: new GlobalPositionStrategy(snackbarSettings);

this.strategy = this.outlet ? new ContainerPositionStrategy(this.positionSettings)
: new GlobalPositionStrategy(this.positionSettings);
super.open();
}

/**
* Opens or closes the snackbar, depending on its current state.
*
* ```typescript
* this.snackbar.toggle();
* ```
*/
public toggle() {
if (this.collapsed || this.isClosing) {
this.open();
} else {
this.close();
}
}

/**
* @hidden
*/
Expand Down
24 changes: 24 additions & 0 deletions projects/igniteui-angular/src/lib/toast/toast.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
IgxToastModule,
} from './toast.component';
import { configureTestSuite } from '../test-utils/configure-suite';
import { HorizontalAlignment, PositionSettings, slideInLeft, slideInRight, VerticalAlignment } from 'igniteui-angular';
import { useAnimation } from '@angular/animations';

describe('IgxToast', () => {
configureTestSuite();
Expand Down Expand Up @@ -43,6 +45,28 @@ describe('IgxToast', () => {
expect(toast.id).toBe('customToast');
expect(domToast.id).toBe('customToast');
});

it('should be able to set custom positionSettings', () => {
const defaultPositionSettings = toast.positionSettings;
expect(defaultPositionSettings.horizontalDirection).toBe(-0.5);
expect(defaultPositionSettings.verticalDirection).toBe(0);
const newPositionSettings: PositionSettings = {
openAnimation: useAnimation(slideInLeft, { params: { duration: '1000ms' } }),
closeAnimation: useAnimation(slideInRight, { params: { duration: '1000ms' } }),
horizontalDirection: HorizontalAlignment.Center,
verticalDirection: VerticalAlignment.Middle,
horizontalStartPoint: HorizontalAlignment.Center,
verticalStartPoint: VerticalAlignment.Middle,
minSize: { height: 100, width: 100 }
};
toast.positionSettings = newPositionSettings;
fixture.detectChanges();
const customPositionSettings = toast.positionSettings;
expect(customPositionSettings.horizontalDirection).toBe(-0.5);
expect(customPositionSettings.verticalDirection).toBe(-0.5);
expect(customPositionSettings.openAnimation.options.params).toEqual({duration: '1000ms'});
expect(customPositionSettings.minSize).toEqual({height: 100, width: 100});
});
});

@Component({
Expand Down
80 changes: 67 additions & 13 deletions projects/igniteui-angular/src/lib/toast/toast.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ import {
HorizontalAlignment,
VerticalAlignment,
GlobalPositionStrategy,
OverlaySettings,
PositionSettings
} from '../services/public_api';
import { mkenum } from '../core/utils';
import { IgxNotificationsDirective } from '../directives/notification/notifications.directive';
import { ToggleViewEventArgs } from '../directives/toggle/toggle.directive';
import { useAnimation } from '@angular/animations';
import { fadeIn, fadeOut } from '../animations/fade';

let NEXT_ID = 0;

Expand Down Expand Up @@ -121,6 +122,54 @@ export class IgxToastComponent extends IgxNotificationsDirective
@Input()
public position: IgxToastPosition = 'bottom';

/**
* Get the position and animation settings used by the toast.
* ```typescript
* @ViewChild('toast', { static: true }) public toast: IgxToastComponent;
* let currentPosition: PositionSettings = this.toast.positionSettings
* ```
*/
@Input()
public get positionSettings(): PositionSettings {
return this._positionSettings;
}

/**
* Set the position and animation settings used by the toast.
* ```html
* <igx-toast [positionSettings]="newPositionSettings"></igx-toast>
* ```
* ```typescript
* import { slideInTop, slideOutBottom } from 'igniteui-angular';
* ...
* @ViewChild('toast', { static: true }) public toast: IgxToastComponent;
* public newPositionSettings: PositionSettings = {
* openAnimation: useAnimation(slideInTop, { params: { duration: '1000ms', fromPosition: 'translateY(100%)'}}),
* closeAnimation: useAnimation(slideOutBottom, { params: { duration: '1000ms', fromPosition: 'translateY(0)'}}),
* horizontalDirection: HorizontalAlignment.Left,
* verticalDirection: VerticalAlignment.Middle,
* horizontalStartPoint: HorizontalAlignment.Left,
* verticalStartPoint: VerticalAlignment.Middle
* };
* this.toast.positionSettings = this.newPositionSettings;
* ```
*/
public set positionSettings(settings: PositionSettings) {
this._positionSettings = settings;
}

private _positionSettings: PositionSettings = {
horizontalDirection: HorizontalAlignment.Center,
verticalDirection:
this.position === 'bottom'
? VerticalAlignment.Bottom
: this.position === 'middle'
? VerticalAlignment.Middle
: VerticalAlignment.Top,
openAnimation: useAnimation(fadeIn),
closeAnimation: useAnimation(fadeOut),
};

/**
* Gets the nativeElement of the toast.
* ```typescript
Expand Down Expand Up @@ -150,25 +199,30 @@ export class IgxToastComponent extends IgxNotificationsDirective
* this.toast.open();
* ```
*/
public open(message?: string | OverlaySettings) {
public open(message?: string) {
if (message !== undefined) {
this.textMessage = message;
}

const toastSettings: PositionSettings = {
horizontalDirection: HorizontalAlignment.Center,
verticalDirection:
this.position === 'bottom'
? VerticalAlignment.Bottom
: this.position === 'middle'
? VerticalAlignment.Middle
: VerticalAlignment.Top
};

this.strategy = new GlobalPositionStrategy(toastSettings);
this.strategy = new GlobalPositionStrategy(this.positionSettings);
super.open();
}

/**
* Opens or closes the toast, depending on its current state.
*
* ```typescript
* this.toast.toggle();
* ```
*/
public toggle() {
if (this.collapsed || this.isClosing) {
this.open();
} else {
this.close();
}
}

/**
* @hidden
*/
Expand Down
13 changes: 13 additions & 0 deletions src/app/snackbar/snackbar.sample.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,16 @@ <h4 class="sample-title">Snackbar w/ action button</h4>
</article>
</section>
</div>

<div class="sample-wrapper">
<section class="sample-content">
<article class="sample-column">
<h4 class="sample-title">Snackbar with positionSettings</h4>
<button igxButton="raised" (click)="snackbar1.open()">Send message</button>
<div>
<igx-snackbar #snackbar1 [autoHide]="false" [positionSettings]="newPositionSettings" actionText="Close" (clicked)="close(snackbar1)">Message sent
</igx-snackbar>
</div>
</article>
</section>
</div>
17 changes: 16 additions & 1 deletion src/app/snackbar/snackbar.sample.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { useAnimation } from '@angular/animations';
import { Component, OnInit, ViewChild } from '@angular/core';
import { IgxSnackbarComponent } from 'igniteui-angular';
// eslint-disable-next-line max-len
import { HorizontalAlignment, IgxSnackbarComponent, PositionSettings, slideInLeft, slideInRight, VerticalAlignment } from 'igniteui-angular';

@Component({
selector: 'app-snackbar-sample',
Expand All @@ -12,6 +14,15 @@ export class SnackbarSampleComponent implements OnInit {

public color: string;
public actionName: string;
public newPositionSettings: PositionSettings = {
openAnimation: useAnimation(slideInLeft, { params: { duration: '1000ms' } }),
closeAnimation: useAnimation(slideInRight, { params: { duration: '1000ms' } }),
horizontalDirection: HorizontalAlignment.Center,
verticalDirection: VerticalAlignment.Middle,
horizontalStartPoint: HorizontalAlignment.Center,
verticalStartPoint: VerticalAlignment.Middle,
minSize: { height: 100, width: 100 }
};
private _colors: string[];

public ngOnInit() {
Expand Down Expand Up @@ -51,4 +62,8 @@ export class SnackbarSampleComponent implements OnInit {
public toggleSnackbar() {
this.snackbar.toggle();
}

public close(element) {
element.close();
}
}